大量のファイルが
openssl enc -aes-256-cbc -pass pass:MYPASSWORD
Opensslはパスフレーズからkey + IVを派生させる必要があります。 そのMYPASSWORDに相当するkey + IVと同等のものを知りたい。それは可能ですか?
MYPASSWORDを知っています。私は復号化し、次に新しい既知のキー+ IVで再暗号化できます:
openssl enc -d -aes-256-cbc -pass pass:MYPASSWORD
openssl enc -aes-256-cbc -K MYKEY -IV MYIV
しかし問題は、データの量が非常に大きいことです。
_openssl enc
_コマンドラインオプションの使用法について説明します there 。以下で、あなたの質問にお答えしますが、私のテキストの最後の部分を確認することを忘れないでください。それは有益です。
OpenSSLはsalted鍵導出アルゴリズムを使用します。ソルトは、暗号化時に生成されるランダムなバイトの断片であり、ファイルヘッダーに格納されます。復号化すると、ソルトがヘッダーから取得され、キーとIVが指定されたパスワードとソルトから再計算されます。
コマンドラインで、_-P
_オプション(大文字のP)を使用して、salt、key、IVを出力し、終了できます。 _-p
_(小文字のP)を使用してソルト、キー、IVを出力し、暗号化を続行することもできます。まずこれを試してください:
_openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P
_
このコマンドを数回実行すると、呼び出しごとに異なる値が返されることがわかります。これは、_-d
_フラグがない場合、_openssl enc
_は暗号化を実行し、毎回ランダムなソルトを生成するためです。塩はさまざまなので、キーとIVも異なります。したがって、暗号化する場合、_-P
_フラグはあまり役に立ちません。ただし、_-p
_フラグは使用できます。もう一度やってみましょう。今回は、_foo_clear
_に暗号化するファイル_foo_enc
_があります。これを実行してみましょう:
_openssl enc -aes-256-cbc -pass pass:MYPASSWORD -p -in foo_clear -out foo_enc
_
このコマンドはファイルを暗号化し(したがって_foo_enc
_を作成します)および次のように出力します。
_salt=A68D6E406A087F05
key=E7C8836AD32C688444E3928F69F046715F8B33AF2E52A6E67A626B586DE8024E
iv=B9F128D827203729BE52A834CC0890B7
_
これらの値は、ファイルの暗号化に実際に使用されるソルト、キー、およびIVです。
後でそれらを取り戻したい場合は、_-P
_フラグと共に_-d
_フラグを使用できます。
_openssl enc -aes-256-cbc -pass pass:MYPASSWORD -d -P -in foo_enc
_
これは毎回上記のsamesalt、key、IVを出力します。どうして?今回はdecryptingなので、_foo_enc
_のヘッダーが読み取られ、ソルトが取得されるためです。与えられたソルト値について、キーとIVへのパスワードの導出は確定的です。
さらに、_-P
_フラグは実際の復号化を防ぐため、ファイルが非常に長い場合でも、このキーとIVの取得は高速です。 ヘッダーを読み取りますが、そこで停止します。
代わりに、_-S
_フラグでソルト値を指定するか、_-nosalt
_でソルトを完全に非アクティブ化できます。無塩暗号化は推奨されていません事前計算されたテーブルを使用してパスワードクラッキングを高速化できるためです(同じパスワードは常に同じキーとIVを生成します)。ソルト値を指定すると、適切なソルトを生成する責任があります。つまり、ソルトをできるだけ一意にしようとします(実際には、ランダムに生成する必要があります)。サイレントエラーが発生する十分な余地があるため、openssl
に処理を任せることをお勧めします(「サイレント」は「弱いクラック可能」を意味しますが、コードは引き続き機能するため、テスト中に問題を検出できません)。
OpenSSLが使用する暗号化形式は非標準です。これは「OpenSSLが行うこと」であり、OpenSSLのすべてのバージョンが互いに一致する傾向がある場合、OpenSSLソースコードを除いて、この形式を説明するリファレンスドキュメントはまだありません。ヘッダーの形式はかなり単純です。
_magic value (8 bytes): the bytes 53 61 6c 74 65 64 5f 5f
salt value (8 bytes)
_
したがって、ASCII文字列_Salted__
_のエンコードで始まり、その後にソルト自体が続く)で始まる固定の16バイトヘッダーです。これですべてです!暗号化アルゴリズムは示されていません。自分で追跡します。
パスワードとソルトがキーとIVに変換されるプロセスは文書化されていませんが、ソースコードはOpenSSL固有の EVP_BytesToKey()
関数を呼び出すことを示しています。カスタム 鍵導出関数(KDF) ハッシュを繰り返したもの。これは非標準で十分に吟味されていない構成(!)であり、疑わしいレピュテーションのMD5ハッシュ関数に依存しています(!!)。その関数は、コマンドラインでundocumented_-md
_フラグ(!!!)を使用して変更できます。 「反復回数」はenc
コマンドによって1に設定され、変更できません(!!!!)。つまり、キーの最初の16バイトはMD5(password || salt)に等しくなり、それだけです。
これは非常に弱いです!PCでコードを記述する方法を知っている人なら誰でも、そのようなスキームを解読して、数十を「試す」ことができます。毎秒数百万の潜在的なパスワード(GPUで数億が達成可能になります)。 _openssl enc
_を使用する場合は、パスワードのエントロピーが非常に高いことを確認してください!(つまり、通常推奨される値よりも高く、少なくとも80ビットを目指します) )。または、できれば使用しないでください。代わりに、より堅牢なものを使用してください( GnuPG 、パスワードの対称暗号化を行う場合、基盤となるハッシュ関数の反復が多い強力なKDFを使用します)。
-P
オプション?
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P
salt=28C5AD65428E4FD2
key=215202893B8CFEE68E733F69C55AE4C7BED7B2A06533774F3EA0894880E585E6
iv =186DE986FC69F8E47ED692B24D940BED
そのMYPASSWORDに相当するkey + IVを知りたい
キー導出関数を EVP_BytesToKey
に複製するだけでよく、これはかなり簡単です。
-md
を指定しない場合(または-md md5
を指定する場合)、使用されるKDFはMD5ベースですが、最初の16バイトは、PKCS#5 PBKDF1を使用して1
の反復回数で導出されます。次に、これはEVP_BytesToKey
で指定された鍵導出アルゴリズムを使用して拡張され、鍵とIVのサイズ要件を満たします。
-md
を使用して基礎となるハッシュ関数を指定し、MD5以外のハッシュ関数(-md sha256
など)を選択すると、OpenSSLはonlyKDFはEVP_BytesToKey
で指定されています(PBKDF1ではありません)。
Python 3での実装(- passlib が必要):
import hashlib, binascii
from passlib.utils.pbkdf2 import pbkdf1
def hasher(algo, data):
hashes = {'md5': hashlib.md5, 'sha256': hashlib.sha256,
'sha512': hashlib.sha512}
h = hashes[algo]()
h.update(data)
return h.digest()
# pwd and salt must be bytes objects
def openssl_kdf(algo, pwd, salt, key_size, iv_size):
if algo == 'md5':
temp = pbkdf1(pwd, salt, 1, 16, 'md5')
else:
temp = b''
fd = temp
while len(fd) < key_size + iv_size:
temp = hasher(algo, temp + pwd + salt)
fd += temp
key = fd[0:key_size]
iv = fd[key_size:key_size+iv_size]
print('salt=' + binascii.hexlify(salt).decode('ascii').upper())
print('key=' + binascii.hexlify(key).decode('ascii').upper())
print('iv=' + binascii.hexlify(iv).decode('ascii').upper())
return key, iv
例(OpenSSL 0.9.8および1.0.1でテスト済み):
openssl_kdf('md5', b'test', b'\xF6\x81\x8C\xAE\x13\x18\x72\xBD', 32, 16)
# generates the same output as:
openssl enc -aes-256-cbc -P -pass pass:test -S F6818CAE131872BD
openssl_kdf('sha256', b'test', b'\xF6\x81\x8C\xAE\x13\x18\x72\xBD', 32, 16)
# generates the same output as:
openssl enc -aes-256-cbc -P -pass pass:test -S F6818CAE131872BD -md SHA256
最近のopenssl(2018年3月27日、OpenSSL 1.1.0hでもテスト済み)では、簡単で簡単に確認できます。
openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
echo -n salt1234 | od -A n -t x1 | Perl -lpe's,\s+,,g'
73616c7431323334
openssl enc -e -aes-128-cbc -pass pass:123 -S 73616c7431323334 -P -md sha256
salt=73616C7431323334
key=5A7C52236BAEAE1A92A6B2D1E50C43ED
iv =9F629A34588A4006FE1C7E8FC664B5EC
echo -n 123salt1234 | openssl dgst -sha256 -binary | hexdump -Cv
00000000 5a 7c 52 23 6b ae ae 1a 92 a6 b2 d1 e5 0c 43 ed |Z|R#k.........C.|
00000010 9f 62 9a 34 58 8a 40 06 fe 1c 7e 8f c6 64 b5 ec |.b.4X.@...~..d..|
00000020
よく見ると、-P
出力は、hexdump出力と一致します。
結論:研究と探査以外の目的でenc
を使用しないでください。これは単なるニースのおもちゃです(まだ知らなかった場合)。