10

Pythonでテキストを暗号化および復号化しようとしていますが、その方法を知っています-問題は、16や32のような一定量の文字を使用する必要がないことです。使用できるようにしたい必要な数の文字/数字を入力してから、エラーなしでテキストを暗号化します。

私はそれを行うことができるので、pythonのbase64は完璧ですが、やりたいときは:

password = "password"
encode = base64.b64encode(password)

...バイト単位ではないため、エラーが返されます。次のようにする必要があります。

encode = base64.b64encode(b'password')

それは完全にうまくいきますが、私はそれをしたくありません。

import base64

password = "hello world"  
encoded = base64.b64encode(password.encode("utf-8"))
print(encoded)
decoded = base64.b64decode(encoded)
print(decoded)

それが私のコードであり、正常に動作しますが、AESの使用方法について知る必要がある間違ったタイプのものを使用していたことがわかります。

4

1 に答える 1

28

Python 3 では、文字列をバイトに変換する必要があります。これは、base64 エンコーディングが文字列のエンコーディングに依存し、Python 3 が文字列エンコーディングについて想定していないためです。この質問を参照してください。

import base64

# Assuming UTF-8 encoding, change to something else if you need to
base64.b64encode("password".encode("utf-8"))

このページでは、Python 3 で文字列の動作が異なる理由について説明します。

2.x の状況との最大の違いは、Python 3.0 でテキストとデータを混在させようとすると TypeError が発生することですが、Python 2.x で Unicode と 8 ビット文字列を混在させようとすると、8 ビットがstring にはたまたま 7 ビット (ASCII) バイトしか含まれていませんでしたが、非 ASCII 値が含まれていると UnicodeDecodeError が返されます。この価値固有の行動は、長年にわたって多くの悲しい顔を引き起こしてきました.

そして、sberry が言ったように、base64 エンコーディングは暗号化ではありません。実際にこれを安全にしたい場合は、AES などを使用する必要があります。パスワードを安全に保存したい場合は、bcrypt または PBKDF2 を使用してください。


PBKDF2 を使用してパスワードから派生したキーを使用して、 PyCrypto を使用して AES で何か暗号化する例を次に示します。

#!/usr/bin/env python3

from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Protocol.KDF import PBKDF2

def make_key(password, salt = None):
    if salt is None:
        # Generate a key from the password
        salt = Random.new().read(8)

    # You probably want to adjust the number of iterations
    # based on your target platform and willingness to wait.
    # Somewhere around 10,000 will give you reasonable security.
    # If you don't mind the wait, 100,000 is better.
    # If you have a really fast computer, or are willing to wait a long
    # time, feel free to set it even higher.
    key = PBKDF2(password, salt, AES.block_size, 100000)
    return (key, salt)

def encrypt(message, key):
    # The IV should always be random
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    ciphertext = cipher.encrypt(message.encode("utf-8"))
    return (ciphertext, iv)

def decrypt(ciphertext, key, iv):
    cipher = AES.new(key, AES.MODE_CFB, iv)
    msg = cipher.decrypt(ciphertext).decode("utf-8")
    return msg

def main():
    # Encryption
    password = "correct horse battery staple"
    message = "Super secret information that shouldn't be seen by attackers"
    key, salt = make_key(password)
    ciphertext, iv = encrypt(message, key)
    print(b"The ciphertext is: " + ciphertext)

    # Decryption

    # In normal cases, you now need to store the salt and iv somewhere
    # Usually you prepend them to the ciphertext
    # I don't feel like doing that, so we'll just assume that I got the salt
    # and IV somehow.
    key, _ = make_key(password, salt)
    cleartext = decrypt(ciphertext, key, iv)
    print("The cleartext is: " + cleartext)

if __name__ == "__main__":
    main()

このように AES を使用するだけで、機密性(攻撃者はパスワードなしでメッセージを読み取ることができません) は提供されますが、整合性は提供されません(攻撃者は暗号文にデータを挿入することができます。唯一の方法は、それがおそらくガベージとして復号化されることです)。 . これを防ぐために、メッセージ認証コードを使用して、パスワードを持っていない人が暗号文を変更していないことを確認することもできます。


これは興味深い演習だと思ったので、より完全な例をBitBucket repoに入れました。HMAC を追加し、JSON ファイルから読み書きします。

于 2013-05-24T17:15:06.397 に答える