3

Pyramid 1.3(Python 2.7)を使用し、MySQLにデータを保存するプロジェクトに取り組んでいます。メールアドレスのテーブルがあり、保存用に暗号化したいと思います。アプリケーションで暗号化しようとしていますが、復号化して表示します。私は完全なセキュリティを求めるつもりはありませんが、データベース自体が危険にさらされた場合にデータを十分に難読化することを主な目的としています。

私はAESでPyCryptoを使用しており、ここのいくつかの投稿と私が見つけたいくつかのWebチュートリアルをフォローしようとしています。私がこれまでに見つけた最も近いものはこの投稿であり、少なくともそれを暗号化することで機能しているようです。"7hBAQrWhJRnL9YdBGJfRErGFwGi3aC6noGzYTrGwAoQ="私はそれに従い、データベースに保存されているようなものを取得します。しかし、復号化機能はこれでエラーを出し続けます:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa1 in position 1: ordinal not in range(128)

Pythonに関するUnicodeプレゼンテーションに出くわしました。これは、Pythonをより理解するのに役立ちましたが、それでも同じエラーが発生し続けます。

エンコード、データベースへの保存、データベースからの引き出し、およびソースデータ文字列のデコードの方法に関する簡単なチュートリアルはありますか?

データベース列に特定の照合が必要ですか?フィールドは特定のタイプである必要がありますか?これまで、文字列を格納していると仮定して、デフォルトの照合を使用し、それをVARCHARに設定してきました。互換性のないタイプなどでエンコーディングの問題が発生しているようですが、何かを変更する必要がある場所で頭が回転しています。

より良いポインタまたは私が提供できる他のものはありますか?コードを表示することはできますが、基本的には上記のリンクのコピーです...変更しすぎる前に、概念実証が機能するようにしようとしていました。

編集:いくつかのサンプルソース... MySQLでは、テーブルはid(int)client_id(int)emailaddress varchar(100)utf8mb4_general_ci(私は照合をいじっていますが、それがどうあるべきかわかりません!)

Python:

from base64 import b64encode, b64decode, urlsafe_b64decode, urlsafe_b64encode

BLOCK_SIZE = 32
INTERRUPT = u'\u0001'
PAD = u'\u0000'
def AddPadding(data, interrupt, pad, block_size):
    new_data = ''.join([data, interrupt])
    new_data_len = len(new_data)
    remaining_len = block_size - new_data_len
    to_pad_len = remaining_len % block_size
    pad_string = pad * to_pad_len
    return ''.join([new_data, pad_string])
def StripPadding(data, interrupt, pad):
    return data.rstrip(pad).rstrip(interrupt)#data.rsplit(interrupt,1)[0]#rstrip(pad).rstrip(interrupt)

SECRET_KEY = u'a1b2c3d4e5f6g7h8a1b2c3d4e5f6g7h8'
IV = u'12345678abcdefgh'

cipher_for_encryption = AES.new(SECRET_KEY, AES.MODE_CBC, IV)
cipher_for_decryption = AES.new(SECRET_KEY, AES.MODE_CBC, IV)

def EncryptWithAES(encrypt_cipher, plaintext_data):
    plaintext_padded = AddPadding(plaintext_data, INTERRUPT, PAD, BLOCK_SIZE)
    encrypted = encrypt_cipher.encrypt(plaintext_padded)
    return urlsafe_b64encode(encrypted)
def DecryptWithAES(decrypt_cipher, encrypted_data):
    decoded_encrypted_data = urlsafe_b64decode(encrypted_data)
    decrypted_data = decrypt_cipher.decrypt(decoded_encrypted_data)
    return StripPadding(decrypted_data, INTERRUPT, PAD)

#encrypts it
posted_singleaddress = EncryptWithAES(cipher_for_encryption, posted_singleaddress)

#"me@mail.com" inserts "Ktpr49Uzn99HZXbmqEzGKlWo9wk-XBMXGZl_iyna-8c=" into the database

clientemailsは、上の表のメールのリストです。コメントを外すとエラーが発生します。

#if clientemails:
#    decrypted = DecryptWithAES(cipher_for_decryption, clientemails[0].emailaddress)

私はそれを機能させるために最初のアイテムをデコードしようとしていましたが、それは今それを適合させているように見える部分です....

4

1 に答える 1

2

PyCryptoの一般的な規則では、暗号化キー、IV、プレーンテキスト、パディング、および暗号文は、テキストではなく、常にバイナリ文字列として定義する必要があります。それらにUnicodeを使用しているという事実は、それ自体が問題の原因です。

もう1つの問題はAES.new、16進エンコード形式でキーとIVに渡すため、前者は256ビット、後者は128ビットになることです。それはまだ機能しているようですが、あなたの意図は128ビットキーを持つAES128を使用することだったと思います。したがって、たとえば次のようにバイナリに変換する必要がありますunhexlify。2文字の文字列b'34'は1バイトの'\x34'にマップされます。IVは2倍の長さである必要があります。

したがって、コードでは次のようにすることをお勧めします。

from binascii import unhexlify

INTERRUPT = b'\x01'
PAD = b'\x00'
SECRET_KEY = unhexlify('a1b2c3d4e5f6g7h8a1b2c3d4e5f6g7h8')
IV = unhexlify('12345678abcdefgh'*2)

テキストを暗号化する必要がある場合は、最初にテキストをエンコードして(たとえば、UTF-8に)、次に関数に渡しますEncryptWithAES()PyCryptoAPIから取得した次の例も参照してください。

from Crypto.Cipher import AES
from Crypto import Random

key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')

暗号化ステップ(つまり、暗号文)の結果も、バイナリ文字列になります。MySQL DBに直接保存するには、BINARYa列またはVARBINARYtype列のいずれかを使用する必要があります。

于 2013-02-06T22:02:39.450 に答える