AES - Шифрование с помощью Crypto (node -js)/дешифрование с помощью Pycrypto (python)

Я пишу этот вопрос + ответ, потому что я много боролся (возможно, из-за отсутствия опыта), заблудился разными способами шифрования/дешифрования с помощью node или python.

Я думал, что мое дело может помочь людям в будущем.

Что мне нужно сделать:

  • Получить данные из формы, зашифровать их с помощью Crypto (node -js)
  • Передайте зашифрованные данные в Python и расшифруйте его с помощью PyCrypto.

Я решил использовать шифрование AES.

Вот как я начал (я не буду проходить все, что я пробовал):

  • Я последовал примеру в конце этой страницы

    Который дал в моем случае:

    (это может быть очень плохое сочетание между javascript и coffeescript)

    crypto = require "crypto"
    [...]
    key = "mykeywhatever"
    cipher = crypto.createCipher('aes192', key)
    cipher.update('string i want to encode', 'binary', 'hex')
    encoded_string = cipher.final('hex')
    [...]
    

    Это сработало очень хорошо, чтобы закодировать мою строку.

  • Затем я написал свой python script, чтобы расшифровать эту строку, используя readme на странице PyCrypto github:

    from Crypto.Cipher import AES
    [...]
    my_string = data_coming_from_rabbitmq
    obj = AES.new('mykeywhatever', AES.MODE_CBC)
    obj.decrypt(ciphertext)
    [...]
    

    Это явно не сработало: в readme есть IV, но так как я не дал один в node script, почему я должен дать один в python один?

После того, как я узнал, что node Crypto использует OpenSSL, в то время как PyCrypto, по-видимому, этого не делает. Поэтому я просмотрел и нашел эти страницы:

Итак, все усложнилось, никто не делает то же самое для дешифрования данных, я потерялся и попросил о помощи.

Ответ заключается в том, с кем я с коллегой (ну, в основном, моим кордером).

Ответы

Ответ 1

Итак, мы начали с "Как я могу дешифровать... OpenSSL" ответ.

  • Нам нужно было изменить шифрование script, которое дало:

    crypto = require "crypto"
    [...]
    var iv = new Buffer('asdfasdfasdfasdf')
    var key = new Buffer('asdfasdfasdfasdfasdfasdfasdfasdf')
    var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    cipher.update(new Buffer("mystring"));
    var enc = cipher.final('base64');
    [...]
    

    iv должно быть 16 байт, - 32 байта. И мы изменили createCipher на createCipheriv.

  • Вернуться к расшифровке python script:

    Процесс просто читал документацию PyCrypto и сравнивал с кодом, который мы начали с.

    Тогда мы решили просто придерживаться API и начать с нуля. И он дал:

    from base64 import b64decode
    from Crypto.Cipher import AES
    [...]
    iv = 'asdfasdfasdfasdf'
    key = 'asdfasdfasdfasdfasdfasdfasdfasdf'
    encoded = b64decode('my_encrypted_string')
    
    dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
    value = dec.decrypt(encoded)
    

И это было так просто... Надеюсь, это поможет некоторым из вас!

Обновление:

Как писал Персеид в комментариях своего ответа, IV должен быть случайным и разным для каждого сообщения

Ответ 2

Система, которую вы строите, вероятно, небезопасна

За исключением хранилища, вы в принципе никогда не хотите просто шифровать свои данные, но также authenticate. Аутентификация в этом контексте означает, что действительное сообщение может генерироваться только тем, кто знает ключ. Широко используемая схема аутентификации HMAC.

Если вы не аутентифицируете свои сообщения, кто-либо может передавать данные в вашу службу. Злоумышленник, возможно, не сможет полностью контролировать результат после дешифрования, но он/она все еще может быть очень опасным. Например, если вы используете CBC (что вы делаете) и наиболее распространенные схемы прокладки (AES является блочным шифрованием и может шифровать только 128 бит блоков данных), и злоумышленник может различать ошибку заполнения и любую другую ошибку, а затем все ваши сообщения может быть расшифрован злоумышленником. Это называется удалением оракула и слишком распространено.

Для защиты от этого класса атак вы можете использовать аутентифицированную схему шифрования, например GCM.

Также вам нужно защитить от повторных атак. Рассмотрите банковское приложение, и данные, которые вы передаете, являются банковским переводом. Запрет любого TAN-атакующего может записывать предыдущую транзакцию и повторно воспроизводить эту транзакцию на ваш сервис снова и снова, таким образом, перенося несколько из денег, которые первоначально хотел клиент.

Является ли форма, с которой вы передаете данные через HTTPS? Если нет: может ли клавиша подслушиваться злоумышленником? Как пользователь знает, что он получил форму от вас, а не кого-то еще (SSL/TLS - это как-то об аутентификации, так как речь идет о конфиденциальности).

Возможно, я забыл некоторые другие векторы атаки, простые предложения CBC-шифрования.

Альтернативы

Вероятно, самым простым способом защиты от этих атак является передача данных формы через HTTPS. SSL/TLS был разработан для предотвращения всех вышеупомянутых атак, а реализации на стороне клиента и серверной части долгое время созревали.