找回密码
 立即注册
首页 业界区 科技 SM4-CBC反转字节攻击(附代码)

SM4-CBC反转字节攻击(附代码)

骆熙华 昨天 09:21

CBC模式:Cipher Block Chaining mode,密文分组链接模式
CBC模式是先将明文分成若干个组块,然后每个明文分组与前一密文分组进行异或 XORXOR 运算,然后再进行加密。因此,每个密文分组都依赖于它前面的所有明文分组
由于密文分组像链条一样相互连接在一起,因此称为密文分组链接模式。
 
由于CBC模式分组块与块之间有相互连接关系,解密时前一块的密文会参与后一块密文的解密,所以我们更改前一块密文的值时,也会对后一块解密后的明文造成影响,而当我们知晓完整的密文和后一块密文对应的明文时,后一块密文解密出的明文就是可控制的,即我们可以通过控制A的值,进而控制C的值。这个攻击方式就是“CBC模式的反转字节攻击”,下面详细介绍原理。(至于为什么这么叫,我猜测是因为原理依赖异或运算吧)
1.png

在上图中,密文分组1为A,密文分组2进行解密运算后为B。明文分组2为C。
由CBC解密原理或图片信息可得:C=A^B。
由于异或两次同一个数等于啥也没干可由上式推出:B=A^C。
现在开始操作密文的值,使A'=A^C,用A'替换原来A的位置。
这个时候C=A'^B=(A^C)^(A^C)=0   C就被操作成了全0的值。
聪明的你肯定想到了,x^0=x。
所以我们再操作一次密文,A''=A^C^x,用A''替代上图中A的位置。
这个时候C=(A^C^x)^(A^C)=x
通过以上方法,我们就做到了在仅已知一对明文密文的情况下,通过修改密文得到一组成立的明密文对,且可以根据我们的喜好自定义明文的一部分。
 
博主博主,这种方式看起来很巧妙,但感觉没什么用呀,有什么具体的使用示例吗?
下面展示一个具体示例,假设我们通过抓包、监听等方式得到了一组明密文:
  1. 待加密内容: abcdefghijklm123456789111-staff
  2. sm4_cbc加密后的结果: a44668576540e3bbf1b95115481e373c5af8c5fdaf5f775b65da549c7ecb8483
复制代码
你可以观察到这里明文结尾为用户名,所以我们可以通过刚刚学到的字节反转攻击方式构造一段明密文,修改最后的用户名,达到伪装为任何用户的目的。
Talk is cheap,上代码,这里通过修改密文,我们伪装了用户名为draina的一段明密文
  1. # -*-coding: utf-8-*-
  2. from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
  3. import binascii
  4. import base64
  5. class SM4_cbc:
  6.     def __init__(self):
  7.         self.crypt_sm4 = CryptSM4()
  8.     def str_to_strBin(self, hex_str):
  9.         hex_data = hex_str.encode('utf-8')
  10.         str_bin = binascii.unhexlify(hex_data)
  11.         return str_bin.decode('utf-8')
  12.     def encrypt_cbc(self, cbc_key, iv, value):
  13.         crypt_cbc = self.crypt_sm4
  14.         crypt_cbc.set_key(binascii.a2b_hex(cbc_key), SM4_ENCRYPT)
  15.         Enc_value = crypt_cbc.crypt_cbc(binascii.a2b_hex(iv), value.encode())
  16.         return binascii.b2a_hex(Enc_value)
  17.     def decrypt_cbc(self, cbc_key, iv, value):
  18.         crypt_cbc = self.crypt_sm4
  19.         crypt_cbc.set_key(binascii.a2b_hex(cbc_key), SM4_DECRYPT)
  20.         Dec_value = crypt_cbc.crypt_cbc(binascii.a2b_hex(iv), value)
  21.         return Dec_value
  22. def hex_to_base64(payload_hex2):
  23.     bytes_out = bytes.fromhex(payload_hex2)
  24.     str_out = base64.b64encode(bytes_out)
  25.     # print("hex_to_base64:", str_out)
  26.     return str_out
  27. def pkcs7_pad(data: bytes, block_size: int = 16) -> bytes:
  28.     """对数据进行 PKCS7 填充"""
  29.     padding_length = block_size - (len(data) % block_size)
  30.     padding = bytes([padding_length] * padding_length)
  31.     return data + padding
  32. def utf8_to_hex_with_padding(plain_text: str) -> str:
  33.     """将 UTF-8 明文转换为十六进制字符串,并进行 PKCS7 填充"""
  34.     utf8_bytes = plain_text.encode('utf-8')
  35.     padded_bytes = pkcs7_pad(utf8_bytes)
  36.     hex_string = padded_bytes.hex()
  37.     return hex_string
  38. def xor_hex_strings(hex1, hex2):
  39.     # 将16进制字符串转换为整数
  40.     int1 = int(hex1, 16)
  41.     int2 = int(hex2, 16)
  42.     # 进行按位异或操作
  43.     xor_result = int1 ^ int2
  44.     # 将结果转换回16进制字符串,并去掉前缀 '0x'
  45.     return hex(xor_result)[2:]
  46. if __name__ == '__main__':
  47.     key = "b01b1e51ba8b9bfcd584ab5b73ab7670"
  48.     str_data = "abcdefghijklm123456789111-staff"
  49.     iv_str = "e5709dcac5e3016de93aaf7b364693c3"
  50.     SM4 = SM4_cbc()
  51.     print("待加密内容:", str_data)
  52.     print("p=",utf8_to_hex_with_padding(str_data))
  53.     cipher = SM4.encrypt_cbc(key, iv_str, str_data)
  54.     cipher_hex = cipher.decode()
  55.     print("sm4_cbc加密后的结果:", cipher_hex, type(cipher_hex))
  56.     val = hex_to_base64(cipher_hex)
  57.     decode_cbc = SM4.decrypt_cbc(key, iv_str, base64.b64decode(val))
  58.     print("sm4_cbc解密结果是:", decode_cbc.decode(), "\n")
  59.     print("下面是字节反转攻击,将staff改为draina")
  60.     p22=utf8_to_hex_with_padding('abcdefghijklm12888888888-draina')[-32:]
  61.     #新明文第二分组,将p2的尾部改为draina后转为HEX并填充
  62.     temp=xor_hex_strings(cipher_hex[:32],utf8_to_hex_with_padding(str_data)[-32:])
  63.     cipherx1= xor_hex_strings(p22,temp)
  64.     #计算新密文的第一个分组,即原明文的第二个分组异或原密文的第一个分组 再异或需要得到的新明文的第二个分组
  65.     cipherx12=cipherx1+cipher_hex[-32:]
  66.     print('新的密文为',cipherx12)
  67.     val2 = hex_to_base64(cipherx12)
  68.     decode_cbc2 = SM4.decrypt_cbc(key, iv_str, base64.b64decode(val2))
  69.     print("sm4_cbc解密结果是:",decode_cbc2, "\n")
复制代码
 
2.png

 
-END-
参考链接
http://f0und.icu/article/28.html
https://blog.csdn.net/weixin_42437696/article/details/133786366


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册