5

Python で以下を実装しようとしています: openssl enc -e -aes-256-cbc -base64 -k "Secret Passphrase" -in plaintext.txt -out ciphertext.txt

openssl enc -d -aes-256-cbc -base64 -k "秘密のパスフレーズ" -in ciphertext.txt -out validation.txt

PyCrypto、M2Crypto など、いくつかの異なるモジュールを試しましたが、パスワードを適切なサイズのキーに変更し、すべてを正しくエンコードするという正しい組み合わせを取得できないようです。https://github.com/nvie/SimpleAESを見つけましたが、基本的にはコマンドラインで OpenSSL を実行するので、避けたいと思います。

4

2 に答える 2

6

base64Base 64 のエンコードとデコードは、標準モジュールを介して簡単に処理できます。

CBC モードでの AES-256 復号化と暗号化は、PyCrypto と M2Crypto の両方でサポートされています。

唯一の非標準 (そして最も困難な) 部分は、IV とパスワードからのキーの導出です。OpenSSL は、この man ページで説明されている独自のEVP_BytesToKey機能を介してこれを行います。

同等の Python は次のとおりです。

def EVP_BytesToKey(password, salt, key_len, iv_len):
    """
    Derive the key and the IV from the given password and salt.
    """
    from hashlib import md5
    dtot =  md5(password + salt).digest()
    d = [ dtot ]
    while len(dtot)<(iv_len+key_len):
        d.append( md5(d[-1] + password + salt).digest() )
        dtot += d[-1]
    return dtot[:key_len], dtot[key_len:key_len+iv_len]

key_lenは 32 で、iv_lenAES-256 の場合は 16 です。この関数は、ペイロードの復号化に使用できるキーと IV を返します。

OpenSSL は、暗号化されたペイロードの最初の 8 バイトにソルトを入れて期待します。

最後に、CBC モードの AES は、16 バイト境界に整列されたデータでのみ機能します。使用されるデフォルトのパディングは PKCS#7 です。

したがって、暗号化の手順は次のとおりです。

  1. ソルトとして 8 バイトのランダム データを生成します。
  2. 手順 1 のソルトを使用して、パスワードから AES キーと IV を取得します。
  3. 入力データを PKCS#7 でパディングします。
  4. 手順 2 のキーと IV を使用して、CBC モードで AES-256 を使用してパディングを暗号化します。
  5. Base64 でエンコードし、ステップ 1 のソルトを出力します。
  6. Base64 でエンコードし、手順 4 の暗号化されたデータを出力します。

復号化からの手順は逆です。

  1. 入力データを Base64 からバイナリ文字列にデコードします。
  2. デコードされたデータの最初の 8 バイトをソルトとして扱います。
  3. 手順 1 のソルトを使用して、パスワードから AES キーと IV を取得します。
  4. ステップ 3 の AES キーと IV を使用して、残りのデコードされたデータを復号化します。
  5. 結果から PKCS#7 パディングを確認して削除します。
于 2012-12-17T22:12:51.793 に答える