Проблема PyCrypto с помощью AES+CTR

Я пишу часть кода для шифрования текста с помощью симметричного шифрования. Но это не возвращается с правильным результатом...

from Crypto.Cipher import AES
import os

crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter = lambda : os.urandom(16))
encrypted = crypto.encrypt("aaaaaaaaaaaaaaaa")
print crypto.decrypt(encrypted)

Здесь, дешифрованный текст отличается от оригинала.

Я действительно не понимаю много о криптографии, поэтому терпите меня. Я понимаю, что режим CTR требует, чтобы "встречная" функция предоставила случайный счетчик каждый раз, но почему ему нужен он, чтобы быть 16 байтов, когда мой ключ составляет 32 байта, и он настаивает, что мое сообщение находится в кратных числах 16 байтов также? Действительно ли это нормально?

Я предполагаю, что это не возвращается к исходному сообщению, потому что счетчик, измененный между, шифрует и дешифрует. Но затем, как это, как предполагается, работает теоретически так или иначе? Что я делаю неправильно? Так или иначе я вынужден обратиться назад к ЕЦБ, пока я не понимаю это :(

10
задан xster 1 July 2010 в 03:55
поделиться

2 ответа

Счетчик должен возвращать то же самое при расшифровке, что и при шифровании, как вы интуитивно понимаете, поэтому один ( ВООБЩЕ НЕ БЕЗОПАСНЫЙ ) способ сделать это:

>>> secret = os.urandom(16)
>>> crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter=lambda: secret)
>>> encrypted = crypto.encrypt("aaaaaaaaaaaaaaaa")
>>> print crypto.decrypt(encrypted)
aaaaaaaaaaaaaaaa

CTR - это блочный шифр, поэтому ограничение «16-за-раз», которое вас удивляет, является довольно естественным.

Конечно, так называемый «счетчик», возвращающий одно и то же значение при каждом вызове , является крайне небезопасным . Не нужно много делать лучше, например ...:

import array

class Secret(object):
  def __init__(self, secret=None):
    if secret is None: secret = os.urandom(16)
    self.secret = secret
    self.reset()
  def counter(self):
    for i, c in enumerate(self.current):
      self.current[i] = c + 1
      if self.current: break
    return self.current.tostring()
  def reset(self):
    self.current = array.array('B', self.secret)

secret = Secret()
crypto = AES.new(os.urandom(32), AES.MODE_CTR, counter=secret.counter)
encrypted = crypto.encrypt(16*'a' + 16*'b' + 16*'c')
secret.reset()
print crypto.decrypt(encrypted)
12
ответ дан 3 December 2019 в 17:57
поделиться

Вектор инициализации ("счетчик") должен оставаться неизменным, как и ключ, между шифрованием и дешифрованием. Он используется для того, чтобы вы могли кодировать один и тот же текст миллион раз и каждый раз получать разный шифротекст (предотвращая некоторые известные атаки с открытым текстом и атаки с подбором шаблона). При расшифровке необходимо использовать тот же IV, что и при шифровании. Обычно, когда вы начинаете расшифровывать поток, вы инициализируете IV тем же значением, что и при шифровании этого потока.

См. http://en.wikipedia.org/wiki/Initialization_vector для получения информации о векторах инициализации.

Обратите внимание, что os.urandom(16) не является "детерминированной", что является требованием для функций счетчика. Я предлагаю вам использовать функцию инкремента, поскольку именно так устроен режим CTR. Начальное значение счетчика должно быть случайным, но последующие значения должны быть полностью предсказуемы от начального значения (детерминированы). Возможно, о начальном значении даже позаботятся за вас (я не знаю деталей)

Что касается размеров ключа, IV и входных данных, похоже, что выбранный вами шифр имеет размер блока 16 байт. Все, что вы описали, соответствует этому и кажется мне нормальным.

1
ответ дан 3 December 2019 в 17:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: