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 ファイルから読み書きします。