第四章 对称加密算法--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算法代码基本一样