加解密算法总结(RSA,DES,MD5)
一.非对称加密算法RSA
非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。RSA算法实现如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.io.ByteArrayOutputStream; 2 import java.security.Key; 3 import java.security.KeyFactory; 4 import java.security.KeyPair; 5 import java.security.KeyPairGenerator; 6 import java.security.interfaces.RSAPrivateKey; 7 import java.security.interfaces.RSAPublicKey; 8 import java.security.spec.PKCS8EncodedKeySpec; 9 import java.security.spec.X509EncodedKeySpec; 10 import java.util.HashMap; 11 import java.util.Map; 12 13 import javax.crypto.Cipher; 14 15 import sun.misc.BASE64Decoder; 16 import sun.misc.BASE64Encoder; 17 18 public class RSAUtils { 19 20 21 /**默认编码*/ 22 private final static String DEFAULT_CHARSET = "UTF-8"; 23 24 /** *//** 25 * RSA最大加密明文大小 26 */ 27 private static final int MAX_ENCRYPT_BLOCK = 117; 28 29 /** *//** 30 * RSA最大解密密文大小 31 */ 32 private static final int MAX_DECRYPT_BLOCK = 128; 33 34 /** 35 * BASE64解密 36 * @param key 37 * @return 38 * @throws Exception 39 */ 40 public static byte[] decryptBASE64(String key) throws Exception{ 41 return (new BASE64Decoder()).decodeBuffer(key); 42 } 43 44 /** 45 * BASE64加密 46 * @param key 47 * @return 48 * @throws Exception 49 */ 50 public static String encryptBASE64(byte[] key)throws Exception{ 51 return (new BASE64Encoder()).encodeBuffer(key); 52 } 53 54 55 public static final String KEY_ALGORTHM="RSA";// 56 public static final String SIGNATURE_ALGORITHM="MD5withRSA"; 57 58 public static final String PUBLIC_KEY = "RSAPublicKey";//公钥 59 public static final String PRIVATE_KEY = "RSAPrivateKey";//私钥 60 61 62 63 64 /** 65 * 初始化密钥 66 * @return 67 * @throws Exception 68 */ 69 public static Map<String,Object> initKey()throws Exception{ 70 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM); 71 keyPairGenerator.initialize(1024); 72 KeyPair keyPair = keyPairGenerator.generateKeyPair(); 73 74 //公钥 75 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 76 //私钥 77 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 78 79 Map<String,Object> keyMap = new HashMap<String, Object>(2); 80 keyMap.put(PUBLIC_KEY, publicKey); 81 keyMap.put(PRIVATE_KEY, privateKey); 82 83 return keyMap; 84 } 85 86 /** 87 * 取得公钥,并转化为String类型 88 * @param keyMap 89 * @return 90 * @throws Exception 91 */ 92 public static String getPublicKey(Map<String, Object> keyMap)throws Exception{ 93 Key key = (Key) keyMap.get(PUBLIC_KEY); 94 return encryptBASE64(key.getEncoded()); 95 } 96 97 /** 98 * 取得私钥,并转化为String类型 99 * @param keyMap 100 * @return 101 * @throws Exception 102 */ 103 public static String getPrivateKey(Map<String, Object> keyMap) throws Exception{ 104 Key key = (Key) keyMap.get(PRIVATE_KEY); 105 return encryptBASE64(key.getEncoded()); 106 } 107 108 /** 109 * 用私钥加密 110 * @param data 加密数据 111 * @param key 密钥 112 * @return 113 * @throws Exception 114 */ 115 public static byte[] encryptByPrivateKey(byte[] data,String key)throws Exception{ 116 //解密密钥 117 byte[] keyBytes = decryptBASE64(key); 118 //取私钥 119 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); 120 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); 121 Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); 122 123 //对数据加密 124 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 125 cipher.init(Cipher.ENCRYPT_MODE, privateKey); 126 127 int inputLen = data.length; 128 ByteArrayOutputStream out = new ByteArrayOutputStream(); 129 int offSet = 0; 130 byte[] cache; 131 int i = 0; 132 // 对数据分段加密 133 while (inputLen - offSet > 0) { 134 if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 135 cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 136 } else { 137 cache = cipher.doFinal(data, offSet, inputLen - offSet); 138 } 139 out.write(cache, 0, cache.length); 140 i++; 141 offSet = i * MAX_ENCRYPT_BLOCK; 142 } 143 byte[] encryptedData = out.toByteArray(); 144 out.close(); 145 return encryptedData; 146 } 147 148 149 /** 150 * 用私钥加密 151 * @param data 加密数据 152 * @param key 密钥 153 * @return 154 * @throws Exception 155 */ 156 public static String encryptByPrivateKey(String data,String key)throws Exception{ 157 158 return encryptBASE64(encryptByPrivateKey(data.getBytes(DEFAULT_CHARSET), key)); 159 } 160 161 /** 162 * 用私钥解密 163 * @param data base64 164 * @param key 165 * @return String 166 * @throws Exception 167 */ 168 public static String decryptByPrivateKey(String data,String key)throws Exception{ 169 170 return new String(decryptByPrivateKey(decryptBASE64(data), key),DEFAULT_CHARSET); 171 } 172 173 174 /** 175 * 用私钥解密 * @param data 加密数据 176 * @param key 密钥 177 * @return 178 * @throws Exception 179 */ 180 public static byte[] decryptByPrivateKey(byte[] data,String key)throws Exception{ 181 //对私钥解密 182 byte[] keyBytes = decryptBASE64(key); 183 184 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); 185 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); 186 Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); 187 //对数据解密 188 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 189 cipher.init(Cipher.DECRYPT_MODE, privateKey); 190 191 int inputLen = data.length; 192 ByteArrayOutputStream out = new ByteArrayOutputStream(); 193 int offSet = 0; 194 byte[] cache; 195 int i = 0; 196 // 对数据分段解密 197 while (inputLen - offSet > 0) { 198 if (inputLen - offSet > MAX_DECRYPT_BLOCK) { 199 cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK); 200 } else { 201 cache = cipher.doFinal(data, offSet, inputLen - offSet); 202 } 203 out.write(cache, 0, cache.length); 204 i++; 205 offSet = i * MAX_DECRYPT_BLOCK; 206 } 207 byte[] decryptedData = out.toByteArray(); 208 out.close(); 209 return decryptedData; 210 } 211 212 213 /** 214 * 用公钥加密 215 * @param data 加密数据 216 * @param key 密钥 217 * @return 218 * @throws Exception 219 */ 220 public static byte[] encryptByPublicKey(byte[] data,String key)throws Exception{ 221 //对公钥解密 222 byte[] keyBytes = decryptBASE64(key); 223 //取公钥 224 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); 225 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); 226 Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec); 227 228 //对数据解密 229 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 230 cipher.init(Cipher.ENCRYPT_MODE, publicKey); 231 232 int inputLen = data.length; 233 ByteArrayOutputStream out = new ByteArrayOutputStream(); 234 int offSet = 0; 235 byte[] cache; 236 int i = 0; 237 // 对数据分段加密 238 while (inputLen - offSet > 0) { 239 if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 240 cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 241 } else { 242 cache = cipher.doFinal(data, offSet, inputLen - offSet); 243 } 244 out.write(cache, 0, cache.length); 245 i++; 246 offSet = i * MAX_ENCRYPT_BLOCK; 247 } 248 byte[] encryptedData = out.toByteArray(); 249 out.close(); 250 return encryptedData; 251 } 252 253 254 /** 255 * 用公钥解密 256 * @param data 加密数据 257 * @param key 密钥 258 * @return 259 * @throws Exception 260 */ 261 public static byte[] decryptByPublicKey(byte[] data,String key)throws Exception{ 262 //对私钥解密 263 byte[] keyBytes = decryptBASE64(key); 264 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); 265 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM); 266 Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec); 267 268 //对数据解密 269 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 270 cipher.init(Cipher.DECRYPT_MODE, publicKey); 271 272 int inputLen = data.length; 273 ByteArrayOutputStream out = new ByteArrayOutputStream(); 274 int offSet = 0; 275 byte[] cache; 276 int i = 0; 277 // 对数据分段解密 278 while (inputLen - offSet > 0) { 279 if (inputLen - offSet > MAX_DECRYPT_BLOCK) { 280 cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK); 281 } else { 282 cache = cipher.doFinal(data, offSet, inputLen - offSet); 283 } 284 out.write(cache, 0, cache.length); 285 i++; 286 offSet = i * MAX_DECRYPT_BLOCK; 287 } 288 byte[] decryptedData = out.toByteArray(); 289 out.close(); 290 return decryptedData; 291 } 292 293 /** 294 * 用公钥加密 295 * @param data 加密数据 296 * @param key 密钥 297 * @return 298 * @throws Exception 299 */ 300 public static String encryptByPublicKey(String data,String key)throws Exception{ 301 302 return encryptBASE64(encryptByPublicKey(data.getBytes(DEFAULT_CHARSET), key)); 303 } 304 305 /** 306 * 用公钥解密 307 * @param data base64 308 * @param key 309 * @return String 310 * @throws Exception 311 */ 312 public static String decryptByPublicKey(String data,String key)throws Exception{ 313 314 return new String(decryptByPublicKey(decryptBASE64(data), key),DEFAULT_CHARSET); 315 } 316 317 public static void main(String[] args) throws Exception { 318 319 Map<String,Object> keyMap = initKey(); 320 String publicKey = getPublicKey(keyMap); 321 String privateKey = getPrivateKey(keyMap); 322 323 String s = "水电费"; 324 s = encryptByPrivateKey(s, privateKey); 325 System.out.println("私钥加密后密文为:"+s); 326 s = decryptByPublicKey(s, publicKey); 327 System.out.println("公钥解密后明文为:"+s); 328 329 } 330 }
二.对称加密算法DES
在对称加密算法中,数据发信方将明文原始数据和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥.DES具体实现如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.security.InvalidKeyException; 2 import java.security.Key; 3 import java.security.NoSuchAlgorithmException; 4 import java.security.SecureRandom; 5 import java.security.spec.InvalidKeySpecException; 6 7 import javax.crypto.Cipher; 8 import javax.crypto.SecretKey; 9 import javax.crypto.SecretKeyFactory; 10 import javax.crypto.spec.DESKeySpec; 11 12 import com.sun.org.apache.xml.internal.security.utils.Base64; 13 14 public class DESUtil { 15 //算法名称 16 public static final String KEY_ALGORITHM = "DES"; 17 //算法名称/加密模式/填充方式 18 //DES共有四种工作模式-->>ECB:电子密码本模式、CBC:加密分组链接模式、CFB:加密反馈模式、OFB:输出反馈模式 19 public static final String CIPHER_ALGORITHM = "DES/ECB/NoPadding"; 20 21 /** 22 * 23 * 生成密钥key对象 24 * @param KeyStr 密钥字符串 25 * @return 密钥对象 26 * @throws InvalidKeyException 27 * @throws NoSuchAlgorithmException 28 * @throws InvalidKeySpecException 29 * @throws Exception 30 */ 31 private static SecretKey keyGenerator(String keyStr) throws Exception { 32 byte input[] = HexString2Bytes(keyStr); 33 DESKeySpec desKey = new DESKeySpec(input); 34 //创建一个密匙工厂,然后用它把DESKeySpec转换成 35 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 36 SecretKey securekey = keyFactory.generateSecret(desKey); 37 return securekey; 38 } 39 40 private static int parse(char c) { 41 if (c >= 'a') return (c - 'a' + 10) & 0x0f; 42 if (c >= 'A') return (c - 'A' + 10) & 0x0f; 43 return (c - '0') & 0x0f; 44 } 45 46 // 从十六进制字符串到字节数组转换 47 public static byte[] HexString2Bytes(String hexstr) { 48 byte[] b = new byte[hexstr.length() / 2]; 49 int j = 0; 50 for (int i = 0; i < b.length; i++) { 51 char c0 = hexstr.charAt(j++); 52 char c1 = hexstr.charAt(j++); 53 b[i] = (byte) ((parse(c0) << 4) | parse(c1)); 54 } 55 return b; 56 } 57 58 /** 59 * 加密数据 60 * @param data 待加密数据 61 * @param key 密钥 62 * @return 加密后的数据 63 */ 64 public static String encrypt(String data, String key) throws Exception { 65 Key deskey = keyGenerator(key); 66 // 实例化Cipher对象,它用于完成实际的加密操作 67 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 68 SecureRandom random = new SecureRandom(); 69 // 初始化Cipher对象,设置为加密模式 70 cipher.init(Cipher.ENCRYPT_MODE, deskey, random); 71 byte[] results = cipher.doFinal(data.getBytes()); 72 for (int i = 0; i < results.length; i++) { 73 System.out.print(results[i] + " "); 74 } 75 System.out.println(); 76 // 执行加密操作。加密后的结果通常都会用Base64编码进行传输 77 return Base64.encode(results); 78 } 79 80 /** 81 * 解密数据 82 * @param data 待解密数据 83 * @param key 密钥 84 * @return 解密后的数据 85 */ 86 public static String decrypt(String data, String key) throws Exception { 87 Key deskey = keyGenerator(key); 88 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 89 //初始化Cipher对象,设置为解密模式 90 cipher.init(Cipher.DECRYPT_MODE, deskey); 91 // 执行解密操作 92 return new String(cipher.doFinal(Base64.decode(data))); 93 } 94 95 public static void main(String[] args) throws Exception { 96 String source = "abcde123"; 97 System.out.println("原文: " + source); 98 String key = "A1B2C3D4E5F60708"; 99 String encryptData = encrypt(source, key); 100 System.out.println("加密后: " + encryptData); 101 String decryptData = decrypt(encryptData, key); 102 System.out.println("解密后: " + decryptData); 103 } 104 }
三.MD5摘要
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5具体实现如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class MD5{ 2 /* 3 *四个链接变量 4 */ 5 private final int A=0x67452301; 6 private final int B=0xefcdab89; 7 private final int C=0x98badcfe; 8 private final int D=0x10325476; 9 /* 10 *ABCD的临时变量 11 */ 12 private int Atemp,Btemp,Ctemp,Dtemp; 13 14 /* 15 *常量ti 16 *公式:floor(abs(sin(i+1))×(2pow32) 17 */ 18 private final int K[]={ 19 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, 20 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8, 21 0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193, 22 0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51, 23 0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, 24 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905, 25 0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681, 26 0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60, 27 0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, 28 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244, 29 0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92, 30 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314, 31 0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391}; 32 /* 33 *向左位移数,计算方法未知 34 */ 35 private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7, 36 12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, 37 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10, 38 15,21,6,10,15,21,6,10,15,21,6,10,15,21}; 39 40 41 /* 42 *初始化函数 43 */ 44 private void init(){ 45 Atemp=A; 46 Btemp=B; 47 Ctemp=C; 48 Dtemp=D; 49 } 50 /* 51 *移动一定位数 52 */ 53 private int shift(int a,int s){ 54 return(a<<s)|(a>>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位 55 } 56 /* 57 *主循环 58 */ 59 private void MainLoop(int M[]){ 60 int F,g; 61 int a=Atemp; 62 int b=Btemp; 63 int c=Ctemp; 64 int d=Dtemp; 65 for(int i = 0; i < 64; i ++){ 66 if(i<16){ 67 F=(b&c)|((~b)&d); 68 g=i; 69 }else if(i<32){ 70 F=(d&b)|((~d)&c); 71 g=(5*i+1)%16; 72 }else if(i<48){ 73 F=b^c^d; 74 g=(3*i+5)%16; 75 }else{ 76 F=c^(b|(~d)); 77 g=(7*i)%16; 78 } 79 int tmp=d; 80 d=c; 81 c=b; 82 b=b+shift(a+F+K[i]+M[g],s[i]); 83 a=tmp; 84 } 85 Atemp=a+Atemp; 86 Btemp=b+Btemp; 87 Ctemp=c+Ctemp; 88 Dtemp=d+Dtemp; 89 90 } 91 /* 92 *填充函数 93 *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64) 94 *填充方式为先加一个0,其它位补零 95 *最后加上64位的原来长度 96 */ 97 private int[] add(String str){ 98 int num=((str.length()+8)/64)+1;//以512位,64个字节为一组 99 int strByte[]=new int[num*16];//64/4=16,所以有16个整数 100 for(int i=0;i<num*16;i++){//全部初始化0 101 strByte[i]=0; 102 } 103 int i; 104 for(i=0;i<str.length();i++){ 105 strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序 106 } 107 strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1 108 /* 109 *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位 110 */ 111 strByte[num*16-2]=str.length()*8; 112 return strByte; 113 } 114 /* 115 *调用函数 116 */ 117 public String getMD5(String source){ 118 init(); 119 int strByte[]=add(source); 120 for(int i=0;i<strByte.length/16;i++){ 121 int num[]=new int[16]; 122 for(int j=0;j<16;j++){ 123 num[j]=strByte[i*16+j]; 124 } 125 MainLoop(num); 126 } 127 return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp); 128 129 } 130 /* 131 *整数变成16进制字符串 132 */ 133 private String changeHex(int a){ 134 String str=""; 135 for(int i=0;i<4;i++){ 136 str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(' ', '0'); 137 138 } 139 return str; 140 } 141 /* 142 *单例 143 */ 144 private static MD5 instance; 145 public static MD5 getInstance(){ 146 if(instance==null){ 147 instance=new MD5(); 148 } 149 return instance; 150 } 151 152 private MD5(){}; 153 154 /** 155 * 加密解密算法 执行一次加密,两次解密 156 */ 157 public static String convertMD5(String inStr){ 158 159 char[] a = inStr.toCharArray(); 160 for (int i = 0; i < a.length; i++){ 161 a[i] = (char) (a[i] ^ 't'); 162 } 163 String s = new String(a); 164 return s; 165 166 } 167 168 169 public static void main(String[] args){ 170 String s = "abcde"; 171 System.out.println("明文:"+s); 172 String str=MD5.getInstance().getMD5(s); 173 System.out.println("MD5值:"+str); 174 System.out.println("加密后:" + convertMD5(str)); 175 System.out.println("解密后:" + convertMD5(convertMD5(str))); 176 } 177 }