如何将AES模式从一个迁移到另一个?

2024-05-26 04:24:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个函数:由AES实现的加密/解密

from cryptography.hazmat.backends import default_backend                                                      
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

DEFAULT_MODE = modes.ECB()

def encrypt(data, key):
    encryptor = Cipher(algorithms.AES(key), DEFAULT_MODE, backend=default_backend()).encryptor()
    return encryptor.update(data) + encryptor.finalize()    

def decrypt(data, key):
    if len(data) == 0 or len(data)%16 != 0:
        raise ValueError
    decryptor = Cipher(algorithms.AES(key), DEFAULT_MODE, backend=default_backend()).decryptor()
    return decryptor.update(data)

代码可按以下方式执行:

>>> encrypt(b'a'*16, b'I_got_one_key_in_32bytes_length.')
'\xab\x07\x9d\xa0\xf0\xa0g\x9ae\xd9\x10\x9e\xea2\xb4\x17'
>>> decrypt(b'\xab\x07\x9d\xa0\xf0\xa0g\x9ae\xd9\x10\x9e\xea2\xb4\x17', b'I_got_one_key_in_32bytes_length.')
'aaaaaaaaaaaaaaaa'

这里的任务是change the mode从欧洲央行到其他国家,比如说GCM。你知道吗

DEFAULT_MODE = modes.GCM('iv')

代码仍可以在以下位置执行:

>>> encrypt(b'a'*16, b'I_got_one_key_in_32bytes_length.')
'Y5y\xbe\xeeK\xb9\x10\xcdf\x99\xa6\x1d\xf2\xa0\x1e'
>>> decrypt(b'Y5y\xbe\xeeK\xb9\x10\xcdf\x99\xa6\x1d\xf2\xa0\x1e', b'I_got_one_key_in_32bytes_length.')
'aaaaaaaaaaaaaaaa'

然而,由于这些加密/解密功能已经广泛使用了一段时间,因此提出了一个问题:如何在不影响原始加密数据的情况下迁移到新模式?


PS:我的想法是这样的:如果可能的话,在GCM模式下解密数据,否则在ECB模式下解密;然后在GCM模式下加密所有数据。但是,这个想法行不通,因为我没有办法提出错误。通过这种方法,可以知道加密数据的AES模式吗?

def decrypt(data, key):
    try:
        # decrypt data by key in GCM
    except GCMDecryptFailedError:
        # decrypt data by key in ECB
    return decrypted_data

Tags: keyinbackenddefaultdatamode模式one
1条回答
网友
1楼 · 发布于 2024-05-26 04:24:53

这里的错误是直接使用加密算法,而不指定特定的协议和协议版本号。幸运的是,有办法解决这个问题,并指定一个特定的协议。你知道吗

密码学使用的技巧之一是,不可能随机生成特定内容,因为生成特定值的几率每降低一位。所以你能做的就是给你的密文加上前缀,比如128/16字节的比特值。在密文开始时生成该值的概率是2到128的幂次方(如果消息本身不是随机的,则对于特定密钥的概率较小)。换言之,这种可能性低至猜测一个AES-128密钥;我们称这种可能性为“可忽略不计”。这个技巧当然取决于ECB加密的输出,使用的随机密钥也是随机的。你知道吗

但是,将来可能需要包含一个或多个字节作为协议版本指示符。因此,您可以发送例如字节值01作为新版本,然后是16字节的魔术值,接着是GCM的随机nonce、密文和GCM身份验证标记(如果GCM密文中还没有包含)。一旦您摆脱了协议的ECB版本(消息中未指明的版本00),那么您就可以摆脱魔法,将消息的协议头中的16个字节重新用于协议2或更高版本。你知道吗

如果您想生成一个漂亮的魔术,那么您可以使用任何类型的16字节字符串,比如ASCII中的"Protocol 1, GCM:"(不带引号)。如果要使用更大的字符串,还可以使用哈希最左边的128位。你知道吗

所以一开始你的逻辑是,在伪代码中:

versionByte = message[0]
if message.length >= 17 && versionByte == 01h then
    magic = message[1- 16]
    if magic == "Protocol 1, GCM:" then
        gcmDecrypt(message, 17)
    else
        ecbDecrypt(message, 0)
//  - include other versions here  -
else
    ecbDecrypt(message, 0)

当然,这仍然是一个非常基本的协议。但至少你以后可以改变它。您可能希望查看更完整的协议规范,例如Fernet、CMS或-当然-TLS,而不仅仅是AES-GCM。你知道吗

无论你做什么:在一个单独的文档中写下你的协议,并从你的代码中引用它。您可以在源代码中引用您的简单协议,以便于查找。你知道吗

相关问题 更多 >