非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。RSA算法實現如下:
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具體實現如下:
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具體實現如下:
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 }