快速了解常用的對稱加密演算法,再也不用擔心面試官的刨根問底

面試官:說一說你常用的加密演算法有哪些?

加密演算法通常被分為兩種:對稱加密和非對稱加密。其中,對稱加密演算法在加密和解密時使用的密鑰相同;非對稱加密演算法在加密和解密時使用的密鑰不同,分為公鑰和私鑰。此外,還有一類叫做消息摘要演算法,是對數據進行摘要並且不可逆的演算法。

這次我們了解一下對稱加密演算法。

對稱加密演算法

對稱加密演算法在加密和解密時使用的密鑰相同,或是使用兩個可以簡單地相互推算的密鑰。在大多數的對稱加密演算法中,加密和解密的密鑰是相同的。

它要求雙方在安全通訊之前,商定一個密鑰。對稱演算法的安全性依賴於密鑰,泄漏密鑰就意味著任何人都可以對他們發送的資訊進行解密,這也是對稱加密演算法的主要缺點之一。

常見的對稱加密演算法有: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演算法加密和解密的過程是什麼樣子的?

加密過程如下:

  1. 使用第一個密鑰加密明文。
  2. 使用第二個密鑰解密上一步的結果。
  3. 使用第三個密鑰加密上一步的結果。

解密過程如下:

  1. 使用第三個密鑰解密明文。
  2. 使用第二個密鑰加密上一步的結果。
  3. 使用第一個密鑰解密上一步的結果。

我們用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必讀技術書籍

Tags: