AES 對(duì)稱密碼和分組工作模式

先看一個(gè)在 Node.js 中使用 AES 對(duì)文件內(nèi)容進(jìn)行加密的例子:

const fs = require('fs')
const { createCipheriv, randomBytes } = require('crypto')

const key = randomBytes(32)
const iv = randomBytes(16)
const cipher = createCipheriv('aes-256-cbc', key, iv)

// 加密文件
fs.createReadStream('plain.txt')
.pipe(cipher)
.pipe(fs.createWriteStream('aes-256-cbc.dat'))

// 輸出 key,iv
fs.writeFileSync('aes-256-cbc.key', key.toString('hex') + '|' + iv.toString('hex'))

輸出的 key 和 iv 分別為:

435157a4775085cef2aa2d44dd399eeea4a3cc304f85c0ef895770943e5ec4fc
294926351aad0cc4e8ce88c8356575b5

對(duì)加密后的文件進(jìn)行解密:

const fs = require('fs')
const { createDecipheriv } = require('crypto')

const [key, iv] = fs.readFileSync('aes-256-cbc.key', {encoding: 'utf8'}).split('|')
const decipher = createDecipheriv('aes-256-cbc', Buffer.from(key, 'hex'), Buffer.from(iv, 'hex'))

fs.createReadStream('aes-256-cbc.dat')
.pipe(decipher)
.pipe(fs.createWriteStream('aes-256-cbc.txt'))

如果你感興趣,可以把代碼復(fù)制出來跑一下看看。

接下來我并不想繼續(xù)介紹 Node.js 中的加密、解密 API 如何,這些在 Node.js 官方文檔中都有:

Crypto - Node.js v12.13.0 Documentation

在上面的例子,使用了算法 aes-256-cbc 進(jìn)行加解密。AES 是一種對(duì)稱密碼算法,而后面的 256cbc 是指什么?iv 又是什么呢?

如果你對(duì)這感興趣,那么本文正適合你。

AES 對(duì)稱密碼

AES 全稱為“Advanced Encryption Standard”,是美國(guó)政府于 2001 年通過公開競(jìng)標(biāo)征集的對(duì)稱密碼算法,用于替代已經(jīng)老舊的 DES 算法。

AES 有三種密鑰長(zhǎng)度:128,192 和 256 比特。上面例子中的 256 就表示密鑰長(zhǎng)度為 256 比特。

由于 AES 算法是公開的,所以決定加密數(shù)據(jù)的機(jī)密性的關(guān)鍵是 密鑰。密鑰越長(zhǎng),則可供選擇的組合數(shù)目越多,也就是密鑰空間越大,對(duì)于暴力破解來說難度也就越高。

AES 每次加密的數(shù)據(jù)塊大小是確定的 128 比特,如果數(shù)據(jù)超過這個(gè)大小,就需要進(jìn)行拆分,分別進(jìn)行加密后再組裝,解密的過程則相反。

看起來對(duì)數(shù)據(jù)進(jìn)行分組加密再組合是很簡(jiǎn)單的事情,最多額外約定下如果分組數(shù)據(jù)不夠 128 比特如何填補(bǔ)就好了。

分組工作模式

ECB 模式

前面提到的思路,就是 ECB(Electronic CodeBook)模式的實(shí)現(xiàn)方式:

EBC 模式加密過程

解密過程相反:分解 - 解密 - 合并。

但是這種模式是不夠安全的,我們考慮數(shù)據(jù)的發(fā)送方(Alice)和接收方(Bob)之間有一個(gè)攻擊者(Mallory)的情況。

由于對(duì)稱密碼的存在,Mallory 并不能解密數(shù)據(jù)。但是 ECB 模式下,數(shù)據(jù)只是簡(jiǎn)單分組加密再組裝,Mallory 如果改變密文分組的順序,Bob 解密得到的明文也就被改變了。

如果 Mallory 知曉通信報(bào)文的格式,就可以通過調(diào)整密文分組的順序達(dá)到特殊的目的。例如 Alice 發(fā)送轉(zhuǎn)賬數(shù)據(jù)給 Bob,Mallory 從中對(duì)調(diào)了付款人和收款人信息對(duì)應(yīng)的分組,就會(huì)導(dǎo)致 Bob 接收到錯(cuò)誤數(shù)據(jù)。

能夠在不破譯密文的情況下操縱明文,這是 ECB 模式的一大弱點(diǎn)。

接下來,我們看下 CBC 模式是怎么應(yīng)對(duì)這種攻擊的。

CBC 模式

CBC 全稱 Cipher Block Chaining,也就是密文分組鏈接模式:

CBC 模式加密過程

上一個(gè)分組加密結(jié)果先與下一個(gè)分組明文執(zhí)行 XOR(異或)運(yùn)算,然后再加密。由于第一個(gè)明文分組沒有上一個(gè)密文分組可以使用,所以需要事先傳人一個(gè)數(shù)據(jù),也就是 IV(初始化向量),其長(zhǎng)度與分組的大小相同。對(duì)于 AES 密碼算法,其分組大小為 128 bit,所以使用的 IV 也就是 128 比特。

采用 CBC 模式,密文中如果有一個(gè)分組缺失,后續(xù)所有分組都無法正確解密;如果一個(gè)分組數(shù)據(jù)被篡改或損壞,由于鏈接關(guān)系的存在,會(huì)影響下一個(gè)分組的解密(因?yàn)榻饷苄枰褂蒙弦环纸M的密文進(jìn)行 XOR 運(yùn)算)。

如果 Mallory 對(duì)分組順序進(jìn)行了調(diào)換,由于相鄰分組鏈接的關(guān)系,會(huì)導(dǎo)致無法正常解密。

當(dāng)然,確保數(shù)據(jù)在傳輸過程中不被篡改(完整性),使用消息認(rèn)真碼(MAC,Message Authentication Code)是更好的方案。

根據(jù)前一分組信息介入的時(shí)機(jī)和方式的不同,還有其他幾種和 CBC 模式類似的模式。

CFB 模式

CFB,Cipher FeedBack,密文反饋模式:

CFB 模式加密過程

看起來有點(diǎn)奇怪,第一個(gè)分組中,應(yīng)用 AES 進(jìn)行加密的其實(shí) IV,IV 的密文再和明文進(jìn)行 XOR 運(yùn)算得到分組最終密文。其實(shí) XOR 也是一種加密運(yùn)算,而 IV 的密文則可以看作是生成的 一次性密碼本。

OFB 模式

OFB,Output-FeedBack,輸出反饋模式:

OFB 模式加密過程

和 CFB 模式非常類似,只是提供下一組的密鑰是密碼算法的輸出,而非最終的密文。

OFB 的優(yōu)勢(shì)是可以拋開明文,事先計(jì)算好每個(gè)分組需要的密鑰,所以生成密鑰流和對(duì)明文進(jìn)行 XOR 運(yùn)算是可以并行的。

CTR 模式

CTR,CounTer,計(jì)數(shù)器模式:

CTR 模式加密過程

CTR 模式和 CBC 模式差別就更大了,CTR 模式是通過對(duì)逐次累加的計(jì)數(shù)器進(jìn)行加密來生成密鑰流的 流密碼。

CTR 和 OFB 有點(diǎn)類似,真正對(duì)明文加密的過程,是基于密鑰流進(jìn)行 XOR 運(yùn)算。而 CTR 模式更進(jìn)一步,由于是采用計(jì)數(shù)器的模式,任意分組的密鑰是可以提前計(jì)算的,不依賴前一分組,所以在支持并行計(jì)算的系統(tǒng)中,CTR 模式的速度會(huì)非??臁?/p>

小結(jié)

這里介紹的分組密碼模式有很多,一般而言,ECB 模式是不應(yīng)該使用的,而通常使用的是 CBC 模式和 CTR 模式。

認(rèn)證加密模式

如果在加密過程中,同時(shí)還生成了有關(guān)數(shù)據(jù)的認(rèn)證信息,則既可以確保數(shù)據(jù)的機(jī)密性,又能確保完整性。

認(rèn)證加密的方法有:

  • Encrypt-then-MAC (EtM):明文加密,密文生成 MAC
  • Encrypt-and-MAC (E&M):明文加密,明文生成 MAC
  • MAC-then-Encrypt (MtE):明文生成 MAC,明文和MAC一起加密

Node.js 文檔中給出的一個(gè)使用 aes-192-ccm 的例子,CCM 模式就是一個(gè)滿足認(rèn)證加密要求的算法:

crypto_ccm_mode - crypto

總結(jié)

回過頭,再看下本文開頭的算法 aes-256-cbc,我們知道:

  • AES:對(duì)稱密碼算法
  • 256:選擇的 AES 密鑰長(zhǎng)度
  • CBC:分組密碼模式

在使用該算法進(jìn)行加密時(shí),需要傳入兩個(gè)參數(shù):

  • key:AES 的密鑰,256 比特
  • iv:CBC 模式需要的初始化向量,與分組大小一致,AES 分組為固定的 128 比特

另外,密鑰 key 是重要的機(jī)密,要妥善保存,通信雙方如果需要傳輸該密鑰,需要額外通過其他機(jī)制(密鑰交換/協(xié)商機(jī)制)。而初始化向量 iv 則無需秘密保存,但要避免在反復(fù)使用相同的數(shù)據(jù),盡量每次創(chuàng)建隨機(jī)數(shù)據(jù)。

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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