面試官:說一說你常用的加密演算法有哪些?
加密演算法通常被分為兩種:對稱加密和非對稱加密。其中,對稱加密演算法在加密和解密時使用的金鑰相同;非對稱加密演算法在加密和解密時使用的金鑰不同,分為公鑰和私鑰。此外,還有一類叫做訊息摘要演算法,是對資料進行摘要並且不可逆的演算法。
這次我們瞭解一下對稱加密演算法。
對稱加密演算法
對稱加密演算法在加密和解密時使用的金鑰相同,或是使用兩個可以簡單地相互推算的金鑰。在大多數的對稱加密演算法中,加密和解密的金鑰是相同的。
它要求雙方在安全通訊之前,商定一個金鑰。對稱演算法的安全性依賴於金鑰,洩漏金鑰就意味著任何人都可以對他們傳送的資訊進行解密,這也是對稱加密演算法的主要缺點之一。
常見的對稱加密演算法有:DES演算法、3DES演算法、AES演算法。
DES演算法
DES演算法(Data Encryption Standard)是一種常見的分組加密演算法。
面試官:什麼是分組加密演算法?
分組加密演算法是將明文分成固定長度的組,每一組都採用同一金鑰和演算法進行加密,輸出也是固定長度的密文。
由IBM公司在1972年研製,1976年被美國聯邦政府的國家標準局確定為聯邦資料處理標準(FIPS),隨後在國際上廣泛流傳開來。
在DES演算法中,金鑰固定長度為64位。明文按64位進行分組,分組後的明文組和金鑰按位置換或交換的方法形成密文組,然後再把密文組拼裝成密文。
金鑰的每個第八位設定為奇偶校驗位,也就是第8、16、24、32、40、48、56、64位,所以金鑰的實際參與加密的長度為56位。
我們用Java寫個例子:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
public class DesUtil {
private static final String DES = "DES";
private static final Charset CHARSET = StandardCharsets.UTF_8;
/**
* 加密
*
* @param input 明文
* @param key 金鑰
* @return 密文
* @throws GeneralSecurityException
*/
public static String encrypt(String input, String key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(DES);
SecretKey keySpec = new SecretKeySpec(key.getBytes(CHARSET), DES);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] data = cipher.doFinal(input.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(data);
}
/**
* 解密
*
* @param input 密文
* @param key 金鑰
* @return 明文
* @throws GeneralSecurityException
*/
public static String decrypt(String input, String key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(DES);
SecretKey keySpec = new SecretKeySpec(key.getBytes(CHARSET), DES);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] data = cipher.doFinal(Base64.getDecoder().decode(input));
return new String(data, CHARSET);
}
public static void main(String[] args) throws GeneralSecurityException {
String msg = "我喜歡你,可以做我女朋友嗎?";
String key = "One-More";
System.out.println("加密前:" + msg);
String pwd = DesUtil.encrypt(msg, key);
System.out.println("加密後:" + pwd);
System.out.println("解密後:" + DesUtil.decrypt(pwd, key));
}
}
執行結果如下:
加密前:我喜歡你,可以做我女朋友嗎?
加密後:i5LZ5aJMrlgN+Pr5IQm87Q14k0kmDLFIPnJmtrGA/xBHG0SivGrqCrc3vXjZoCBm
解密後:我喜歡你,可以做我女朋友嗎?
DES現在已經不是一種安全的加密方法,主要因為它使用的金鑰過短,很容易被暴力破解。
3DES演算法
3DES演算法(Triple Data Encryption Algorithm)是DES演算法的升級版本,相當於是對明文進行了三次DES加密。
由於計算機運算能力的增強,DES演算法由於金鑰長度過低容易被暴力破解;3DES演算法提供了一種相對簡單的方法,即通過增加DES的金鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼演算法。
在DES演算法中,金鑰固定長度為192位。在加密和解密時,金鑰會被分為3個64位的金鑰。
面試官:3DES演算法加密和解密的過程是什麼樣子的?
加密過程如下:
- 使用第一個金鑰加密明文。
- 使用第二個金鑰解密上一步的結果。
- 使用第三個金鑰加密上一步的結果。
解密過程如下:
- 使用第三個金鑰解密明文。
- 使用第二個金鑰加密上一步的結果。
- 使用第一個金鑰解密上一步的結果。
我們用Java寫個例子:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
public class TripleDesUtil {
private static final String DESede = "DESede";
private static final Charset CHARSET = StandardCharsets.UTF_8;
/**
* 加密
*
* @param input 明文
* @param key 金鑰
* @return 密文
* @throws GeneralSecurityException
*/
public static String encrypt(String input, String key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(DESede);
SecretKey keySpec = new SecretKeySpec(key.getBytes(CHARSET), DESede);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] data = cipher.doFinal(input.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(data);
}
/**
* 解密
*
* @param input 密文
* @param key 金鑰
* @return 明文
* @throws GeneralSecurityException
*/
public static String decrypt(String input, String key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(DESede);
SecretKey keySpec = new SecretKeySpec(key.getBytes(CHARSET), DESede);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] data = cipher.doFinal(Base64.getDecoder().decode(input));
return new String(data, CHARSET);
}
public static void main(String[] args) throws GeneralSecurityException {
String msg = "我喜歡你,可以做我女朋友嗎?";
String key = "One-More12345678One.More";
System.out.println("加密前:" + msg);
String pwd = TripleDesUtil.encrypt(msg, key);
System.out.println("加密後:" + pwd);
System.out.println("解密後:" + TripleDesUtil.decrypt(pwd, key));
}
}
執行結果如下:
加密前:我喜歡你,可以做我女朋友嗎?
加密後:q/ZWtjDGoxIjmd30he0oZ3XLjJhh/ACedaXaj12Zi3Wtlqz+ZzJmQuScjKuZoONF
解密後:我喜歡你,可以做我女朋友嗎?
雖然3DES演算法在安全性上有所提升,但是因為使用了3次DES演算法,加密和解密速度比較慢。
AES演算法
AES(Advanced Encryption Standard,高階加密標準)主要是為了取代DES加密演算法的,雖然出現了3DES的加密方法,但由於它的加密時間是DES演算法的3倍多,金鑰位數還是不能滿足對安全性的要求。
1997年1月2號,美國國家標準與技術研究院(NIST)宣佈希望徵集高階加密標準,用以取代DES。全世界很多密碼工作者都提交了自己設計的演算法。經過甄選流程,高階加密標準由美國國家標準與技術研究院於2001年11月26日釋出於FIPS PUB 197,並在2002年5月26日成為有效的標準。
該演算法為比利時密碼學家Joan Daemen和Vincent Rijmen所設計,結合兩位作者的名字,以Rijndael為名投稿高階加密標準的甄選流程。
面試官:AES演算法的金鑰長度是固定的嗎?
AES演算法的金鑰長度是固定,金鑰的長度可以使用128位、192位或256位。
AES演算法也是一種分組加密演算法,其分組長度只能是128位。分組後的明文組和金鑰使用幾種不同的方法來執行排列和置換運算形成密文組,然後再把密文組拼裝成密文。
我們用Java寫個例子:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
public class AesUtil {
private static final String AES = "AES";
private static final Charset CHARSET = StandardCharsets.UTF_8;
/**
* 加密
*
* @param input 明文
* @param key 金鑰
* @return 密文
* @throws GeneralSecurityException
*/
public static String encrypt(String input, String key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(AES);
SecretKey keySpec = new SecretKeySpec(key.getBytes(CHARSET), AES);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] data = cipher.doFinal(input.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(data);
}
/**
* 解密
*
* @param input 密文
* @param key 金鑰
* @return 明文
* @throws GeneralSecurityException
*/
public static String decrypt(String input, String key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(AES);
SecretKey keySpec = new SecretKeySpec(key.getBytes(CHARSET), AES);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] data = cipher.doFinal(Base64.getDecoder().decode(input));
return new String(data, CHARSET);
}
public static void main(String[] args) throws GeneralSecurityException {
String msg = "我喜歡你,可以做我女朋友嗎?";
String key = "One-More12345678One.More87654321";
System.out.println("加密前:" + msg);
String pwd = AesUtil.encrypt(msg, key);
System.out.println("加密後:" + pwd);
System.out.println("解密後:" + AesUtil.decrypt(pwd, key));
}
}
執行結果如下:
加密前:我喜歡你,可以做我女朋友嗎?
加密後:dT29xX+XpPTO3OMuDw1ASyU/+aNfJ1K+endNUJ84h2KZhqRDNfiO4hAQjOXMCoN4
解密後:我喜歡你,可以做我女朋友嗎?
AES演算法是目前應用最廣泛的對稱加密演算法。
總結
對稱加密演算法在加密和解密時使用的金鑰相同,常見的對稱加密演算法有:DES演算法、3DES演算法、AES演算法。
由於安全性低、加密解密效率低,DES演算法和3DES演算法是不推薦使用的,AES演算法是目前應用最廣泛的對稱加密演算法。
竟然已經看到這裡了,你我定是有緣人,留下你的點贊和關注,他日必成大器。
微信公眾號:萬貓學社
微信掃描二維碼
關注後回覆「電子書」
獲取12本Java必讀技術書籍