一文搞懂對(duì)稱加密:加密算法、工作模式、填充方式、代碼實(shí)現(xiàn)

微信搜索:碼農(nóng)StayUp
主頁(yè)地址:https://gozhuyinglong.github.io
源碼分享:https://github.com/gozhuyinglong/blog-demos

上篇介紹了《單向散列加密》,它是一種消息摘要算法。該算法在信息安全領(lǐng)域,有很多重要的應(yīng)用場(chǎng)景,比如:用戶密碼保護(hù)、數(shù)字簽名、文件完整性校驗(yàn)、云盤妙傳等。

單向散列加密只能夠?qū)ο⑦M(jìn)行加密(嚴(yán)格來(lái)說(shuō)是計(jì)算消息的摘要),想要實(shí)現(xiàn)對(duì)密文解密,需要使用其它加密方式了。今天介紹一個(gè)在信息安全領(lǐng)域中,比較重要的加密方式——對(duì)稱加密。

下面是本篇講述內(nèi)容:


目錄

加密、解密和密鑰

加密(Encrypt)是從明文生成密文的步驟,解密(Decrypt)是從密文還原成明文的步驟,而這兩個(gè)步驟都需要用到密鑰(Key)。這和我們現(xiàn)實(shí)中,用鑰匙上鎖和開(kāi)鎖是一樣的。

加密、解密和密鑰

什么是對(duì)稱加密

對(duì)稱加密(Symmetric Cryptography)是密碼學(xué)中的一類加密算法,這類算法在加密和解密時(shí),使用相同的密鑰。

對(duì)稱加密又稱為共享密鑰加密,其最大的缺點(diǎn)是,對(duì)稱加密的安全性依賴于密鑰,一旦泄露,就意味著任何人都能解密消息。

對(duì)稱加密的優(yōu)點(diǎn)是加密速度快,所以在很多場(chǎng)合被使用。

常見(jiàn)算法

本節(jié)介紹對(duì)稱加密的一些常見(jiàn)算法,包括DES、3DES和AES。

DES算法

DES(Data Encryption Standard,中文:數(shù)據(jù)加密標(biāo)準(zhǔn)),是一種對(duì)稱加密算法。該算法在1976年被美國(guó)聯(lián)邦政府的國(guó)家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS),并于1977年被發(fā)布,隨后在國(guó)際上廣泛流傳開(kāi)來(lái)。然而,隨著計(jì)算機(jī)的進(jìn)步,DES 已經(jīng)能夠被暴力破解,所以該算法已經(jīng)不安全了。

DES是一種分組密碼(Block Cipher,或者叫塊加密),即將明文按64比特進(jìn)行分組加密,每組生成64位比特的密文。它的密鑰長(zhǎng)度為56比特(從規(guī)格上來(lái)說(shuō),密鑰長(zhǎng)度是64比特,但由于每隔7比特會(huì)設(shè)置一個(gè)用于錯(cuò)誤檢查的比特,因此實(shí)際長(zhǎng)度為56比特)。

DES算法

3DES算法

三重?cái)?shù)據(jù)加密算法(Triple Data Encryption Algorithm,縮寫為TDEA),簡(jiǎn)稱3DES(Triple-DES),是DES的增強(qiáng)版,相當(dāng)于對(duì)每組數(shù)據(jù)應(yīng)用了三次DES算法。

由于DES算法的密鑰長(zhǎng)度過(guò)短,容易被暴力破解,為了解決這一問(wèn)題,設(shè)計(jì)出了該算法。它使用簡(jiǎn)單的方法,通過(guò)增加DES密鑰長(zhǎng)度的方式來(lái)避免類似攻擊,而不是一種全新的密碼算法。

該算法在每次應(yīng)用DES時(shí),使用不同的密鑰,所以有三把獨(dú)立密鑰。這三把密鑰組成一起,是一個(gè)長(zhǎng)度為168(56 + 56 + 56)比特的密鑰,所以3DES算法的密鑰總長(zhǎng)度為168比特。

3DES的加密過(guò)程,并不是進(jìn)行三次DES加密(加密→加密→加密),而是以密鑰1、密鑰2、密鑰3的順序,進(jìn)行加密解密加密的過(guò)程。

3DES加密

3DES的解密過(guò)程和加密正好相反,是以密鑰3、密鑰2、密鑰1的順序,進(jìn)行解密加密解密的操作。

3DES解密

AES算法

AES(Advanced Encryption Standard),即高級(jí)加密標(biāo)準(zhǔn),是取代DES算法的一種新的對(duì)稱加密算法。AES算法是從全世界的企業(yè)和密碼學(xué)家,提交的對(duì)稱密碼算法中競(jìng)選出來(lái)的,最終 Rijndael 加密算法勝出,所以AES又稱為 Rijndael 加密算法。

AES也是一種分組密碼,它的分組長(zhǎng)度為128比特,密鑰長(zhǎng)度可以為128比特、192比特或256比特。

AES算法

分組密碼的模式

上面介紹的DES、3DES和AES都屬于分組密碼,它們只能加密固定長(zhǎng)度的明文。如果需要加密更長(zhǎng)的明文,就需要對(duì)分組密碼進(jìn)行迭代,而分組密碼的迭代方法稱為分組密碼的模式(Model)。簡(jiǎn)而一句話:分組密碼的模式,就是分組密碼的迭代方式。

分組密碼有很多種模式,這里主要介紹以下幾種:ECB、CBC、CFB、OFB、CTR。

明文分組與密文分組

在下面對(duì)模式的介紹時(shí),會(huì)用到兩個(gè)術(shù)語(yǔ),這里先介紹一下:

在分組密碼中,我們稱每組的明文為明文分組,每組生成的密文稱為密文分組

若將所有的明文分組合并起來(lái)就是完整的明文(先忽略填充),將所以的密文分組合并起來(lái)就是完整的密文。

ECB模式

ECB(Electronic CodeBook)模式,即電子密碼本模式。該模式是將明文分組,加密后直接成為密文分組,分組之間沒(méi)有關(guān)系。

ECB模式

ECB模式是所有模式中最簡(jiǎn)單的一種,該模式的明文分組與密文分組是一一對(duì)應(yīng)的關(guān)系,若明文分組相同,其密文分組也一定相同。因此,ECB模式也是最不安全的模式。

CBC模式

CBC(Cipher Block Chaining)模式,即密碼分組鏈接模式。該模式首先將明文分組與前一個(gè)密文分組進(jìn)行XOR運(yùn)算,然后再進(jìn)行加密。只有第一個(gè)明文分組特殊,需要提前為其生成一個(gè)與分組長(zhǎng)度相同的比特序列,進(jìn)行XOR運(yùn)算,這個(gè)比特序列稱為初始化向量(Initialization Vector),簡(jiǎn)稱IV。

CBC模式

CFB模式

CFB(Cipher FeedBack)模式,即密文反饋模式。該模式首先將前一個(gè)密文分組進(jìn)行加密,再與當(dāng)前明文分組進(jìn)行XOR運(yùn)算,來(lái)生成密文分組。同樣CFB模式也需要一個(gè)IV。

CFB模式

OFB模式

OFB(Output FeedBack)模式,即輸出反饋模式。該模式會(huì)產(chǎn)生一個(gè)密鑰流,即將密碼算法的前一個(gè)輸出值,做為當(dāng)前密碼算法的輸入值。該輸入值再與明文分組進(jìn)行XOR運(yùn)行,計(jì)算得出密文分組。該模式需要一個(gè)IV,進(jìn)行加密后做為第一個(gè)分組的輸入。

OFB模式

CTR模式

CTR(CounTeR)模式,即計(jì)數(shù)器模式。該模式也會(huì)產(chǎn)生一個(gè)密鑰流,它通過(guò)遞增一個(gè)計(jì)數(shù)器來(lái)產(chǎn)生連續(xù)的密鑰流。對(duì)該計(jì)數(shù)器進(jìn)行加密,再與明文分組進(jìn)行XOR運(yùn)算,計(jì)算得出密文分組。

CTR模式

分組密碼的填充

在分組密碼中,當(dāng)數(shù)據(jù)長(zhǎng)度不符合分組長(zhǎng)度時(shí),需要按一定的方式,將尾部明文分組進(jìn)行填充,這種將尾部分組數(shù)據(jù)填滿的方法稱為填充(Padding)。

No Padding

即不填充,要求明文的長(zhǎng)度,必須是加密算法分組長(zhǎng)度的整數(shù)倍。

... | DD DD DD DD DD DD DD DD | DD DD DD DD DD DD DD DD |

ANSI X9.23

在填充字節(jié)序列中,最后一個(gè)字節(jié)填充為需要填充的字節(jié)長(zhǎng)度,其余字節(jié)填充0。

... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 04 |

ISO 10126

在填充字節(jié)序列中,最后一個(gè)字節(jié)填充為需要填充的字節(jié)長(zhǎng)度,其余字節(jié)填充隨機(jī)數(shù)。

... | DD DD DD DD DD DD DD DD | DD DD DD DD 81 A6 23 04 |

PKCS#5和PKCS#7

在填充字節(jié)序列中,每個(gè)字節(jié)填充為需要填充的字節(jié)長(zhǎng)度。

... | DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |

ISO/IEC 7816-4

在填充字節(jié)序列中,第一個(gè)字節(jié)填充固定值80,其余字節(jié)填充0。若只需填充一個(gè)字節(jié),則直接填充80。

... | DD DD DD DD DD DD DD DD | DD DD DD DD 80 00 00 00 |

... | DD DD DD DD DD DD DD DD | DD DD DD DD DD DD DD 80 |

Zero Padding

在填充字節(jié)序列中,每個(gè)字節(jié)填充為0。

... | DD DD DD DD DD DD DD DD | DD DD DD DD 00 00 00 00 |

Java代碼實(shí)現(xiàn)

Java在底層已經(jīng)封裝好了對(duì)稱加密的實(shí)現(xiàn), 我們只需要使用即可。現(xiàn)在介紹幾個(gè)重要的類:

SecureRandom類

SecureRandom類是一個(gè)強(qiáng)安全的隨機(jī)數(shù)生成器(Random Number Generator,簡(jiǎn)稱:RNG),加密相關(guān)的推薦使用此隨機(jī)數(shù)生成器。

我們可以通過(guò)構(gòu)造方法生成一個(gè)實(shí)例,或者向構(gòu)造方法傳遞一個(gè)種子來(lái)創(chuàng)建實(shí)例。

SecureRandom random = new SecureRandom();

KeyGenerator類

KeyGenerator類是對(duì)稱密碼的密鑰生成器,需要指定加密算法,來(lái)生成相應(yīng)的密鑰。

Java中支持的算法:

  • AES (128)
  • DES (56)
  • DESede (168)
  • HmacSHA1
  • HmacSHA256

下面是一些標(biāo)準(zhǔn)算法的介紹:

標(biāo)準(zhǔn)算法

生成密鑰代碼如下:

/**
 * 通過(guò)密碼和算法獲取 Key 對(duì)象
 *
 * @param key       密鑰
 * @param algorithm 算法,例如:AES (128)、DES (56)、DESede (168)、HmacSHA1、HmacSHA256
 * @return 密鑰 Key
 * @throws Exception
 */
private static Key getKey(byte[] key, String algorithm) throws Exception {
    // 通過(guò)算法獲取 KeyGenerator 對(duì)象
    KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
    // 使用密鑰做為隨機(jī)數(shù),初始化 KeyGenerator 對(duì)象
    keyGenerator.init(new SecureRandom(key));
    // 生成 Key
    return keyGenerator.generateKey();
}

Cipher類

Cipher類提供了加密和解密的功能。該類需要指定一個(gè)轉(zhuǎn)換(Transformation)來(lái)創(chuàng)建一個(gè)實(shí)例,轉(zhuǎn)換的命名方式:算法名稱/工作模式/填充方式。

下面是Java支持的轉(zhuǎn)換:

  • AES/CBC/NoPadding (128)
  • AES/CBC/PKCS5Padding (128)
  • AES/ECB/NoPadding (128)
  • AES/ECB/PKCS5Padding (128)
  • DES/CBC/NoPadding (56)
  • DES/CBC/PKCS5Padding (56)
  • DES/ECB/NoPadding (56)
  • DES/ECB/PKCS5Padding (56)
  • DESede/CBC/NoPadding (168)
  • DESede/CBC/PKCS5Padding (168)
  • DESede/ECB/NoPadding (168)
  • DESede/ECB/PKCS5Padding (168)
  • RSA/ECB/PKCS1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
  • RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)

下面是一些標(biāo)準(zhǔn)的模式:

標(biāo)準(zhǔn)模式

下面是一些標(biāo)準(zhǔn)的填充:

標(biāo)準(zhǔn)填充

加密代碼如下:

private static final String DES_ALGORITHM = "DES";
private static final String DES_TRANSFORMATION = "DES/ECB/PKCS5Padding";

/**
 * DES 加密
 *
 * @param data 原始數(shù)據(jù)
 * @param key  密鑰
 * @return 密文
 */
private static byte[] encryptDES(byte[] data, byte[] key) throws Exception {
    // 獲取 DES Key
    Key secretKey = getKey(key, DES_ALGORITHM);

    // 通過(guò)標(biāo)準(zhǔn)轉(zhuǎn)換獲取 Cipher 對(duì)象, 由該對(duì)象完成實(shí)際的加密操作
    Cipher cipher = Cipher.getInstance(DES_TRANSFORMATION);
    // 通過(guò)加密模式、密鑰,初始化 Cipher 對(duì)象
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    // 生成密文
    return cipher.doFinal(data);
}

解密代碼如下:

private static final String DES_ALGORITHM = "DES";
private static final String DES_TRANSFORMATION = "DES/ECB/PKCS5Padding";

/**
 * DES 解密
 *
 * @param data 密文
 * @param key  密鑰
 * @return 原始數(shù)據(jù)
 */
private static byte[] decryptDES(byte[] data, byte[] key) throws Exception {
    // 獲取 DES Key
    Key secretKey = getKey(key, DES_ALGORITHM);
    // 通過(guò)標(biāo)準(zhǔn)轉(zhuǎn)換獲取 Cipher 對(duì)象, 由該對(duì)象完成實(shí)際的加密操作
    Cipher cipher = Cipher.getInstance(DES_TRANSFORMATION);
    // 通過(guò)解密模式、密鑰,初始化 Cipher 對(duì)象
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    // 生成原始數(shù)據(jù)
    return cipher.doFinal(data);
}

完整代碼

完整代碼請(qǐng)?jiān)L問(wèn)我的Github,若對(duì)你有幫助,歡迎給個(gè)?,感謝~~??????

https://github.com/gozhuyinglong/blog-demos/blob/main/java-source-analysis/src/main/java/io/github/gozhuyinglong/utils/SymmetricKeyUtil.java

推薦閱讀

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容