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 был разработан для предотвращения всех вышеупомянутых атак, а реализации на стороне клиента и серверной части долгое время созревали.