3

私は最近、認証と検証のために SHA-256 HMAC を使用して AES-256 CBC でファイルを暗号化する次のコード サンプルを見つけました。

aes_key, hmac_key = self.keys
# create a PKCS#7 pad to get us to `len(data) % 16 == 0`
pad_length = 16 - len(data) % 16
data = data + (pad_length * chr(pad_length))
# get IV
iv = os.urandom(16)
# create cipher
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
data = iv + cipher.encrypt(data)
sig = hmac.new(hmac_key, data, hashlib.sha256).digest()
# return the encrypted data (iv, followed by encrypted data, followed by hmac sig):
return data + sig

私の場合、かなり大きなファイルではなく、文字列よりもはるかに多くのものを暗号化しているため、コードを次のように変更しました。

aes_key, hmac_key = self.keys
iv = os.urandom(16)
cipher = AES.new(aes_key, AES.MODE_CBC, iv)

with open('input.file', 'rb') as infile:
    with open('output.file', 'wb') as outfile:
        # write the iv to the file:
        outfile.write(iv)

        # start the loop
        end_of_line = True

        while True:
            input_chunk = infile.read(64 * 1024)

            if len(input_chunk) == 0:
                # we have reached the end of the input file and it matches `% 16 == 0`
                # so pad it with 16 bytes of PKCS#7 padding:
                end_of_line = True
                input_chunk += 16 * chr(16)
            elif len(input_chunk) % 16 > 0:
                # we have reached the end of the input file and it doesn't match `% 16 == 0`
                # pad it by the remainder of bytes in PKCS#7:
                end_of_line = True
                input_chunk_remainder = 16 - (len(input_chunk) & 16)
                input_chunk += input_chunk_remainder * chr(input_chunk_remainder)

            # write out encrypted data and an HMAC of the block
            outfile.write(cipher.encrypt(input_chunk) + hmac.new(hmac_key, data, 
                    hashlib.sha256).digest())

            if end_of_line:
                break

簡単に言えば、これは入力ファイルを一度に 64KB のブロックで読み取り、これらのブロックを暗号化し、暗号化されたデータの SHA-256 を使用して HMAC を生成し、その HMAC を各ブロックの後に追加します。復号化は、64KB + 32B チャンクを読み取り、最初の 64KB の HMAC を計算し、それをチャンクの最後の 32 バイトを占める SHA-256 サムと比較することによって行われます。

これは HMAC を使用する正しい方法ですか? データが変更されておらず、正しいキーで復号化されているというセキュリティと認証が保証されますか?

参考までに、AES キーと HMAC キーはどちらも、入力テキストを SHA-512、次に bcrypt、次に SHA-512 で実行することによって生成される同じパスフレーズから派生しています。最終的な SHA-512 からの出力は、2 つのチャンクに分割されます。1 つは AES パスワードに使用され、もう 1 つは HMAC に使用されます。

4

2 に答える 2

6

はい、セキュリティ上の問題が 2 つあります。

しかし、最初に、最後に次のステートメントがあると仮定します。

# write out encrypted data and an HMAC of the block
outfile.write(cipher.encrypt(input_chunk) + hmac.new(hmac_key, data, hashlib.sha256).digest())

あなたは実際に意味しました:

# write out encrypted data and an HMAC of the block
data = cipher.encrypt(input_chunk)
outfile.write(data + hmac.new(hmac_key, data, hashlib.sha256).digest())

dataはどこにも定義されていないためです。

1 つ目のセキュリティ上の問題は、各ピースを他のピースとは独立して認証しているが、構成は認証していないことです。つまり、攻撃者はチャンクを再シャッフル、複製、または削除することができ、受信者は気付かないでしょう。

より安全なアプローチは、HMAC の 1 つのインスタンスのみを持ち、すべての暗号化されたデータをupdateメソッドを介してそれに渡し、最後に 1 つのダイジェストを出力することです。

または、ファイル全体を受信する前に受信者が改ざんを検出できるようにする場合は、各部分の中間 MAC を出力できます。実際、への呼び出しdigestは HMAC の状態を変更しません。update後で電話をかけ続けることができます。

2 番目のセキュリティ上の問題は、キーの派生にソルトを使用していないことです (ソルトを送信しないため、そう言います)。パスワード クラッキングとは別に、同じパスワードを使用して 2 つ以上のファイルを暗号化すると、HMAC キーが同じであるため、攻撃者は暗号化されたファイルのチャンクを自由に組み合わせることができます。解決策:塩を使用してください。

最後にもう 1 つ重要な点があります。返されるバイト数はバイトinfile.read(64 * 1024)未満になる場合がありますが、それはファイルの最後に到達したことを意味するものではありません64*1024

于 2013-02-22T23:37:49.257 に答える
-2

あなたが HMAC で行っていることにセキュリティ上の問題があるとは思いませんが (セキュリティに問題がないという意味ではありません)、HMAC サブ要素の実際の値はわかりません。暗号文はあなたを取得します。改ざんが発生した場合に平文の部分的な回復をサポートしたい場合を除き、完全な暗号文と比較して、64 KB ブロックの HMAC のオーバーヘッドが発生する理由はあまりありません。

キー生成の観点からは、パスフレーズから生成されたキーを使用してランダムに生成された 2 つのキーを暗号化し、ランダムに生成されたキーを使用して HMAC および AES 操作を実行する方が理にかなっています。ブロック暗号と HMAC の両方に同じ鍵を使用することが悪いニュースであることは知っていますが、同じ方法で生成された鍵を使用することが同様に悪いことかどうかはわかりません。

少なくとも、鍵導出メカニズムを微調整する必要があります。bcrypt はパスワード ハッシュ メカニズムであり、キー派生関数ではありません。キーの導出には PBKDF2 を使用する必要があります。

于 2013-02-22T23:14:56.237 に答える