Включить nonce и количество блоков в PyCrypto AES MODE_CTR - PullRequest
5 голосов
/ 16 марта 2012

Некоторая справочная информация, вы можете пропустить эту часть для реального вопроса

Это мой третий вопрос по этой теме здесь, в stackoverflow.Чтобы закончить, это другие вопросы AES с crypt-js и PyCrypto и Сопоставить де / шифрование AES в python и javascript .К сожалению, моя последняя попытка получила два downvots за оригинальный вопрос.Проблема была, даже Я не знал, каков был мой настоящий вопрос .Я просто покопался, чтобы найти настоящий вопрос, который искал.С отзывами в комментариях и прочтением дополнительной информации я обновил свой вопрос.Думаю, я раскопаю правильный вопрос.Но моя проблема не получила больше просмотров после моих обновлений.Поэтому я очень надеюсь, что этот вопрос теперь стал более ясным и понятным - даже я знаю, в чем заключается моя проблема: D
Спасибо всем за создание стекаповорот в этом крутом сообществе - я часто находил здесь решения для своих проблем.Пожалуйста, продолжайте отвечать на плохие вопросы, чтобы их можно было улучшать и обновлять, что расширяет эту огромную базу знаний и решений.И не стесняйтесь исправлять мою грамматику английского языка и орфографию.

Проблема

AES в Javascript

У меня есть зашифрованная строка, которую я могу расшифровать с помощью этого эта реализация Javascript режима CTR AES 256

password = "myPassphrase"
ciphertext = "bQJdJ1F2Y0+uILADqEv+/SCDV1jAb7jwUBWk"
origtext = Aes.Ctr.decrypt(ciphertext, password, 256);
alert(origtext)

Это расшифровывает мою строку, и появляется окно с This is a test Text.

AES с PyCrypto

Теперь я хочу расшифровать эту строку с помощью python и PyCrypto

password = 'myPassphrase'
ciphertext = "bQJdJ1F2Y0+uILADqEv+/SCDV1jAb7jwUBWk"
ctr = Counter.new(nbits=128)
encryptor = AES.new(key, AES.MODE_CTR, counter=ctr)
origtext = encryptor.decrypt(base64.b64decode(ciphertext))
print origtext

Этот код не запускается.Я получаю ValueError: AES key must be either 16, 24, or 32 bytes long.Когда я понял, что в PyCrypto мне нужно делать больше, чем просто вызывать метод дешифрования, я начал исследовать и пытаться выяснить, что мне нужно делать.

Расследование

Основные вещиСначала я выяснил, были ли:

  • AES 256 бит (?).Но стандарт AES 128 бит.Достаточно ли увеличения ключевой фразы до 32 байт?
  • Counter Mode.Легко установить в PyCrypto с помощью AES.MODE_CTR.Но я должен указать метод counter ().Поэтому я использовал базовый двоичный счетчик , предоставленный PyCrypto .Совместимо ли это с реализацией Javascript?Я не могу понять, что они делают.
  • Строка в кодировке base64.Не большая проблема.
  • Заполнение в целом.И пароль, и зашифрованная строка.

Для пароля они делают это:

for (var i=0; i<nBytes; i++) {
    pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
}

Затем я сделал это в python

l = 32
key = key + (chr(0)*(l-len(key)%l))

Но это сделалнет помощи.Я все еще получаю странную строку ? A???B??d9= ,?h????' со следующим кодом

l = 32
key = 'myPassphrase'
key = key + (chr(0)*(l-len(key)%l))
ciphertext = "bQJdJ1F2Y0+uILADqEv+/SCDV1jAb7jwUBWk"
ctr = Counter.new(nbits=128)
encryptor = AES.new(key, AES.MODE_CTR, counter=ctr)
origtext = encryptor.decrypt(base64.b64decode(ciphertext))
print origtext

Затем я читаю больше о реализации Javascript и там говорится:

[...] В этой реализацииначальный блок содержит одноразовый номер в первых 8 байтах, а количество блоков во вторых 8 байтах.[...]

Я думаю, что это может быть ключом к решению.Поэтому я проверил, что происходит, когда я шифрую пустую строку в Javascript:

origtext = ""
var ciphertext =Aes.Ctr.encrypt(origtext, password, 256);
alert(ciphertext)

В окне предупреждения отображается /gEKb+N3Y08= (12 символов).Но почему 12?Разве это не должно быть 8 + 8 = 16 байт?Ну, в любом случае, я попробовал метод bruteforce для расшифровки python, протестировав дешифрование с помощью for i in xrange(0,20): и ciphertext[i:] или base64.b64decode(ciphertext)[i:].Я знаю, что это очень неловкая попытка, но я все больше и больше отчаялся.И это тоже не сработало.

Будущие перспективы также заключаются в том, чтобы реализовать шифрование таким же образом.

дополнительная информация

Зашифрованная строка изначально не была зашифрована с помощью это реализация Javascript , это из другого источника.Я только что понял, что код Javascript делает правильные вещи.Поэтому я утверждаю, что этот вид реализации является чем-то вроде «стандарта» .

Вопрос

Что я могу сделать, что шифрование и дешифрование из строки сPyCrypto такой же, как в реализации Javascript, так что я могу обмениваться данными между Javascript и Python?Я также переключился бы на другую криптографическую библиотеку в python, если вы можете предложить другую.Кроме того, я доволен любыми советами и отзывами.

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

1 Ответ

6 голосов
/ 18 марта 2012

Мы все еще имеем дело с кучей вопросов здесь.

Как мне извлечь одноразовый номер и счетчик для расшифровки?

Это легко.В реализации Javascript (которая не следует определенному стандарту в этом отношении) 8-байтовый одноразовый номер добавляется к зашифрованному результату.В Python вы извлекаете его с помощью:

import base64
from_js_bin = base64.decode(from_js)
nonce = from_js_bin[:8]
ciphertext = from_js_bin[8:]

Где from_js - полученная вами двоичная строка.

Счетчик не может быть извлечен, поскольку реализация JS не передает его.Тем не менее, начальное значение (как это обычно бывает) 0.

Как я могу использовать одноразовый номер и счетчик для расшифровки строки в Python?

Во-первых, он должендолжно быть установлено, как nonce и counter объединяются, чтобы получить блок counter.Кажется, что реализация JS следует стандарту NIST 800-38A , где левая половина - это одноразовый номер, а правая половина - счетчик.Точнее, счетчик имеет формат с прямым порядком байтов (младший байт - младший).Это также то, что показывает Википедия: AES CTR mode.

К сожалению, режим CTR плохо документирован в PyCrypto ( известная проблема ).По сути, параметр counter должен быть вызываемым объектом, который возвращает правильный 16-байтовый (для AES) блок счетчика для каждого последующего вызова.Crypto.Util.Counter делает это, но неясным образом.

Это только для целей производительности.Вы можете легко реализовать это самостоятельно так:

from Crypto.Cipher import AES
import struct

class MyCounter:

  def __init__(self, nonce):
    """Initialize the counter object.

    @nonce      An 8 byte binary string.
    """
    assert(len(nonce)==8)
    self.nonce = nonce
    self.cnt = 0

  def __call__(self):
    """Return the next 16 byte counter, as binary string."""
    righthalf = struct.pack('>Q',self.cnt)
    self.cnt += 1
    return self.nonce + righthalf

cipher_ctr = AES.new(key, mode=AES.MODE_CTR, counter=MyCounter(nonce))
plaintext = cipher_ctr.decrypt(ciphertext)

Как долго длится ключ для AES?

Длина ключа для AES-128 составляет 16 байтов.Длина ключа для AES-192 составляет 24 байта.Длина ключа для AES-256 составляет 32 байта.Каждый алгоритм отличается, но большая часть реализации является общей.Во всех случаях алгоритм оперирует 16-байтовыми блоками данных.Для простоты придерживайтесь AES-128 (nBits=128).

Будет ли ваш код работать?

У меня такое ощущение, что не будет, потому что, как вывычислить ключ AES кажется неверным.Код JS кодирует пароль в UTF-8 и шифрует его сам.Результатом является фактический ключевой материал.Он имеет длину 16 байт, поэтому для AES-192 и -256 реализация копирует его часть сзади.Кроме того, перед шифрованием открытый текст также кодируется в кодировке UTF-8.

В общем, я предлагаю вам придерживаться следующего подхода:

  1. Сделайте вашу реализацию JS воспроизводимой (сейчас шифрование зависит оттекущее время, которое меняется довольно часто ;-)).
  2. Вывод значения ключей и данных на каждом шаге (или использование отладчика).
  3. Попробуйте воспроизвести тот же алгоритм в Pythonи распечатайте значения.
  4. Исследуйте, где они начинают различаться.

После того, как вы продублировали алгоритм шифрования в Python, расшифровка должна быть простой.

...