Ответ 1
Криптография с открытым ключом обычно используется только для небольших объемов данных. Он медленный, и его трудно использовать правильно. Обычная практика заключается в том, чтобы использовать другие методы для уменьшения асимметричной проблемы до той, где безопасность обеспечивается общим ключом, а затем использовать криптографию с открытым ключом для защиты этого общего ключа. Например:
- Чтобы зашифровать файл, произвольно создайте секретный ключ для блочного или потокового шифрования (например, AES). Храните данные, зашифрованные этим шифрованием, и храните секретный ключ, зашифрованный открытым ключом вместе с зашифрованной полезной нагрузкой.
- Чтобы подписать файл, вычислите криптографический дайджест (например, SHA-256). Подпишите дайджест файла с закрытым ключом и сохраните его вместе с файлом.
Итак, набросок того, как может выглядеть шифрование (предупреждение, непроверенный код, введенный непосредственно в браузере):
import os
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
import Crypto.Util.number
def encrypt_file(rsa, input, output):
# Generate secret key
secret_key = os.urandom(16)
# Padding (see explanations below)
plaintext_length = (Crypto.Util.number.size(rsa.n) - 2) / 8
padding = '\xff' + os.urandom(16)
padding += '\0' * (plaintext_length - len(padding) - len(secret_key))
# Encrypt the secret key with RSA
encrypted_secret_key = rsa.encrypt(padding + secret_key, None)
# Write out the encrypted secret key, preceded by a length indication
output.write(str(len(encrypted_secret_key)) + '\n')
output.write(encrypted_secret_key)
# Encrypt the file (see below regarding iv)
iv = '\x00' * 16
aes_engine = AES.new(secret_key, AES.MODE_CBC, iv)
output.write(aes_engine.encrypt(input.read()))
iv
является вектором инициализации для CBC режим работы. Он должен быть уникальным для каждого сообщения. Обычно он отправляется вместе с данными в открытом тексте. Здесь, поскольку ключ используется только один раз, вы можете использовать известный IV.
API блочного шифра описан в PEP 272. К сожалению, он поддерживает только шифрование "все в один раз". Для больших файлов было бы лучше зашифровать кусок куском; вы можете зашифровать всего лишь блок за раз (16 байт для AES), но для этого вам нужна лучшая библиотека криптографии.
Обратите внимание, что в общем случае вы не должны напрямую шифровать данные с помощью RSA. Наиболее очевидная проблема заключается в том, что злоумышленник знает открытый ключ и поэтому может попытаться угадать открытый текст (если злоумышленник считает, что открытый текст может быть swordfish
, тогда злоумышленник может зашифровать swordfish
открытым ключом RSA и сравнить результат с выходом RSA-шифрования). Еще одна проблема, которая возникла бы, если бы вы хотели отправить файл нескольким получателям, заключается в том, что если шаг шифрования RSA детерминирован, тогда злоумышленник может сказать, что открытые тексты являются одинаковыми, поскольку зашифрованные тексты являются одинаковыми. Обычная защита от этих проблем заключается в использовании схемы дополнения , которая состоит из добавления некоторых случайных секретных данных в открытый текст; эти данные называются заполнением. Затем злоумышленник не может угадать случайные данные и видит разные результаты для каждого шифрования, потому что один и тот же открытый текст никогда не зашифровывается дважды; что касается законного получателя, то заполнение - это просто данные, которые можно выбросить.
Здесь может показаться, что вышеупомянутые проблемы не применяются в этом сценарии. Однако есть и другие недостатки, которые могут возникнуть в результате использования RSA без защиты. В частности, если публичный показатель очень мал (здесь не так, как PyCrypto использует 65537), или вы шифруете один и тот же материал для многих разных получателей (опять же, вероятно, это не так, поскольку каждое сообщение имеет свой секретный ключ), тогда простой математический расчет позволит злоумышленнику восстановить открытый текст RSA. Чтобы избежать этой атаки, значение, зашифрованное с помощью RSA, должно быть "достаточно близко" к модулю RSA, так что операция шифрования фактически выполняет модульное возведение в степень. Предлагаемое мною дополнение гарантирует, что, делая байт самого высокого порядка, который соответствует 0xff; это считается безопасным, хотя в реальном мире вы должны использовать утвержденный режим заполнения (OAEP).