1、简单介绍

什么是对称加密算法?

对称加密算法即,加密和解密使用相同密钥的算法。

优缺点:

优点:算法公开、计算量小、加密速度快、加密效率高。

缺点:

(1)交易双方都使用同样钥匙,安全性得不到保证。

(2)每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。

摘录来源:http://www.cnblogs.com/Free-Thinker/p/5825582.html

常用的算法

  • DES(Data Encryption Standard,数据加密算法)
  • 3DES(Triple Data Encryption Algorithm,三重数据加密算法)
  • AES(Advanced Encryption Standard,高级加密标准,又称Rijndael加密法)
  • PBE(Password-based encryption,基于密码验证)

本文会介绍通过JDK来实现上述相关算法,会在源码中加入其它第三方包的开发源码,建议先看:java加密算法入门(一)-算法概念及单向加密  理解相关概念。另外,本文不会讲述太多算法原理,注重在应用。

2、DES(Data Encryption Standard,数据加密算法)

DES是最基本的对称加密算法,也是使用频率最高的一种算法,加密密钥与解密密钥相同。DES出身比较好,出自IBM之手,后被美国军方采纳,之后便广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法。DES使用56位长度的密钥,有些提供商可能附加8位奇偶校验位。

2.1 算法流程:

发送者构建秘钥-->发送秘钥--> 接收者

发送者明文-->DES算法+秘钥加密--> 密文--> 接收者

接收者--> DES算法+秘钥解密--> 明文

2.2 具体实现

1.初始化密钥
使用KeyGenerator类的getInstance()静态方法,获取生成指定算法的密钥生成器,参数是算法名称.
使用KeyGenerator类的init()方法进行密钥生成器的初始化,指定密钥生成器产生密钥的长度.
使用KeyGenerator类的generatorKey()方法生成一个密钥对象,返回SecretKey密钥对象.
SecretKey为密钥对象.使用它的getEncoded()方法返回一个密钥(字节数组形式)

public static byte[] initSecretKey(){
//返回生成指定算法密钥的KeyGenerator对象
KeyGenerator kg = KeyGenerator.getInstance("DES");
//初始化此密钥生成器,使其具有确定的密钥大小
kg.init(56);
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return secretKey.getEncoded();
}

2.转化密钥(还原密钥),将jdk生成的密钥对象转化成DES规则的密钥对象.
创建一个DESKeySpec实例,作用是将JDK初始化的密钥转化成DES规则的密钥,构造方法参数是JDK生成的密钥(字节数组形式).
使用SecretKeyFactory类的getInstance()静态方法获取一个密钥工厂实例,参数是算法名称
使用SecretKeyFactory类的generateSecret()方法生成密钥,参数是DESKeySpec实例.返回SecretKey,返回的SecretKey实例就是符合DES算法的密钥.

private static Key toKey(byte[] key){
//实例化DES密钥规则
DESKeySpec dks = new DESKeySpec(key);
//实例化密钥工厂
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
//生成密钥
SecretKey secretKey = skf.generateSecret(dks);
return secretKey;
}

3.加密
创建Cipher对象,该类提供加密和解密功能,使用Cipher类的getInstance()静态方法,参数是“算法/模式/填充”或“算法”,后一种参数使用默认值,后续类似,默认不在说明。
初始化Cipher对象,init(int opmode, Key key),参数:opmode为以下之一:ENCRYPT_MODE、DECRYPT_MODE、WRAP_MODE 或 UNWRAP_MODE,key - 密钥
加密操作,返回加密后的字节数组,然后需要编码。主要编解码方式有Base64, HEX, UUE, 7bit等等。
编码,ps:此为测试用

Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("jdk des encrypt:" + Hex.encodeHexString(result));

4.解密
将服务器返回的加密字符串,先用Base64、HEX等解码成byte[]
再用加密时相同的加密方式及key进行解密。加密与解密代码几乎相同。唯一区别为在Cipher类init时,工作模式为Cipher.DECRYPT_MODE。

2.3 实现代码

/**

 * {@link http://www.cnblogs.com/allanzhang/}

 * @author 小卖铺的老爷爷

 *

 */
public class DESTest
{
    public static final String src = "laoyeye des";
    public static void main(String[] args)
    {
        jdkDES();
        bcDES();

    }

    // 用jdk实现:

    public static void jdkDES()
    {
        try
        {
            // 生成KEY

            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56);
            // 产生密钥

            SecretKey secretKey = keyGenerator.generateKey();
            // 获取密钥

            byte[] bytesKey = secretKey.getEncoded();

            // KEY转换

            DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
            Key convertSecretKey = factory.generateSecret(desKeySpec);

            // 加密

            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");//

            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("jdk des encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("jdk des decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 用bouncy castle实现:

    public static void bcDES()
    {
        try
        {
            Security.addProvider(new BouncyCastleProvider());

            // 生成KEY

            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES", "BC");
            keyGenerator.getProvider();
            keyGenerator.init(56);
            // 产生密钥

            SecretKey secretKey = keyGenerator.generateKey();
            // 获取密钥

            byte[] bytesKey = secretKey.getEncoded();

            // KEY转换

            DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
            Key convertSecretKey = factory.generateSecret(desKeySpec);

            // 加密

            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc des encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("bc des decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

3、3DES(Triple Data Encryption Algorithm,三重数据加密算法)

3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。 来源:百度百科

DES被很多密码学机构质疑,因为算法是半公开的,因此违反柯克霍夫原则,所以在这个基础上,延伸了3重DES.

3.1 算法流程:

发送者构建秘钥-->发送秘钥--> 接收者

发送者明文-->3DES算法+秘钥加密--> 密文--> 接收者

接收者--> 3DES算法+秘钥解密--> 明文

3DES与实现DES方式基本一致,算法名称要改为DESede,密钥长度为168,转换密钥时使用DESedeKeySpec类。

3.2 实现代码

/**

 * {@link http://www.cnblogs.com/allanzhang/}

 * @author 小卖铺的老爷爷

 *

 */
public class DES3Test
{
    public static final String src = "laoyeye 3des";
    public static void main(String[] args)
    {
        jdk3DES();
        bc3DES();

    }

    // 用jdk实现:

    public static void jdk3DES()
    {
        try
        {
            // 生成KEY

            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            // 必须长度是:112或168

//            keyGenerator.init(168);

            keyGenerator.init(new SecureRandom());//new SecureRandom()会根据算法,设置默认的长度

            // 产生密钥

            SecretKey secretKey = keyGenerator.generateKey();
            // 获取密钥

            byte[] bytesKey = secretKey.getEncoded();

            // KEY转换

            DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            Key convertSecretKey = factory.generateSecret(desKeySpec);

            // 加密

            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("jdk 3des encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("jdk 3des decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 用bouncy castle实现:

    public static void bc3DES()
    {
        try
        {
            Security.addProvider(new BouncyCastleProvider());

            // 生成KEY

            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede", "BC");
            keyGenerator.getProvider();
            keyGenerator.init(168);
            // 产生密钥

            SecretKey secretKey = keyGenerator.generateKey();
            // 获取密钥

            byte[] bytesKey = secretKey.getEncoded();

            // KEY转换

            DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            Key convertSecretKey = factory.generateSecret(desKeySpec);

            // 加密

            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc 3des encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
            result = cipher.doFinal(result);
            System.out.println("bc 3des decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

3重DES与DES的区别:
1.密钥长度增长(168)
2.迭代次数提高
3.重DES在实际应用中是应用最多的。

4、AES(Advanced Encryption Standard,高级加密标准,又称Rijndael加密法)

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。 来源:百度百科

AES是目前使用最多的对称加密算法之一,AES至今尚未听说有被破解的案例。
AES通常用于移动通信系统加密以及基于SSH协议的软件,如SSH Client,secureCRT
AES是用来替代DES的,因为DES有很多被破解,而3DES效率又比较慢

AES加密算法的默认密钥长度为128,还可以选择192、256.
注意:JDK实现AES算法,使用256位密钥长度时要获得无政策限制权限文件,BC不会存在该问题。无政策限制权限是指某些国家的进口管制限制,java发布的运行环境包中中的加解密有一定限制。

4.1 算法流程:

发送者构建秘钥-->发送秘钥--> 接收者

发送者明文-->AES算法+秘钥加密--> 密文--> 接收者

接收者--> AES算法+秘钥解密--> 明文

4.2 实现步骤

1.根据算法创建key生成器
2.指定密钥长度
3.生成密钥对象
4.获取密钥
5.转换密钥,有两种方式

1.使用SecretKeySpec,构造参数为密钥、算法名,直接返回SecretKey.该方式适用于MAC、AES
2.使用XXXKeySpec,构造参数密钥,再使用SecretKeyFactory的getInstance(),参数是算法名,然后再使用generateSecret()方法,参数是XXXKeySpec.该方式适用于DES

6.创建密码对象Cipher,参数是算法/工作模式/填充方式.
7.初始化密钥,参数是加解密模式、密钥.
8.执行方法,doFinal(byte[] b)

4.3 实现代码

/**

 * {@link http://www.cnblogs.com/allanzhang/}

 * @author 小卖铺的老爷爷

 *

 */
public class AESTest
{
    public static final String src = "laoyeye aes";
    public static void main(String[] args)
    {
        jdkAES();
        bcAES();

    }

    // 用jdk实现:

    public static void jdkAES()
    {
        try
        {
            // 生成KEY

            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);
            // 产生密钥

            SecretKey secretKey = keyGenerator.generateKey();
            // 获取密钥

            byte[] keyBytes = secretKey.getEncoded();

            // KEY转换

            Key key = new SecretKeySpec(keyBytes, "AES");

            // 加密

            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("jdk aes encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, key);
            result = cipher.doFinal(result);
            System.out.println("jdk aes decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 用bouncy castle实现:

    public static void bcAES()
    {
        try
        {
            Security.addProvider(new BouncyCastleProvider());

            // 生成KEY

            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES", "BC");
            keyGenerator.getProvider();
            keyGenerator.init(128);
            // 产生密钥

            SecretKey secretKey = keyGenerator.generateKey();
            // 获取密钥

            byte[] keyBytes = secretKey.getEncoded();

            // KEY转换

            Key key = new SecretKeySpec(keyBytes, "AES");

            // 加密

            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc aes encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, key);
            result = cipher.doFinal(result);
            System.out.println("bc aes decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

5、PBE(Password-based encryption,基于密码验证)

PBE算法(Password Based Encryption,基于口令加密)是一种基于口令的加密算法,其特点是使用口令代替了密钥,而口令由用户自己掌管,采用随机数杂凑多重加密等方法保证数据的安全性。PBE算法在加密过程中并不是直接使用口令来加密,而是加密的密钥由口令生成,这个功能由PBE算法中的KDF函数完成。KDF函数的实现过程为:将用户输入的口令首先通过“盐”(salt)的扰乱产生准密钥,再将准密钥经过散列函数多次迭代后生成最终加密密钥,密钥生成后,PBE算法再选用对称加密算法对数据进行加密,可以选择DES、3DES、RC5等对称加密算法。 来源:百度百科

特点:

结合了消息摘要算法和对称加密算法的优点,本质上是对MD5/SHA以及DES/3DES/AES算法的包装,不是新的算法,不过也是最为牛逼的一种方式。
盐:指加密的随机字符串或者口令等,也可以人为是一些扰码,防止密码的暴力破解

5.1 算法流程:

发送者构建口令-->发送口令--> 接收者

发送者构建盐

发送者明文-->PBE算法+口令+盐加密--> 密文(同时发送盐)--> 接收者

接收者--> PBE算法+口令+盐解密--> 明文

5.2 实现代码

/**

 * {@link http://www.cnblogs.com/allanzhang/}

 * @author 小卖铺的老爷爷

 *

 */
public class PBETest {
    public static final String src = "laoyeye pbe";
    public static void main(String[] args)
    {
        jdkPBE();

    }

    // 用jdk实现:

    public static void jdkPBE()
    {
        try
        {
            // 初始化盐

            SecureRandom random = new SecureRandom();
            byte[] salt = random.generateSeed(8);

            // 口令与密钥

            String password = "laoyeye";
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
            Key key = factory.generateSecret(pbeKeySpec);

            // 加密

            PBEParameterSpec pbeParameterSpac = new PBEParameterSpec(salt, 100);//参数:盐和迭代次数

            Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES");
            cipher.init(Cipher.ENCRYPT_MODE, key, pbeParameterSpac);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("jdk pbe encrypt:" + Hex.encodeHexString(result));

            // 解密

            cipher.init(Cipher.DECRYPT_MODE, key, pbeParameterSpac);
            result = cipher.doFinal(result);
            System.out.println("jdk pbe decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

总结:
1:DES是最基本的算法,出身比较好美国军方通过IBM来实现的
2:3DES由于DES有漏洞不安全,所以,产生了3DES,应用更加的广泛,不过效率不高,所以才有了后来的AES
3:AES是应用更加广泛的一种对称加密算法,安全性更高
4:PBE本质是其他对称加密算法一种综合,加入了盐(随机字符串)防止密码的暴力破解

注意:实际的加密解密不是在一起的,通常是将秘钥发送给解密的那一方来实现的,或者实现约定好了的

源码:

https://git.oschina.net/allanzhang/checkcode.git

java加密算法入门(二)-对称加密详解的更多相关文章

  1. 对称加密详解,以及JAVA简单实现

    (原) 常用的加密有3种 1.正向加密,如MD5,加密后密文固定,目前还没办法破解,但是可以能过数据库撞库有一定概率找到,不过现在一般用这种方式加密都会加上盐值. 2.对称加密,通过一个固定的对称密钥 ...

  2. Java网络编程二:Socket详解

    Socket又称套接字,是连接运行在网络上两个程序间的双向通讯的端点. 一.使用Socket进行网络通信的过程 服务端:服务器程序将一个套接字绑定到一个特定的端口,并通过此套接字等待和监听客户端的连接 ...

  3. Java一维数组二维数组详解API

    所谓数组,是有序的元素序列. 若将有限个类型相同的变量的集合命名,那么这个名称为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量.用于区分数组的各个元素的数字编号称为下标 ...

  4. java加密算法入门(三)-非对称加密详解

    1.简单介绍 这几天一直在看非对称的加密,相比之前的两篇内容,这次看了两倍多的时间还云里雾里的,所以这篇文章相对之前的两篇,概念性的东西多了些,另外是代码的每一步我都做了介绍,方便自己以后翻阅,也方便 ...

  5. 爬虫入门之urllib库详解(二)

    爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...

  6. Java进阶(三十二) HttpClient使用详解

    Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...

  7. 二叉搜索树详解(Java实现)

    1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...

  8. HTTPD之二————HTTPD服务详解————httpd的配置文件常见设置

    HTTPD之二----HTTPD服务详解----httpd的配置文件常见设置 HTTP服务器应用 http服务器程序 httpd apache nginx lighttpd 应用程序服务器 IIS,a ...

  9. java的集合框架最全详解

    java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...

随机推荐

  1. 使用Perl提取Excel中的IO_MUX

    使用Perl提取Excel中的IO_MUX 关键问题 提取数据 格式化输出 循环嵌套 数据结构构建 坐标映射,逆向提取关键字 描述 在IC集成中,我们使用Excel表格规划设计的IC引脚功能映射需要转 ...

  2. C#中 dynamic 关键字

       所有表达式都能隐式的转换成dynamic,因为所有的表达式最终都能生成从Object派生出的类型. ; int b = a; //隐式转换错误 int b2 = (int)a; ; int b3 ...

  3. uoj#73 【WC2015】未来程序

    在 2047 年,第 64 届全国青少年信息学奥林匹克冬令营前夕,B君找到了 2015 年,第 32 届冬令营的题目来练习. 他打开了第三题 “未来程序” 这道题目: 本题是一道提交答案题,一共 10 ...

  4. [内存管理]管理图解v0.1 v0.2 v0.3

    内存管理图解v0.1 内存管理图解v0.2 内存管理图解v0.3 

  5. IO调度器原理介绍

    IO调度器(IO Scheduler)是操作系统用来决定块设备上IO操作提交顺序的方法.存在的目的有两个,一是提高IO吞吐量,二是降低IO响应时间.然而IO吞吐量和IO响应时间往往是矛盾的,为了尽量平 ...

  6. codeforces 803B Distances to Zero

    Distances to Zero 题目链接:http://codeforces.com/problemset/problem/803/B 题目大意: 给一串数字,求每个数字到离他最近数字0的距离.. ...

  7. jenkins 设置自动发送邮件

      1.测试邮件发送 进入jenkins系统管理-->系统设置做如下配置   1.设置系统管理员邮件地址,这是一个全局变量,意味着所有的jenkins执行的任务,最后都会通过这个邮件地址发送邮件 ...

  8. 将sublimeText添加到鼠标右键菜单栏

    将sublimeText添加到鼠标右键菜单栏主要是写一个注册表的文件,将这个注进去,首先你需要清楚你的sublimeText软件的安装路径,然后改一下下面这段代码就可以了 Windows Regist ...

  9. 通过ssh远程ipython notebook登录使用服务器

    远程服务器有时候我们这里通过虚拟机登录服务器的winclient会发生冲突,怎么办呢?曲线救国,使用SSH登录. 首先在远程机器上,启动IPython notebooks服务: remote_user ...

  10. MyBatis之级联——鉴别器

    鉴别器(discriminator)是MyBatis为我们提供的第三个级联也是最后一个.基于之前两篇级联中的场景,现增加学生们去体检,但男女体检项目不一样,我们把男女体检表做成两张表,当然我想也可以设 ...