Подтвердить что ты не робот

Почему PyCrypto не использует стандартный IV?

Я пытаюсь выяснить, почему мой клиент Python и сервер Ruby не согласны с тем, как шифровать данные. Единственное различие, которое я вижу в коде Ruby и моем коде, заключается в том, что они не указывают вектор инициализации, поэтому он возвращается к умолчанию по умолчанию для всех \x0

Когда я пытаюсь создать экземпляр PyCrypto без iv, он дает мне ошибку. Вот пример:

from Crypto.Cipher import AES
test = "Very, very confidential data"
key = b'Thirty Two Byte key, made Beef y' 

gryp = AES.new(key, AES.MODE_CBC)

(Этот пример является, по сути, примером кода из документов PyCrypto без указания IV). Документы говорят, что w/r/t IV "Это необязательно, а когда нет, ему будет присвоено значение по умолчанию для всех нулей". Однако я получаю ошибку "ValueError: IV должен иметь длину 16 байтов".

Поэтому я мог бы указать IV, это не проблема, но я пытаюсь понять, что если он думает, что не может использовать значение по умолчанию, если что-то не так с тем, как я использую библиотеку.

4b9b3361

Ответ 1

Это выглядит как ошибка в документации по классу для Pycrypto AES, поскольку реализация AES была изменена, так что IV не необязательно для тех режимов, которые требуют одного (т.е. вы должны сами передать 16 байтов нулей, если вы это сделаете).

См. этот отчет отчет об ошибке для той же самой проблемы, где кто-то не указал IV и просмотрел онлайн-документы. Было внесено изменение, которое явно требует IV и, по сути, никто не обновил онлайн-документы, чтобы отразить это. Документы класса в источнике Pycrypto были обновлены, но онлайн-документацию необходимо восстановить, чтобы отразить это.

В новой документации из источника указано:

Для всех других режимов это должно быть block_size long long.

Вместо старой версии

Для всех остальных режимов это должно быть block_size long. Это необязательно и когда нет, ему будет присвоено значение по умолчанию для всех нулей.

Обновленный пример в источнике, который указывает iv,:

from Crypto.Cipher import AES
from Crypto import Random

key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')

Ответ 2

вот реализация, которая работает для меня с некоторыми исправлениями:

class AESCipher:

    def __init__(self, key):
        self.bs = 32
        if len(key) >= 32:
            self.key = key[:32]
        else:
            self.key = self._pad(key)

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:]))

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    def _unpad(self, s):
        return s[:-ord(s[len(s)-1:])]