JAVA加密系列(一)-Base64與單向加密算法MD5、SHA、HMAC
Base64
Base64是網絡上最常見的用於傳輸8Bit字節碼的編碼方式之一,Base64就是一種基於64個可打印字符來表示二進制數據的方法,嚴格的來說base64屬於編碼格式並非加密算法,但是因爲base64是二進制數據可以和很多的加密算法配合產生化學反應,學加密前先了解清楚base64的原理,實質上應用場景非常廣泛,很容易掌握,不懂原理的可以看什麼是base64
單向加密
單向加密又稱爲不可逆加密算法,在加密過程中不使用密鑰,明文由系統加密處理成密文,密文無法解密。一般適合於驗證,在驗證過程中,重新輸入明文,並經過同樣的加密算法處理,得到相同的密文並被系統重新認證。廣泛使用於口令加密。
- MD5(Message Digest algorithm 5,信息摘要算法)
- SHA(Secure Hash Algorithm,安全散列算法)
- HMAC(Hash Message Authentication Code,散列消息鑑別碼)
加密解析
Base64
- 1 字節(byte) = 8 比特位(bit)
- Base64 定義了 64 (2^6)個可打印字符表示二進制的方法,也就是說 6 個 bit 的二進制數據可以用對應的字符代替表示
- 對於連續多個二進制數據,每 3 個字節一組進行轉換,3個字節 24 bit,然後將其分爲 4 部分(3×8 = 4×6),每個部分剛好 6 bit,將 6 bit 二進制轉換爲 Base64 定義的字符即完成轉換
- 例, 6 bit 二進制是 000000,那麼對應的字符就是 A,如果 6 bit 二進制是 110011,那麼對應的字符就是 z
- 若二進制數據字節數不是 3 的倍數,Base64 就將剩下的二進制數據補 0 至 3 的倍數,全 0 的用字符 “=” 代替
源碼解析
public static void main(String[] args) {
//字符串編碼
System.out.println("編碼結果:"+encrypt("hello word"));
//字符串解碼
System.out.println("編碼結果:"+decrypt("aGVsbG8gd29yZA=="));
}
public static String encrypt(String str){
byte[] bytes=str.getBytes();
bytes=Base64.getEncoder().encode(bytes);
return new String(bytes);
}
public static String decrypt(String str){
byte[] bytes=str.getBytes();
bytes=Base64.getDecoder().decode(bytes);
return new String(bytes);
}
log
編碼結果:aGVsbG8gd29yZA==
編碼結果:hello word
MD5
- 一般用於確保信息的傳輸完整一致性,校驗傳輸的數據是否被修改,一旦原始信息被修改,生成的 MD5 值將會變得很不同
- 算法能將任意大小、格式的文字或文件進行加密從而產生 128 bit(16 字節)的散列值。如同人的指紋,不同文本的 MD5 值是不同的。
- 極端情況:就是不同的字符串的 MD5 值一樣,這叫哈希碰撞。2009 年中科院就已經實現了相應的碰撞算法,不過 MD5 應用仍然很廣泛
- 一般不可破解,除非使用窮舉法,難度依舊很大
- MD5加密算法,是一種被廣泛使用的密碼散列函數,可以產生出一個128位的散列值,用於確保信息傳輸完全一致,在很多方面都有着廣泛的應用,例如保存用戶密碼,比較下載文件的md5值以保證文件無損毀等等。
源碼解析
public static void main(String[] args) {
//字符串編碼
System.out.println("編碼結果:"+encryptMD5("hello word"));
}
public static String encryptMD5(String str){
try {
byte[] bytes=str.getBytes();
MessageDigest messageDigest=MessageDigest.getInstance("MD5");
messageDigest.update(bytes);
bytes = messageDigest.digest();
// digest()最後確定返回md5 hash值,返回值爲8位字符串。因爲md5 hash值是16位的hex值,實際上就是8位的字符
// BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
//一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方)
return new BigInteger(1, bytes).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
log
編碼結果:13574ef0d58b50fab38ec841efe39df4
SHA
- 在使用上跟MD5沒什麼差別,畢竟都是單向加密,祖宗都是MD4,下面列舉一下幾點不同點
- 對強行攻擊的安全性:最顯著和最重要的區別是SHA-1摘要比MD5摘要長32 位。使用強行技術,產生任何一個報文使其摘要等於給定報摘要的難度對MD5是2128數量級的操作,而對SHA-1則是2160數量級的操作。這樣,SHA-1對強行攻擊有更大的強度。
- 對密碼分析的安全性:由於MD5的設計,易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。
- 速度:在相同的硬件上,SHA-1的運行速度比MD5慢。
- SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512這幾種單向散列算法。SHA-1,SHA-224和SHA-256適用於長度不超過264二進制位的消息。SHA-384和SHA-512適用於長度不超過2128二進制位的消息。
源碼解析
public static void main(String[] args) {
//字符串編碼
System.out.println("編碼結果:"+encrypt("hello word"));
}
public static String encrypt(String str){
try {
byte[] bytes=str.getBytes();
MessageDigest messageDigest=MessageDigest.getInstance("SHA");
messageDigest.update(bytes);
bytes = messageDigest.digest();
// digest()最後確定返回md5 hash值,返回值爲8位字符串。因爲md5 hash值是16位的hex值,實際上就是8位的字符
// BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
//一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方)
return new BigInteger(1, bytes).toString(16);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
log
編碼結果:e0738b87e67bbfc9c5b77556665064446430e81c
HMAC
- “散列消息鑑別碼”,主要是利用哈希算法,以一個密鑰和一個消息爲輸入,生成一個消息摘要作爲輸出。
- 驗證TPM接受的授權數據和認證數據;
- 確認TPM接受到的命令請求是已授權的請求,並且,命令在傳送的過程中沒有被改動過。
- 定義HMAC需要一個加密用散列函數(表示爲H,可以是MD5或者SHA-1)和一個密鑰K。我們用B來表示數據塊的字節數。(以上所提到的散列函數的分割數據塊字長B=64),用L來表示散列函數的輸出數據字節數(MD5中L=16,SHA-1中L=20)。鑑別密鑰的長度可以是小於等於數據塊字長的任何正整數值。應用程序中使用的密鑰長度若是比B大,則首先用使用散列函數H作用於它,然後用H輸出的L長度字符串作爲在HMAC中實際使用的密鑰。一般情況下,推薦的最小密鑰K長度是L個字節。
- 使用的密鑰是雙方事先約定的,第三方不可能知道。作爲非法截獲信息的第三方,能夠得到的信息只有作爲“挑戰”的隨機數和作爲“響應”的HMAC結果,無法根據這兩個數據推算出密鑰。由於不知道密鑰,所以無法仿造出一致的響應。
public static void main(String[] args) {
//字符串編碼
System.out.println("編碼結果:"+encrypt("hello word"));
}
public static String encrypt(String str){
try {
byte[] bytes=str.getBytes();
SecretKey secretKey=new SecretKeySpec(bytes,"HmacMD5");
Mac mac=Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
bytes=mac.doFinal(bytes);
// digest()最後確定返回md5 hash值,返回值爲8位字符串。因爲md5 hash值是16位的hex值,實際上就是8位的字符
// BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
//一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方)
return new BigInteger(1, bytes).toString(16);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
log
編碼結果:4b003eb6cb233122bb5a94ff468b95b7
源碼下載
詳情文章
- JAVA加密系列(一)- Base64與單向加密算法MD5、SHA、HMAC
- JAVA加密系列(二)- 對稱加密算法 DES、AES
- JAVA加密系列(三)- 非對稱加密算法 RSA、DSA
- JAVA加密系列(四)- 位運算加密
總結
單向加密應用非常廣泛,比較常用的用途是校驗數據或者文件在傳輸過程中是否修改,以上例子均展示的最簡單的實例,因爲都是基於byte數據進行操作,那麼完全可以使用base64以及位運算進行操作加大安全性,具體實現方式請查看後續文章