項目中又遇到了加密問題,又去翻了半天,然后做測試,干脆就把常用的兩類小結一下.
1.第一種所謂的MD5加密
其實也不算加密,只是基於Hash算法的不可逆編碼而已,等於說,一旦經過MD5處理,是不可能從編碼后的字符串反推回去的.
MD5的方法是基於散列的。本身信息不全。理論上是不能還原成唯一字符串的。
網上所謂的解密,也只是擁有一個足夠大的字典映射,將編碼前的源字符和編碼后的目標字符關聯起來而已,大多數常見的還行,復雜點的估計就會話費很長時間,有興趣的可以試試.
至於MD5的用法,在初次錄入的時候,也就做一次編碼,而后存儲,沒什么可說的.主要是驗證一致性,如登錄中的密碼,普遍做法就是將新獲取的密碼編碼,在用編碼之后的和數據庫中的比較,判斷是否一致.
理論上來講,對於這個密碼,除了使用的人,其他人是不知道的,包括管理員.
一般的系統這種方案也就夠用了.或者利用MD5多次編碼(加密),次數自己控制即可,也能增加點安全性.
2.第二種就是AES加密/解密
AES 是一種對稱加密算法,加密過程中要使用密鑰這個東西. 有興趣的可以去仔細了解一下: http://www.mamicode.com/info-detail-514466.html
就是說,我有個密碼:mima001,要使用AES加密,此時我就需要提供一個 密鑰(key) :thisKey,然后使用AES算法加密,得到一個結果result,存入數據庫;
然后,解密的時候,我們從數據庫中拿到這個result,然后同時也要獲得上面加密的時候用到的密鑰:thisKey,然后使用AES算法解密;
在這個過程中,如果有密鑰,則整個過程是可逆的,並且密鑰只有一個,可逆相對來說也就是對稱的,加密前和解密后的東西,沒有什么差異.
另外,補充一點啊,就是加密解密基礎問題:字節數組和(16進制)字符串的相互轉換
在加密時,一般加密算法和hash算法,它們操作的都是字節數組,對字節數組按照加密算法進行各種變換,運算,得到的結果也是字節數組。而我們一般是要求對字符串進行加密,所以就涉及到字符串String到 byte[] 的轉換,這個很簡單。同時在解密時,也涉及到字節數組byte[] 到 String 的轉換。另外在對用戶的密碼進行hash加密之后,最終是要保存在數據庫中,所以加密得到 byte[] 也要轉換到 String.
想了解詳細一點的朋友可以去: http://www.cnblogs.com/digdeep/p/4627813.html 看看.
下面是工具類:提供了加密方法,解密方法,還有講加密結果轉換為常見的字符串轉換方法.
1 import javax.crypto.*; 2 import javax.crypto.spec.SecretKeySpec; 3 import java.io.UnsupportedEncodingException; 4 import java.security.InvalidKeyException; 5 import java.security.MessageDigest; 6 import java.security.NoSuchAlgorithmException; 7 import java.security.SecureRandom; 8 9 /** 10 * @see: PasswordUtil 11 * @author: lnexin@aliyun.com 12 * @date: 2017-04-29 10:12 13 */ 14 public class PasswordUtil { 15 /** 16 * 使用: 17 * 直接使用即可,至於具體參數,看下面方法的說明即可; 18 * 1. PasswordUtil.MD5Encode(); MD5不可逆簡單加密:散列函數-基於HASH算法的編碼 19 * 2. PasswordUtil.AESEncrypt(); AES加密 20 * 3. PasswordUtil.AESDecrypt(); AES解密 21 * 4. PasswordUtil.parseByte2HexStr(); 二進制到16進制 22 * 5. PasswordUtil.parseHexStr2Byte(); 16進制到2進制 23 */ 24 25 // 16進制的字符數組 26 private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; 27 28 /** 29 * @param source 原字符串 30 * @param encoding 指定編碼類型 31 * @param uppercase 是否轉為大寫字符串 32 */ 33 public static String MD5Encode(String source, String encoding, boolean uppercase) { 34 String result = null; 35 try { 36 result = source; 37 // 獲得MD5摘要對象 38 MessageDigest messageDigest = MessageDigest.getInstance("MD5"); 39 // 使用指定的字節數組更新摘要信息 40 messageDigest.update(result.getBytes(encoding)); 41 // messageDigest.digest()獲得16位長度 42 // result = parseByte2HexStr(messageDigest.digest()); 43 result = byteArrayToHexString(messageDigest.digest()); 44 45 } catch (Exception e) { 46 e.printStackTrace(); 47 } 48 return uppercase ? result.toUpperCase() : result; 49 } 50 51 /** 52 * AES 加密 53 * 54 * @param content 需要加密的內容 55 * @param aesKey 加密密鑰 56 * @return 57 */ 58 public static byte[] AESEncrypt(String content, String aesKey) { 59 try { 60 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 61 kgen.init(128, new SecureRandom(aesKey.getBytes())); 62 SecretKey secretKey = kgen.generateKey(); 63 byte[] enCodeFormat = secretKey.getEncoded(); 64 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 65 Cipher cipher = Cipher.getInstance("AES");// 創建密碼器 66 byte[] byteContent = content.getBytes("utf-8"); 67 cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 68 byte[] result = cipher.doFinal(byteContent); 69 return result; // 加密 70 } catch (NoSuchAlgorithmException e) { 71 e.printStackTrace(); 72 } catch (NoSuchPaddingException e) { 73 e.printStackTrace(); 74 } catch (InvalidKeyException e) { 75 e.printStackTrace(); 76 } catch (UnsupportedEncodingException e) { 77 e.printStackTrace(); 78 } catch (IllegalBlockSizeException e) { 79 e.printStackTrace(); 80 } catch (BadPaddingException e) { 81 e.printStackTrace(); 82 } 83 return null; 84 } 85 86 /** 87 * 解密 88 * 89 * @param content 待解密內容 90 * @param aesKey 解密密鑰 秘miyao 91 * @return 92 */ 93 public static byte[] AESDecrypt(byte[] content, String aesKey) { 94 try { 95 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 96 kgen.init(128, new SecureRandom(aesKey.getBytes())); 97 SecretKey secretKey = kgen.generateKey(); 98 byte[] enCodeFormat = secretKey.getEncoded(); 99 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 100 Cipher cipher = Cipher.getInstance("AES");// 創建密碼器 101 cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 102 byte[] result = cipher.doFinal(content); 103 return result; // 加密 104 } catch (NoSuchAlgorithmException e) { 105 e.printStackTrace(); 106 } catch (NoSuchPaddingException e) { 107 e.printStackTrace(); 108 } catch (InvalidKeyException e) { 109 e.printStackTrace(); 110 } catch (IllegalBlockSizeException e) { 111 e.printStackTrace(); 112 } catch (BadPaddingException e) { 113 e.printStackTrace(); 114 } 115 return null; 116 } 117 118 /** 119 * 將二進制轉換成16進制 120 */ 121 public static String parseByte2HexStr(byte buf[]) { 122 StringBuffer sb = new StringBuffer(); 123 for (int i = 0; i < buf.length; i++) { 124 String hex = Integer.toHexString(buf[i] & 0xFF); 125 if (hex.length() == 1) { 126 hex = '0' + hex; 127 } 128 sb.append(hex.toUpperCase()); 129 } 130 return sb.toString(); 131 } 132 133 /** 134 * 將16進制轉換為二進制 135 */ 136 public static byte[] parseHexStr2Byte(String hexStr) { 137 if (hexStr.length() < 1) 138 return null; 139 byte[] result = new byte[hexStr.length() / 2]; 140 for (int i = 0; i < hexStr.length() / 2; i++) { 141 int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); 142 int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); 143 result[i] = (byte) (high * 16 + low); 144 } 145 return result; 146 } 147
//byte轉16進制 148 private static String byteArrayToHexString(byte[] bytes) { 149 StringBuilder stringBuilder = new StringBuilder(); 150 for (byte tem : bytes) { 151 stringBuilder.append(byteToHexString(tem)); 152 } 153 return stringBuilder.toString(); 154 } 155 //16進制轉byte[] 156 private static String byteToHexString(byte b) { 157 int n = b; 158 if (n < 0) { 159 n = 256 + n; 160 } 161 int d1 = n / 16; 162 int d2 = n % 16; 163 return hexDigits[d1] + hexDigits[d2]; 164 } 165 166 }
使用說明:
隨便寫個測試類:截圖直觀一點,控制台輸出在圖右下角,測試具體代碼在文末.
1 public class PasswordTest { 2 3 4 @Test 5 public void MD5Test() throws Exception { 6 String encode = PasswordUtil.MD5Encode("admin", "UTF8", true); 7 System.out.println(); 8 System.out.println("MD5算法:"+encode); 9 } 10 11 @Test 12 public void aesTest() throws Exception { 13 String content = "admin"; 14 String aesKey = "thisiskey"; 15 16 byte[] encrypt = PasswordUtil.AESEncrypt(content, aesKey);//加密 17 System.out.println("AES加密后-byte[]:"+encrypt); 18 19 String strHex = PasswordUtil.parseByte2HexStr(encrypt); 20 System.out.println("轉換后的十六進制:"+strHex); 21 22 23 byte[] decrypt = PasswordUtil.AESDecrypt(PasswordUtil.parseHexStr2Byte(strHex), aesKey);//解密 24 System.out.println("AES解密后-byte[]"+decrypt); 25 System.out.println("AES解密轉換后:"+new String(decrypt)); 26 } 27 28 }
使用工具類的時候,要傳入什么參數,主要方法上面的注釋即可;