幾種常見的加密演算法及 Java 實現
介紹
本文主要對加密演算法做個概況性的介紹,然後給出幾種簡單的加密演算法 Java 實現。
1. 演算法種類
- 單向加密
- 對稱加密
- 非對稱加密
1.1 單向加密
即加密之後不能解密,一般用於資料驗證
1) Base64
Base64 編碼是從二進位制到字元的過程,用 64 個字元來表示任意的二進位制資料,常用於在 HTTP 加密,圖片編碼傳輸等。
可列印字元:在ASCII碼中規定,0~31、128 這33個字元屬於控制字元,32~127這95個字元屬於可列印字元
轉換方式:在 HTTP 協議下傳輸二進位制資料時需要將其轉換為字元資料,而網路傳輸只能傳輸可列印字元(95 個),不能轉換的就需要使用 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 的用字元 “=” 代替
2) MD5
Message Digest algorithm 5,資訊摘要演算法,MD5
- 一般用於確保資訊的傳輸完整一致性,校驗傳輸的資料是否被修改,一旦原始資訊被修改,生成的 MD5 值將會變得很不同
- 演算法能將任意大小、格式的文字或檔案進行加密從而產生 128 bit(16 位元組)的雜湊值。如同人的指紋,不同文字的 MD5 值是不同的。
- 極端情況:就是不同的字串的 MD5 值一樣,這叫雜湊碰撞。2009 年中科院就已經實現了相應的碰撞演算法,不過 MD5 應用仍然很廣泛
- 一般不可破解,除非使用窮舉法,難度依舊很大
3) SHA 家族
- 是一個密碼雜湊函式家族,是 FIPS 所認證的安全雜湊演算法
- 和 MD5 類似,都是對文字進行雜湊,產生一定長度的雜湊值
4) HMAC
Hash Message Authentication Code,雜湊訊息鑑別碼
- 是一種通過特別計算方式之後產生的訊息認證碼(MAC),使用密碼雜湊函式,同時結合一個加密金鑰。它可以用來保證資料的完整性,同時可以用來作某個訊息的身份驗證。
1.2 對稱加密
對稱加密的意思就是資訊收發都有相同的一把鑰匙,訊息的加密解密都用這進行
1)DES
- Data Encryption Standard,資料加密標準,速度較快,適用於加密大量資料的場合。
2)AES
- Advanced Encryption Standard,高階加密標準,是下一代的加密演算法標準,速度快,安全級別高;
1.3 非對稱加密
非對稱加密演算法是一種金鑰的保密方法。 非對稱加密演算法需要兩個金鑰:公開金鑰(publickey)和私有金鑰(privatekey)。 公開金鑰與私有金鑰是一對,如果用公開金鑰對資料進行加密,只有用對應的私有金鑰才能解密;如果用私有金鑰對資料進行加密,那麼只有用對應的公開金鑰才能解密。
1)RSA
- 名稱來源於發明這個演算法的三個人的姓氏組成,演算法大致內容就是對極大整數進行因式分解
- 這種演算法非常可靠,金鑰越長,它就越難破解。根據已經披露的文獻,目前被破解的最長 RSA金鑰是768個二進位制位。也就是說,長度超過768位的金鑰,還無法破解(至少沒人公開宣佈)。因此可以認為,1024位的RSA金鑰基本安全,2048位的金鑰極其安全。
2)DSA
Digital Signature Algorithm,數字簽名演算法,是一種標準的 DSS(數字簽名標準);
3)ECC
- Elliptic Curves Cryptography,橢圓曲線密碼編碼學。
- 一種建立公開金鑰加密的演算法,基於橢圓曲線數學。
- ECC的主要優勢是在某些情況下它比其他的方法使用更小的金鑰——比如RSA加密演算法——提供相當的或更高等級的安全。ECC的另一個優勢是可以定義群之間的雙線性對映,基於Weil對或是Tate對;雙線性對映已經在密碼學中發現了大量的應用,例如基於身份的加密。不過一個缺點是加密和解密操作的實現比其他機制花費的時間長。
2. 演算法實現(java)
Base64
public static void main(String[] args) {
try {
// 編碼
String encode = Base64.getEncoder().encodeToString("son".getBytes("UTF-8"));
System.out.println(encode); // c29u
// 解碼
byte[] decode = Base64.getDecoder().decode("c29u");
System.out.println(new String(decode, "UTF-8")); // 周杰倫
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
MD5 和 SHA 家族
public static void main(String[] args) {
String content = "you are my son"; // 原文
try {
byte[] a;
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
a = messageDigest.digest(content.getBytes());
System.out.println(byte2hex(a)); // 333a9634d8809b5a9e8d280d82553b8fd8d4a911
messageDigest = MessageDigest.getInstance("SHA-256");
a = messageDigest.digest(content.getBytes());
System.out.println(byte2hex(a)); // cdb2c97079d9a1943eea98de4201f5c4f49ecda5af2b364e1c7a5d1ae89688eb
messageDigest = MessageDigest.getInstance("MD5");
a = messageDigest.digest(content.getBytes());
System.out.println(byte2hex(a)); // 6fe6b9a8f8bd29f4f4f1368a0619a7ae
// 第三方 MD5 演算法。需要新增 jar 包 org.apache.commons.codec.digest.DigestUtils
String encodeStr=DigestUtils.md5Hex(content);
System.out.println(encodeStr); // 6fe6b9a8f8bd29f4f4f1368a0619a7ae
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static String byte2hex(byte[] b) //二進位制轉字串
{
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
}
return hs;
}
總結
現在的加密演算法大部分情況下是為了驗證資料的一致性,例如傳遞一些引數組的時候,簡單的會使用 BASE64 或 MD5 進行加密生成一個簽名。複雜點就是 BASE64 編碼之後再用 對稱金鑰再加密一次,達到比較不容易被人篡改的目的
對於一些支付場景,一般使用 非對稱加密演算法 實現,這樣的場景需要的安全性更高。