16

PyCryptoを使用して、RSAでファイル暗号化を実装しています。

PyCrypto RSA は 128 文字しか暗号化できないため、まず RSA が非常に遅く、次にファイルを 128 文字のチャンクに分解する必要があるため、多少間違っていることはわかっています。

これまでのコードは次のとおりです。

from Crypto.PublicKey import RSA

file_to_encrypt = open('my_file.ext', 'rb').read()
pub_key = open('my_pub_key.pem', 'rb').read()
o = RSA.importKey(pub_key)

to_join = []
step = 0

while 1:
    # Read 128 characters at a time.
    s = file_to_encrypt[step*128:(step+1)*128]
    if not s: break
    # Encrypt with RSA and append the result to list.
    # RSA encryption returns a tuple containing 1 string, so i fetch the string.
    to_join.append(o.encrypt(s, 0)[0])
    step += 1

# Join the results.
# I hope the \r\r\r sequence won't appear in the encrypted result,
# when i explode the string back for decryption.
encrypted = '\r\r\r'.join(to_join)
# Write the encrypted file.
open('encrypted_file.ext', 'wb').write(encrypted)

私の質問は次のとおりです。ファイルで秘密鍵/公開鍵の暗号化を使用するためのより良い方法はありますか?

Mcrypt と OpenSSL について聞いたことがありますが、ファイルを暗号化できるかどうかはわかりません。

4

1 に答える 1

33

公開鍵暗号方式は通常、少量のデータのみに使用されます。遅く、正しく使用するのが難しい場合があります。通常の方法では、他の方法を使用して、非対称の問題を共有鍵によってセキュリティが提供される問題に減らしてから、公開鍵暗号化を使用してその共有鍵を保護します。例えば:

  • ファイルを暗号化するには、ブロックまたはストリーム暗号 (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()))

ivCBC動作モードの初期化ベクトルです。メッセージごとのキーごとに一意である必要があります。通常、データと一緒に平文で送信されます。ここでは、キーは一度しか使用されないため、既知の IV を使用できます。

ブロック暗号の API はPEP 272に記述されています。残念ながら、一括暗号化しかサポートしていません。大きなファイルの場合は、チャンクごとに暗号化することをお勧めします。一度に暗号化できるのは 1 ブロック (AES の場合は 16 バイト) ですが、そのためにはより優れた暗号ライブラリが必要です。

一般に、RSA を使用してデータを直接暗号化しないでください。swordfish最も明白な懸念は、攻撃者が公開鍵を知っているため、平文を推測しようとする可能性があることです (攻撃者が平文がswordfish. RSA 暗号化)。ファイルを複数の受信者に送信する場合に発生するもう 1 つの問題は、RSA 暗号化の手順が決定論的である場合、暗号文が同じであるため、攻撃者は平文が同じであると判断できることです。これらの問題に対する通常の防御策は、パディング スキームを使用することです。これは、ランダムな秘密データを平文に追加することで構成されます。このデータはパディングと呼ばれます。攻撃者はランダムなデータを推測できず、同じ平文が 2 回暗号化されることはないため、暗号化ごとに異なる結果が表示されます。正当な受信者に関する限り、パディングは破棄できる単なるデータです。

ここで、上記の懸念はこのシナリオには当てはまらないように見えるかもしれません。ただし、保護されていない RSA を使用すると、他の弱点が生じる可能性があります。特に、公開指数が非常に小さい場合 (PyCrypto は 65537 を使用するため、ここでは当てはまりません)、または多くの異なる受信者に対して同じ内容を暗号化する場合 (ここでも、各メッセージには独自の秘密鍵があるため、おそらくそうではありません)、単純な数学的計算により、攻撃者は RSA 平文を復元できます。この攻撃を回避するには、RSA で暗号化された値が RSA モジュラスに「十分近い」必要があります。これにより、暗号化操作が実際に剰余累乗を実行します。私が提案するパディングは、0xff に適合する最上位バイトを作成することにより、次のことを保証します。これは安全であると考えられていますただし、実際には承認されたパディング モード ( OAEP ) を使用する必要があります。

于 2012-01-27T19:37:29.587 に答える