第四章 对称加密算法--DES--AES--IDEA--PBE

10.1、DES

  • 已破解,不再安全,基本没有企业在用了
  • 是对称加密算法的基石,具有学习价值
  • 密钥长度56(JDK)、56/64(BC)

10.2、DESede(三重DES)

  • 早于AES出现来替代DES
  • 计算密钥时间太长、加密效率不高,所以也基本上不用
  • 密钥长度112/168(JDK)、128/192(BC)

10.3、AES

  • 最常用的对称加密算法
  • 密钥建立时间短、灵敏性好、内存需求低(不管怎样,反正就是好)
  • 实际使用中,使用工作模式为CTR(最好用BC去实现),此工作模式需要引入IV参数(16位的字节数组)
  • 密钥长度128/192/256,其中192与256需要配置无政策限制权限文件(JDK6)
  • 填充模式最常用的两种PKCS5Padding和PKCS7Padding,其中后者只有BC独有。

10.4、IDEA

  • 常用的电子邮件加密算法
  • 工作模式只有ECB
  • 密钥长度128位

10.5、PBE

  • 综合了消息摘要算法和对称加密算法,最常见的是PBEWithMD5AndDES
  • 工作模式只有CBC(已丧失安全性,不推荐使用),所以PBE也不推荐使用了

7.1、对称加密算法

特点:

  • 加密与解密使用同一个密钥
  • 是使用最广的算法

常见对称加密算法:

  • DES(已被破解,但是是其他对称算法的基石)
  • DESede(处理速度慢、加密耗时,也不常用)
  • AES(DES的替代者,最常用)
  • IDEA(目前常用的电子邮件加密算法)
  • PBE(对已知对称加密进行包装)

7.2、DES(已破解,基本不用)

实现方式:

  • JDK(提供56位密钥,提供PKCS5Padding的填充模式)
  • Bouncy Castle(提供64位密钥,提供PKCS7Padding的填充模式)

由于DES已被破解,现在企业基本已不再使用,此处只列出基于JDK实现的代码。

1 package com.util.des;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.security.InvalidKeyException;
  5 import java.security.Key;
  6 import java.security.NoSuchAlgorithmException;
  7 import java.security.spec.InvalidKeySpecException;
  8 
  9 import javax.crypto.BadPaddingException;
 10 import javax.crypto.Cipher;
 11 import javax.crypto.IllegalBlockSizeException;
 12 import javax.crypto.KeyGenerator;
 13 import javax.crypto.NoSuchPaddingException;
 14 import javax.crypto.SecretKey;
 15 import javax.crypto.SecretKeyFactory;
 16 import javax.crypto.spec.DESKeySpec;
 17 
 18 import org.apache.commons.codec.binary.Base64;
 19 
 20 /**
 21  * 基于JDK的DES算法
 22  */
 23 public class DESJDK {
 24     private static final String ENCODING = "UTF-8";
 25     private static final String KEY_ALGORITHM = "DES";//产生密钥的算法
 26     private static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";//加解密算法 格式:算法/工作模式/填充模式
 27     
 28     /**
 29      * 产生密钥
 30      */
 31     public static byte[] getKey() throws NoSuchAlgorithmException{
 32         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
 33         keyGenerator.init(56);//初始化密钥长度
 34         SecretKey key =keyGenerator.generateKey();//产生密钥
 35         return key.getEncoded();
 36     }
 37     
 38     /**
 39      * 还原密钥:二进制字节数组转换为十六进制字符串
 40      */
 41     public static Key toKey(byte[] keyByte) throws InvalidKeyException, 
 42                                                    NoSuchAlgorithmException, 
 43                                                    InvalidKeySpecException{
 44         DESKeySpec desKeySpec = new DESKeySpec(keyByte);
 45         return SecretKeyFactory.getInstance(KEY_ALGORITHM).generateSecret(desKeySpec);
 46     }
 47     
 48     /**
 49      * DES加密
 50      * @param data     带加密数据
 51      * @param keyByte  密钥
 52      */
 53     public static byte[] encrypt(String data, byte[] keyByte) throws InvalidKeyException, 
 54                                                                      NoSuchAlgorithmException, 
 55                                                                      InvalidKeySpecException, 
 56                                                                      NoSuchPaddingException, 
 57                                                                      IllegalBlockSizeException, 
 58                                                                      BadPaddingException, 
 59                                                                      UnsupportedEncodingException{
 60         Key key = toKey(keyByte);//还原密钥
 61         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 62         cipher.init(Cipher.ENCRYPT_MODE, key);//设置加密模式并且初始化key
 63         return cipher.doFinal(data.getBytes(ENCODING));
 64     }
 65     
 66     /**
 67      * DES加密,并转为16进制字符串或Base64编码字符串
 68      */
 69     public static String encryptDESHex(String data, byte[] keyByte) throws InvalidKeyException, 
 70                                                                            NoSuchAlgorithmException, 
 71                                                                            InvalidKeySpecException, 
 72                                                                            NoSuchPaddingException, 
 73                                                                            IllegalBlockSizeException, 
 74                                                                            BadPaddingException, 
 75                                                                            UnsupportedEncodingException {
 76         byte[] encodedByte = encrypt(data, keyByte);
 77         //return new String(Hex.encode(encodedByte));//借助BC
 78         //return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
 79         return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
 80     }
 81     
 82     /**
 83      * DES解密
 84      * @param data        待解密数据为字节数组
 85      * @param keyByte    密钥
 86      */
 87     public static byte[] decrypt(byte[] data, byte[] keyByte) throws InvalidKeyException, 
 88                                                                      NoSuchAlgorithmException, 
 89                                                                      InvalidKeySpecException, 
 90                                                                      NoSuchPaddingException, 
 91                                                                      IllegalBlockSizeException, 
 92                                                                      BadPaddingException, 
 93                                                                      UnsupportedEncodingException {
 94         Key key = toKey(keyByte);//还原密钥
 95         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 96         cipher.init(Cipher.DECRYPT_MODE, key);//设置解密模式(这是加解密的唯一不同的地方)并且初始化key
 97         return cipher.doFinal(data);
 98     }
 99     
100     /**
101      * DES解密
102      * @param data        待解密数据为字符串
103      * @param keyByte    密钥
104      */
105     public static byte[] decrypt(String data, byte[] keyByte) throws InvalidKeyException, 
106                                                                      NoSuchAlgorithmException, 
107                                                                      InvalidKeySpecException, 
108                                                                      NoSuchPaddingException, 
109                                                                      IllegalBlockSizeException, 
110                                                                      BadPaddingException, 
111                                                                      UnsupportedEncodingException {
112         Key key = toKey(keyByte);//还原密钥
113         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
114         cipher.init(Cipher.DECRYPT_MODE, key);//设置解密模式(这是加解密的唯一不同的地方)并且初始化key
115         return cipher.doFinal(Base64.decodeBase64(data));//注意data不可以直接采用data.getByte()方法转化为字节数组,否则会抛异常
116     }
117     
118     /**
119      * 测试
120      */
121     public static void main(String[] args) throws NoSuchAlgorithmException, 
122                                                   InvalidKeyException, 
123                                                   InvalidKeySpecException, 
124                                                   NoSuchPaddingException, 
125                                                   IllegalBlockSizeException, 
126                                                   BadPaddingException, 
127                                                   UnsupportedEncodingException {
128         String data = "找一个好姑娘做老婆是我的梦 想!";
129         /*************测试encode()**************/
130         System.out.println("原文-->"+data);
131         byte[] keyByte = DESJDK.getKey(); 
132         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
133         byte[] encodedByte = DESJDK.encrypt(data, keyByte);
134         System.out.println("加密后-->"+encodedByte);
135         byte[] encodedByte2 = DESJDK.encrypt(data, keyByte);
136         System.out.println("加密后-->"+encodedByte2);
137         byte[] decodedByte = DESJDK.decrypt(encodedByte, keyByte);
138         System.out.println("解密后-->"+decodedByte);
139         for(int i=0;i<encodedByte.length;i++){
140             System.out.println(encodedByte[i]==encodedByte2[i]);
141         }
142         /*************测试encodeHmacMD5Hex()**************/
143         System.out.println("原文-->"+data);
144         byte[] keyByte3 = DESJDK.getKey(); 
145         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
146         String encodedStr = DESJDK.encryptDESHex(data, keyByte3);
147         System.out.println("加密后-->"+encodedStr);
148         String encodedByte4 = DESJDK.encryptDESHex(data, keyByte3);
149         System.out.println("加密后-->"+encodedByte4);
150         byte[] decodedByte3 = DESJDK.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
151         System.out.println("解密Byte[]后-->"+decodedByte3);
152         byte[] decodedByte4 = DESJDK.decrypt(encodedStr, keyByte3);
153         System.out.println("解密String后-->"+decodedByte4);
154     }
155 }

注意点:

  • 整个算法的过程与Hmac系列算法一样,都是发送方先生成一个密钥(二进制的字节数组),然后发送方将密钥通过安全的途径传给接收方。加解密过程:还原密钥(将二进制的字节数组还原成Java对象),然后根据密钥与待加解密数据进行加解密。
  • 加解密算法常量CIPHER_ALGORITHM是一个组合常量,其中的工作模式常用的是ECB和CTR(AES最常用的工作模式)填充模式一般采用PKCS5Padding即可,或者使用BC的PKCS7Padding,具体的工作模式与填充模式的介绍自己去查吧,至于JDK和BC均支持那些工作模式与填充模式直接去查本文最上边的书籍附录即可。
  • 初始化密钥长度的时候指定为56(JDK提供56位的密钥,采用BC可以产生64位的密钥)
  • 还原密钥的时候没有使用通用的方式SecretKey key = new SecretKeySpec(keyByte, ALGORITHM)来还原(当然也可以使用),而是使用了DES自己的还原类,这是DES的推荐做法,但是在AES中推荐使用通用的方式来还原密钥
  • 实际使用中,加密的密文会采用二进制来存储,密钥会采用Base64编码来存储;但是在演示的时候我会提供转化为字符串的密文(转化方法:BC的十六进制转化类 ;CC的十六进制转化类;CC的Base64编码)
  • 在解密过程中,如果传入的待解密数据data是String的,在使用dofinal()方法进行加密时,不可以直接使用doFinal(data.getByte()),否则会抛异常;可以使用doFinal(Base64.decodeBase64(data))
  • 同一段数据使用统一个密钥无论加密多少次,加密后的密文都相同

8.1、AES

特点:

  • 密钥建立时间短、灵敏性好、内存需求低(不管怎样,反正就是好)
  • 最常用的对称加密算法

8.2、实现方式

  • JDK(密钥长度有128,192,256三种选法,提供PKCS5Padding的填充模式)
  • Bouncy Castle(密钥长度有128,192,256三种选法,提供PKCS7Padding的填充模式)

8.2.1、基于JDK或BC的AES实现(工作模式为ECB)

1 package com.util.aes;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.security.InvalidAlgorithmParameterException;
  5 import java.security.InvalidKeyException;
  6 import java.security.Key;
  7 import java.security.NoSuchAlgorithmException;
  8 import java.security.NoSuchProviderException;
  9 import java.security.Security;
 10 import java.security.spec.InvalidKeySpecException;
 11 
 12 import javax.crypto.BadPaddingException;
 13 import javax.crypto.Cipher;
 14 import javax.crypto.IllegalBlockSizeException;
 15 import javax.crypto.KeyGenerator;
 16 import javax.crypto.NoSuchPaddingException;
 17 import javax.crypto.SecretKey;
 18 import javax.crypto.spec.SecretKeySpec;
 19 
 20 import org.apache.commons.codec.binary.Base64;
 21 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 22 
 23 /**
 24  * 基于JDK或BC的AES算法,工作模式采用ECB
 25  */
 26 public class AESJDK {
 27     private static final String ENCODING = "UTF-8";
 28     private static final String KEY_ALGORITHM = "AES";//产生密钥的算法
 29     private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//加解密算法 格式:算法/工作模式/填充模式 注意:ECB不使用IV参数
 30     /**
 31      * 产生密钥
 32      */
 33     public static byte[] getKey() throws NoSuchAlgorithmException{
 34         Security.addProvider(new BouncyCastleProvider());//在BC中用,JDK下去除
 35         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
 36         keyGenerator.init(256);//初始化密钥长度,128,192,256(选用192和256的时候需要配置无政策限制权限文件--JDK6)
 37         SecretKey key =keyGenerator.generateKey();//产生密钥
 38         return key.getEncoded();
 39     }
 40     
 41     /**
 42      * 还原密钥:二进制字节数组转换为Java对象
 43      */
 44     public static Key toKey(byte[] keyByte){
 45         return new SecretKeySpec(keyByte, KEY_ALGORITHM);
 46     }
 47     
 48     /**
 49      * AES加密
 50      * @param data     带加密数据
 51      * @param keyByte  密钥
 52      */
 53     public static byte[] encrypt(String data, byte[] keyByte) throws InvalidKeyException, 
 54                                                                      NoSuchAlgorithmException, 
 55                                                                      InvalidKeySpecException, 
 56                                                                      NoSuchPaddingException, 
 57                                                                      IllegalBlockSizeException, 
 58                                                                      BadPaddingException, 
 59                                                                      UnsupportedEncodingException, 
 60                                                                      NoSuchProviderException, 
 61                                                                      InvalidAlgorithmParameterException{
 62         Key key = toKey(keyByte);//还原密钥
 63         //Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
 64         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
 65         cipher.init(Cipher.ENCRYPT_MODE, key);//设置加密模式并且初始化key
 66         return cipher.doFinal(data.getBytes(ENCODING));
 67     }
 68     
 69     /**
 70      * AES加密,并转为16进制字符串或Base64编码字符串
 71      */
 72     public static String encryptAESHex(String data, byte[] keyByte) throws InvalidKeyException, 
 73                                                                            NoSuchAlgorithmException, 
 74                                                                            InvalidKeySpecException, 
 75                                                                            NoSuchPaddingException, 
 76                                                                            IllegalBlockSizeException, 
 77                                                                            BadPaddingException, 
 78                                                                            UnsupportedEncodingException, 
 79                                                                            NoSuchProviderException, 
 80                                                                            InvalidAlgorithmParameterException {
 81         byte[] encodedByte = encrypt(data, keyByte);
 82         //return new String(Hex.encode(encodedByte));//借助BC
 83         //return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
 84         return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
 85     }
 86     
 87     /**
 88      * AES解密
 89      * @param data        待解密数据为字节数组
 90      * @param keyByte    密钥
 91      */
 92     public static byte[] decrypt(byte[] data, byte[] keyByte) throws InvalidKeyException, 
 93                                                                      NoSuchAlgorithmException, 
 94                                                                      InvalidKeySpecException, 
 95                                                                      NoSuchPaddingException, 
 96                                                                      IllegalBlockSizeException, 
 97                                                                      BadPaddingException, 
 98                                                                      UnsupportedEncodingException, 
 99                                                                      NoSuchProviderException, 
100                                                                      InvalidAlgorithmParameterException {
101         Key key = toKey(keyByte);//还原密钥
102         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
103         //Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
104         cipher.init(Cipher.DECRYPT_MODE, key);
105         return cipher.doFinal(data);
106     }
107     
108     /**
109      * AES解密
110      * @param data        待解密数据为字符串
111      * @param keyByte    密钥
112      */
113     public static byte[] decrypt(String data, byte[] keyByte) throws InvalidKeyException, 
114                                                                      NoSuchAlgorithmException, 
115                                                                      InvalidKeySpecException, 
116                                                                      NoSuchPaddingException, 
117                                                                      IllegalBlockSizeException, 
118                                                                      BadPaddingException, 
119                                                                      UnsupportedEncodingException, 
120                                                                      NoSuchProviderException, 
121                                                                      InvalidAlgorithmParameterException {
122         Key key = toKey(keyByte);//还原密钥
123         //Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);//JDK下用
124         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
125         cipher.init(Cipher.DECRYPT_MODE, key);
126         return cipher.doFinal(Base64.decodeBase64(data));//注意data不可以直接采用data.getByte()方法转化为字节数组,否则会抛异常
127     }
128     
129     /**
130      * 测试
131      */
132     public static void main(String[] args) throws NoSuchAlgorithmException, 
133                                                   InvalidKeyException, 
134                                                   InvalidKeySpecException, 
135                                                   NoSuchPaddingException, 
136                                                   IllegalBlockSizeException, 
137                                                   BadPaddingException, 
138                                                   UnsupportedEncodingException, 
139                                                   NoSuchProviderException, 
140                                                   InvalidAlgorithmParameterException {
141         String data = "找一个好姑娘做老婆是我的梦 想!";
142         /*************测试encrypt()、decrypt()**************/
143         System.out.println("原文-->"+data);
144         byte[] keyByte = AESJDK.getKey(); 
145         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
146         byte[] encodedByte = AESJDK.encrypt(data, keyByte);
147         System.out.println("加密后-->"+encodedByte);
148         byte[] encodedByte2 = AESJDK.encrypt(data, keyByte);
149         System.out.println("加密后-->"+encodedByte2);
150         byte[] decodedByte = AESJDK.decrypt(encodedByte, keyByte);
151         System.out.println("解密后-->"+decodedByte);
152         for(int i=0;i<encodedByte.length;i++){
153             System.out.println(encodedByte[i]==encodedByte2[i]);
154         }
155         /*************测试encryptAESHex()、decrypt()**************/
156         System.out.println("原文-->"+data);
157         byte[] keyByte3 = AESJDK.getKey(); 
158         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
159         String encodedStr = AESJDK.encryptAESHex(data, keyByte3);
160         System.out.println("加密后-->"+encodedStr);
161         String encodedByte4 = AESJDK.encryptAESHex(data, keyByte3);
162         System.out.println("加密后-->"+encodedByte4);
163         byte[] decodedByte3 = AESJDK.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
164         System.out.println("解密Byte[]后-->"+decodedByte3);
165         byte[] decodedByte4 = AESJDK.decrypt(encodedStr, keyByte3);
166         System.out.println("解密String后-->"+decodedByte4);
167     }
168 }

注意点:

  • 本文JDK版本采用的是1.6(也是当下企业常用的版本)
  • 基于JDK或是基于BC去实现查看代码中注释即可
  • 想使用BC下,需要在生成密钥的地方加上Security.addProvider(new BouncyCastleProvider());(这与书中不同,可能JDK7不需要加)
  • 密钥初始化长度可以为128,192,256,其中在选用192和256的时候需要配置无政策限制权限文件,具体方法文末会讲。(这与书中不同,可能JDK7下192不需要配置那个文件)

8.2.2、基于BC的AES实现(工作模式为CTR)(这个类在我后边的使用中有点问题,以后有时间再来解决,如果要用AES算法的话,用上边那种就好)

 1 package com.util.aes;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.security.InvalidAlgorithmParameterException;
  5 import java.security.InvalidKeyException;
  6 import java.security.Key;
  7 import java.security.NoSuchAlgorithmException;
  8 import java.security.NoSuchProviderException;
  9 import java.security.Security;
 10 import java.security.spec.InvalidKeySpecException;
 11 
 12 import javax.crypto.BadPaddingException;
 13 import javax.crypto.Cipher;
 14 import javax.crypto.IllegalBlockSizeException;
 15 import javax.crypto.KeyGenerator;
 16 import javax.crypto.NoSuchPaddingException;
 17 import javax.crypto.SecretKey;
 18 import javax.crypto.spec.IvParameterSpec;
 19 import javax.crypto.spec.SecretKeySpec;
 20 
 21 import org.apache.commons.codec.binary.Base64;
 22 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 23 
 24 /**
 25  * 基于BC的AES算法,工作模式采用CTR
 26  */
 27 public class AESBC {
 28     private static final String ENCODING = "UTF-8";
 29     private static final String KEY_ALGORITHM = "AES";//产生密钥的算法
 30     private static final String CIPHER_ALGORITHM = "AES/CTR/PKCS7Padding";//加解密算法 格式:算法/工作模式/填充模式 注意:ECB不使用IV参数,CTR使用
 31     private static final byte[] IV = "zhaojigangzhaoji".getBytes();//注意:这里需要是十六个字符,用于CTR
 32     /**
 33      * 产生密钥
 34      */
 35     public static byte[] getKey() throws NoSuchAlgorithmException{
 36         Security.addProvider(new BouncyCastleProvider());//加入BCProvider
 37         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
 38         keyGenerator.init(256);//初始化密钥长度,128,192,256(选用192和256的时候需要配置无政策限制权限文件--JDK6)
 39         SecretKey key =keyGenerator.generateKey();//产生密钥
 40         return key.getEncoded();
 41     }
 42     
 43     /**
 44      * 还原密钥:二进制字节数组转换为Java对象
 45      */
 46     public static Key toKey(byte[] keyByte){
 47         return new SecretKeySpec(keyByte, KEY_ALGORITHM);
 48     }
 49     
 50     /**
 51      * AES加密
 52      * @param data     带加密数据
 53      * @param keyByte  密钥
 54      */
 55     public static byte[] encrypt(String data, byte[] keyByte) throws InvalidKeyException, 
 56                                                                      NoSuchAlgorithmException, 
 57                                                                      InvalidKeySpecException, 
 58                                                                      NoSuchPaddingException, 
 59                                                                      IllegalBlockSizeException, 
 60                                                                      BadPaddingException, 
 61                                                                      UnsupportedEncodingException, 
 62                                                                      NoSuchProviderException, 
 63                                                                      InvalidAlgorithmParameterException{
 64         Key key = toKey(keyByte);//还原密钥
 65         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//使用BC
 66         cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));//设置加密模式并且初始化key,加入IV用于BC下的CTR
 67         return cipher.doFinal(data.getBytes(ENCODING));
 68     }
 69     
 70     /**
 71      * AES加密,并转为16进制字符串或Base64编码字符串
 72      */
 73     public static String encryptAESHex(String data, byte[] keyByte) throws InvalidKeyException, 
 74                                                                            NoSuchAlgorithmException, 
 75                                                                            InvalidKeySpecException, 
 76                                                                            NoSuchPaddingException, 
 77                                                                            IllegalBlockSizeException, 
 78                                                                            BadPaddingException, 
 79                                                                            UnsupportedEncodingException, 
 80                                                                            NoSuchProviderException, 
 81                                                                            InvalidAlgorithmParameterException {
 82         byte[] encodedByte = encrypt(data, keyByte);
 83         //return new String(Hex.encode(encodedByte));//借助BC
 84         //return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
 85         return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
 86     }
 87     
 88     /**
 89      * AES解密
 90      * @param data        待解密数据为字节数组
 91      * @param keyByte    密钥
 92      */
 93     public static byte[] decrypt(byte[] data, byte[] keyByte) throws InvalidKeyException, 
 94                                                                      NoSuchAlgorithmException, 
 95                                                                      InvalidKeySpecException, 
 96                                                                      NoSuchPaddingException, 
 97                                                                      IllegalBlockSizeException, 
 98                                                                      BadPaddingException, 
 99                                                                      UnsupportedEncodingException, 
100                                                                      NoSuchProviderException, 
101                                                                      InvalidAlgorithmParameterException {
102         Key key = toKey(keyByte);//还原密钥
103         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");
104         cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));//设置加密模式并且初始化key,加入IV用于BC下的CTR
105         return cipher.doFinal(data);
106     }
107     
108     /**
109      * AES解密
110      * @param data        待解密数据为字符串
111      * @param keyByte    密钥
112      */
113     public static byte[] decrypt(String data, byte[] keyByte) throws InvalidKeyException, 
114                                                                      NoSuchAlgorithmException, 
115                                                                      InvalidKeySpecException, 
116                                                                      NoSuchPaddingException, 
117                                                                      IllegalBlockSizeException, 
118                                                                      BadPaddingException, 
119                                                                      UnsupportedEncodingException, 
120                                                                      NoSuchProviderException, 
121                                                                      InvalidAlgorithmParameterException {
122         Key key = toKey(keyByte);//还原密钥
123         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");
124         cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));//设置加密模式并且初始化key,加入IV用于BC下的CTR
125         return cipher.doFinal(Base64.decodeBase64(data));
126     }
127     
128     /**
129      * 测试
130      */
131     public static void main(String[] args) throws NoSuchAlgorithmException, 
132                                                   InvalidKeyException, 
133                                                   InvalidKeySpecException, 
134                                                   NoSuchPaddingException, 
135                                                   IllegalBlockSizeException, 
136                                                   BadPaddingException, 
137                                                   UnsupportedEncodingException, 
138                                                   NoSuchProviderException, 
139                                                   InvalidAlgorithmParameterException {
140         String data = "找一个好姑娘做老婆是我的梦 想!";
141         /*************测试encrypt()、decrypt()**************/
142         System.out.println("原文-->"+data);
143         byte[] keyByte = AESBC.getKey(); 
144         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
145         byte[] encodedByte = AESBC.encrypt(data, keyByte);
146         System.out.println("加密后-->"+encodedByte);
147         byte[] encodedByte2 = AESBC.encrypt(data, keyByte);
148         System.out.println("加密后-->"+encodedByte2);
149         byte[] decodedByte = AESBC.decrypt(encodedByte, keyByte);
150         System.out.println("解密后-->"+decodedByte);
151         for(int i=0;i<encodedByte.length;i++){
152             System.out.println(encodedByte[i]==encodedByte2[i]);
153         }
154         /*************测试encryptAESHex()、decrypt()**************/
155         System.out.println("原文-->"+data);
156         byte[] keyByte3 = AESBC.getKey(); 
157         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
158         String encodedStr = AESBC.encryptAESHex(data, keyByte3);
159         System.out.println("加密后-->"+encodedStr);
160         String encodedByte4 = AESBC.encryptAESHex(data, keyByte3);
161         System.out.println("加密后-->"+encodedByte4);
162         byte[] decodedByte3 = AESBC.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
163         System.out.println("解密Byte[]后-->"+decodedByte3);
164         byte[] decodedByte4 = AESBC.decrypt(encodedStr, keyByte3);
165         System.out.println("解密String后-->"+decodedByte4);
166     }
167 }

 注意点:

  • CTR是AES最常使用的工作模式
  • 在CTR模式下需要加入IV参数(必须是一个16位的自己数组,例如:byte[] IV = "zhaojigangzhaoji".getBytes()),这是ECB模式所不需要的。
  • IV参数用于cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV))

9.1、IDEA

特点:

  • 先于AES出来取代DES
  • 安全性极高
  • 常用于电子邮件加密算法

9.2、实现方式

  • Bouncy Castle(BC,工作模式只有ECB,密钥长度为128位)

9.2.1、基于BC实现的IDEA算法

1 package com.util.idea;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.security.InvalidAlgorithmParameterException;
  5 import java.security.InvalidKeyException;
  6 import java.security.Key;
  7 import java.security.NoSuchAlgorithmException;
  8 import java.security.NoSuchProviderException;
  9 import java.security.Security;
 10 import java.security.spec.InvalidKeySpecException;
 11 
 12 import javax.crypto.BadPaddingException;
 13 import javax.crypto.Cipher;
 14 import javax.crypto.IllegalBlockSizeException;
 15 import javax.crypto.KeyGenerator;
 16 import javax.crypto.NoSuchPaddingException;
 17 import javax.crypto.SecretKey;
 18 import javax.crypto.spec.SecretKeySpec;
 19 
 20 import org.apache.commons.codec.binary.Base64;
 21 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 22 
 23 /**
 24  * 基于BC的IDEA算法,工作模式只有ECB
 25  */
 26 public class IDEABC {
 27     private static final String ENCODING = "UTF-8";
 28     private static final String KEY_ALGORITHM = "IDEA";//产生密钥的算法
 29     private static final String CIPHER_ALGORITHM = "IDEA/ECB/PKCS5Padding";//加解密算法 格式:算法/工作模式/填充模式
 30     /**
 31      * 产生密钥
 32      */
 33     public static byte[] getKey() throws NoSuchAlgorithmException{
 34         Security.addProvider(new BouncyCastleProvider());//在BC中用,JDK下去除
 35         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
 36         keyGenerator.init(128);//初始化密钥长度,128
 37         SecretKey key =keyGenerator.generateKey();//产生密钥
 38         return key.getEncoded();
 39     }
 40     
 41     /**
 42      * 还原密钥:二进制字节数组转换为Java对象
 43      */
 44     public static Key toKey(byte[] keyByte){
 45         return new SecretKeySpec(keyByte, KEY_ALGORITHM);
 46     }
 47     
 48     /**
 49      * IDEA加密
 50      * @param data     带加密数据
 51      * @param keyByte  密钥
 52      */
 53     public static byte[] encrypt(String data, byte[] keyByte) throws NoSuchAlgorithmException, 
 54                                                                      NoSuchProviderException, 
 55                                                                      NoSuchPaddingException, 
 56                                                                      InvalidKeyException, 
 57                                                                      IllegalBlockSizeException, 
 58                                                                      BadPaddingException, 
 59                                                                      UnsupportedEncodingException {
 60         Key key = toKey(keyByte);//还原密钥
 61         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
 62         cipher.init(Cipher.ENCRYPT_MODE, key);//设置加密模式并且初始化key
 63         return cipher.doFinal(data.getBytes(ENCODING));
 64     }
 65     
 66     /**
 67      * IDEA加密,并转为16进制字符串或Base64编码字符串
 68      */
 69     public static String encryptIDEAHex(String data, byte[] keyByte) throws NoSuchAlgorithmException, 
 70                                                                            NoSuchProviderException, 
 71                                                                            NoSuchPaddingException, 
 72                                                                            InvalidKeyException, 
 73                                                                            IllegalBlockSizeException, 
 74                                                                            BadPaddingException, 
 75                                                                            UnsupportedEncodingException {
 76         byte[] encodedByte = encrypt(data, keyByte);
 77         //return new String(Hex.encode(encodedByte));//借助BC
 78         //return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
 79         return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
 80     }
 81     
 82     /**
 83      * IDEA解密
 84      * @param data        待解密数据为字节数组
 85      * @param keyByte    密钥
 86      */
 87     public static byte[] decrypt(byte[] data, byte[] keyByte) throws NoSuchAlgorithmException, 
 88                                                                      NoSuchProviderException, 
 89                                                                      NoSuchPaddingException, 
 90                                                                      InvalidKeyException, 
 91                                                                      IllegalBlockSizeException, 
 92                                                                      BadPaddingException {
 93         Key key = toKey(keyByte);//还原密钥
 94         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
 95         cipher.init(Cipher.DECRYPT_MODE, key);
 96         return cipher.doFinal(data);
 97     }
 98     
 99     /**
100      * IDEA解密
101      * @param data        待解密数据为字符串
102      * @param keyByte    密钥
103      */
104     public static byte[] decrypt(String data, byte[] keyByte) throws NoSuchAlgorithmException, 
105                                                                      NoSuchProviderException, 
106                                                                      NoSuchPaddingException, 
107                                                                      InvalidKeyException, 
108                                                                      IllegalBlockSizeException, 
109                                                                      BadPaddingException  {
110         Key key = toKey(keyByte);//还原密钥
111         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM,"BC");//BC下用
112         cipher.init(Cipher.DECRYPT_MODE, key);
113         return cipher.doFinal(Base64.decodeBase64(data));//注意data不可以直接采用data.getByte()方法转化为字节数组,否则会抛异常
114     }
115     
116     /**
117      * 测试
118      */
119     public static void main(String[] args) throws NoSuchAlgorithmException, 
120                                                   InvalidKeyException, 
121                                                   InvalidKeySpecException, 
122                                                   NoSuchPaddingException, 
123                                                   IllegalBlockSizeException, 
124                                                   BadPaddingException, 
125                                                   UnsupportedEncodingException, 
126                                                   NoSuchProviderException, 
127                                                   InvalidAlgorithmParameterException {
128         String data = "找一个好姑娘做老婆是我的梦 想!";
129         /*************测试encrypt()、decrypt()**************/
130         System.out.println("原文-->"+data);
131         byte[] keyByte = IDEABC.getKey(); 
132         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
133         byte[] encodedByte = IDEABC.encrypt(data, keyByte);
134         System.out.println("加密后-->"+encodedByte);
135         byte[] encodedByte2 = IDEABC.encrypt(data, keyByte);
136         System.out.println("加密后-->"+encodedByte2);
137         byte[] decodedByte = IDEABC.decrypt(encodedByte, keyByte);
138         System.out.println("解密后-->"+decodedByte);
139         for(int i=0;i<encodedByte.length;i++){
140             System.out.println(encodedByte[i]==encodedByte2[i]);
141         }
142         /*************测试encryptIDEAHex()、decrypt()**************/
143         System.out.println("原文-->"+data);
144         byte[] keyByte3 = IDEABC.getKey(); 
145         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
146         String encodedStr = IDEABC.encryptIDEAHex(data, keyByte3);
147         System.out.println("加密后-->"+encodedStr);
148         String encodedByte4 = IDEABC.encryptIDEAHex(data, keyByte3);
149         System.out.println("加密后-->"+encodedByte4);
150         byte[] decodedByte3 = IDEABC.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
151         System.out.println("解密Byte[]后-->"+decodedByte3);
152         byte[] decodedByte4 = IDEABC.decrypt(encodedStr, keyByte3);
153         System.out.println("解密String后-->"+decodedByte4);
154     }
155 }

注意:

  • 与基于BC实现的AES算法代码基本一样

 

 

posted @ 2022-05-22 15:17  hanease  阅读(624)  评论(0编辑  收藏  举报