Как перенести режим AES с одного на другой? - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть 2 функции: шифрование / дешифрование, реализованное 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 от ECB до других, скажем, 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 позже.Но AFAIK, эта идея не будет работать, так как у меня нет способа поднять ошибку. При таком подходе возможно ли узнать режим шифрования данных AES?

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

1 Ответ

0 голосов
/ 18 февраля 2019

Ошибка здесь заключается в прямом использовании криптографического алгоритма, без указания конкретного протокола и номера версии протокола, который поставляется вместе с ним.К счастью, есть способы выйти из этого, и указывает конкретный протокол .

Один из приемов, используемых криптографией, заключается в том, что невозможно генерировать конкретный контент случайным образом просто потому, чтогенерации конкретного значения уменьшается на каждый бит.Так что вы можете сделать префикс вашего зашифрованного текста, например, с битным значением 128/16.Вероятность того, что вы сгенерируете это значение в начале своего зашифрованного текста, равна 2 степени 128 для каждого сообщения (меньше, если сообщения не являются случайными для конкретного ключа).Другими словами, вероятность не меньше, чем угадывание ключа AES-128;мы называем такой шанс "незначительным".Этот трюк, конечно, зависит от вывода шифрования ECB с использованием случайного ключа, который также должен быть случайным.

Однако в будущем вы можете захотеть включить один или несколько байтов в качестве индикатора версии протокола .Таким образом, вы можете отправить, например, значение байта 01 в качестве новой версии, а затем 16-байтовое магическое значение , за которым следует случайный одноразовый номер для GCM, зашифрованный текст и тег аутентификации GCM (если он еще не включен)в зашифрованном тексте GCM).После того, как вы избавились от версии протокола ECB (версия 00, не указанная в ваших сообщениях), вы можете избавиться от магии и повторно использовать 16 байтов в заголовке протокола ваших сообщений для протокола 2 или выше..

Если вы хотите создать красивую магию, вы можете использовать любой вид 16-байтовой строки, скажем, "Protocol 1, GCM:" (без кавычек) в ASCII.Вы также можете использовать крайние левые 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.

Что бы вы ни делали: запишите свой протокол в отдельный документ и обратитесь к нему из своего кода .Вы можете указать свой простой протокол в исходном коде как легкий поиск.

...