在項目中經常會對一些比較隱私的內容進行加密后再傳輸,比如登錄密碼、個人信息等;
DES和AES是目前兩種比較常用的對稱加密算法;
一、JS實現方式:
需要引入JavaScript加密庫-CryptoJS
1.DES加密以及解密:
1 //DES 加密 2 function encryptByDES(message, key) { 3 var keyHex = CryptoJS.enc.Utf8.parse(key); 4 var encrypted = CryptoJS.DES.encrypt(message, keyHex, { 5 mode: CryptoJS.mode.ECB, 6 padding: CryptoJS.pad.Pkcs7 7 }); 8 return encrypted.toString(); 9 } 10 //DES 解密 11 function decryptByDES(ciphertext, key) { 12 var keyHex = CryptoJS.enc.Utf8.parse(key); 13 // direct decrypt ciphertext 14 var decrypted = CryptoJS.DES.decrypt({ 15 ciphertext: CryptoJS.enc.Base64.parse(ciphertext) 16 }, keyHex, { 17 mode: CryptoJS.mode.ECB, 18 padding: CryptoJS.pad.Pkcs7 19 }); 20 return decrypted.toString(CryptoJS.enc.Utf8); 21 }
2.AES加密以及解密:
1 //AES 加密 2 function encryptByAES(message, key) { 3 var keyHex = CryptoJS.enc.Utf8.parse(key); 4 var encrypted = CryptoJS.AES.encrypt(message, keyHex, { 5 mode: CryptoJS.mode.ECB, 6 padding: CryptoJS.pad.Pkcs7 7 }); 8 return encrypted.toString(); 9 } 10 //AES 解密 11 function decryptByAES(ciphertext, key) { 12 var keyHex = CryptoJS.enc.Utf8.parse(key); 13 // direct decrypt ciphertext 14 var decrypted = CryptoJS.AES.decrypt({ 15 ciphertext: CryptoJS.enc.Base64.parse(ciphertext) 16 }, keyHex, { 17 mode: CryptoJS.mode.ECB, 18 padding: CryptoJS.pad.Pkcs7 19 }); 20 return decrypted.toString(CryptoJS.enc.Utf8); 21 }
二、Java實現
Java有兩種AES加密實現方式:
1.使用AES-128-ECB加密模式,秘鑰必須為16位字符串(128bit = 16 * 8bit);這種方式與上面JS的AES可以前后端配合一起使用;
1 // 加密 2 public static String Encrypt(String sSrc, String sKey) throws Exception { 3 if (sKey == null) { 4 System.out.print("Key為空null"); 5 return null; 6 } 7 // 判斷Key是否為16位 8 if (sKey.length() != 16) { 9 System.out.print("Key長度不是16位"); 10 return null; 11 } 12 byte[] raw = sKey.getBytes("utf-8"); 13 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 14 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/補碼方式" 15 cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 16 byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8")); 17 //此處使用BASE64做轉碼功能,同時能起到2次加密的作用。 18 //return new Base64().encodeToString(encrypted); 19 return Base64.encode(encrypted); 20 } 21 22 // 解密 23 public static String Decrypt(String sSrc, String sKey) throws Exception { 24 try { 25 // 判斷Key是否正確 26 if (sKey == null) { 27 System.out.print("Key為空null"); 28 return null; 29 } 30 // 判斷Key是否為16位 31 if (sKey.length() != 16) { 32 System.out.print("Key長度不是16位"); 33 return null; 34 } 35 byte[] raw = sKey.getBytes("utf-8"); 36 SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 37 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 38 cipher.init(Cipher.DECRYPT_MODE, skeySpec); 39 //先用base64轉碼 40 //byte[] encrypted1 = new Base64().decode(sSrc); 41 byte[] encrypted1 = Base64.decode(sSrc); 42 try { 43 byte[] original = cipher.doFinal(encrypted1); 44 String originalString = new String(original,"utf-8"); 45 return originalString; 46 } catch (Exception e) { 47 System.out.println(e.toString()); 48 return null; 49 } 50 } catch (Exception ex) { 51 System.out.println(ex.toString()); 52 return null; 53 } 54 }
2.下面這種方式對加密解密的秘鑰沒有長度限制(代碼中進行了補全到相應位數),但不能和JS的實現配合使用,將算法名稱和秘鑰的編碼位數進行更改就變為了DES加密
1 //加密 2 public static String encrypt(String content, String password) { 3 try { 4 //將秘鑰補全為128位 5 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 6 //若想改為DES加密,則需要將秘鑰位數改為64位 7 kgen.init(128, new SecureRandom(password.getBytes())); 8 SecretKey secretKey = kgen.generateKey(); 9 byte[] enCodeFormat = secretKey.getEncoded(); 10 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 11 //創建密碼器 12 Cipher cipher = Cipher.getInstance("AES"); 13 byte[] byteContent = content.getBytes("utf-8"); 14 //初始化 15 cipher.init(Cipher.ENCRYPT_MODE, key); 16 //加密 17 byte[] result = cipher.doFinal(byteContent); 18 //Base64轉碼 19 return Base64.encode(result); 20 } catch (NoSuchAlgorithmException e) { 21 e.printStackTrace(); 22 } catch (NoSuchPaddingException e) { 23 e.printStackTrace(); 24 } catch (InvalidKeyException e) { 25 e.printStackTrace(); 26 } catch (UnsupportedEncodingException e) { 27 e.printStackTrace(); 28 } catch (IllegalBlockSizeException e) { 29 e.printStackTrace(); 30 } catch (BadPaddingException e) { 31 e.printStackTrace(); 32 } 33 return null; 34 } 35 36 //解密 37 public static String decrypt(String content, String password) throws Exception { 38 try { 39 //將秘鑰補全為128位 40 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 41 //若想改為DES加密,則需要將秘鑰位數改為64位 42 kgen.init(128, new SecureRandom(password.getBytes())); 43 SecretKey secretKey = kgen.generateKey(); 44 byte[] enCodeFormat = secretKey.getEncoded(); 45 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 46 //創建密碼器 47 Cipher cipher = Cipher.getInstance("AES"); 48 //初始化 49 cipher.init(Cipher.DECRYPT_MODE, key); 50 //Base64轉碼 51 byte[] encrypted1 = Base64.decode(content); 52 //解密 53 byte[] result = cipher.doFinal(encrypted1); 54 //二進制轉為字符串 55 return new String(result, "utf-8"); 56 } catch (NoSuchAlgorithmException e) { 57 e.printStackTrace(); 58 } catch (NoSuchPaddingException e) { 59 e.printStackTrace(); 60 } catch (InvalidKeyException e) { 61 e.printStackTrace(); 62 } catch (IllegalBlockSizeException e) { 63 e.printStackTrace(); 64 } catch (BadPaddingException e) { 65 e.printStackTrace(); 66 } 67 return null; 68 }
加密解密時密碼器的輸入輸出都為2進制數組,這里我們用Base64在加解密的中間過程中進行了轉碼,所以可以以字符串形式展示加密后的密文,也可以使用下面的方法將二進制數組轉換為16進制的字符串來表示,同樣起到轉換的作用
1 //將二進制數組轉化為16進制字符串 2 public static String parseByte2HexStr(byte buf[]) { 3 StringBuffer sb = new StringBuffer(); 4 for (int i = 0; i < buf.length; i++) { 5 String hex = Integer.toHexString(buf[i] & 0xFF); 6 if (hex.length() == 1) { 7 hex = '0' + hex; 8 } 9 sb.append(hex.toUpperCase()); 10 } 11 return sb.toString(); 12 } 13 //將16進制字符串轉化為二進制數組 14 public static byte[] parseHexStr2Byte(String hexStr) { 15 if (hexStr.length() < 1) 16 return new byte[0]; 17 byte[] result = new byte[hexStr.length()/2]; 18 for (int i = 0;i< hexStr.length()/2; i++) { 19 int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); 20 int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); 21 result[i] = (byte) (high * 16 + low); 22 } 23 return result; 24 }