199

メッセージとキーの2つのパラメーターを受け入れるPyCryptoを使用して、2つの関数を作成し、メッセージを暗号化/復号化しようとしています。

私は私を助けるためにウェブ上にいくつかのリンクを見つけました、しかしそれらのそれぞれには欠陥があります:

codekoalaのこれはos.urandomを使用していますが、これはPyCryptoによって推奨されていません。

さらに、私が関数に与えるキーは、期待される正確な長さを保証するものではありません。それを実現するために何ができますか?

また、いくつかのモードがありますが、どれをお勧めしますか?何を使うべきかわからない:/

最後に、IVとは正確には何ですか?暗号化と復号化に別のIVを提供できますか、それとも別の結果が返されますか?

編集:安全ではなかったため、コード部分を削除しました。

4

14 に答える 14

154

入力の長さが BLOCK_SIZE の倍数でない場合に、パディング (pad暗号化を行う場合) とパディングを解除する (復号化を行う場合)の 2 つの関数が必要になる場合があります。unpad

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
unpad = lambda s : s[:-ord(s[len(s)-1:])]

それで、キーの長さを尋ねていますか?キーを直接使用するのではなく、キーの md5sum を使用できます。

さらに、PyCrypto を使用した私の小さな経験によると、IV は入力が同じ場合に暗号化の出力を混同するために使用されるため、IV はランダムな文字列として選択され、暗号化出力の一部として使用されます。それを使用してメッセージを復号化します。

そして、これが私の実装です。それがあなたにとって役立つことを願っています:

import base64
from Crypto.Cipher import AES
from Crypto import Random

class AESCipher:
    def __init__( self, key ):
        self.key = key

    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) ) 

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        iv = enc[:16]
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] ))
于 2012-09-21T06:12:54.457 に答える
6

SHA-1 や SHA-256 のような暗号化ハッシュ関数 ( Python のビルトインではない)を使用して、任意のパスワードからパスフレーズを取得できます。hashPython には、標準ライブラリで両方のサポートが含まれています。

import hashlib

hashlib.sha1("this is my awesome password").digest() # => a 20 byte string
hashlib.sha256("another awesome password").digest() # => a 32 byte string

[:16]orを使用するだけで暗号化ハッシュ値を切り捨てることができ、[:24]指定した長さまでセキュリティを保持します。

于 2012-09-21T06:08:30.607 に答える
5

他の人のために、@Cyril と @Marcus の回答を組み合わせて得た復号化の実装を次に示します。これは、encryptedText が引用され、base64 でエンコードされた HTTP リクエストを介してこれが受信されることを前提としています。

import base64
import urllib2
from Crypto.Cipher import AES


def decrypt(quotedEncodedEncrypted):
    key = 'SecretKey'

    encodedEncrypted = urllib2.unquote(quotedEncodedEncrypted)

    cipher = AES.new(key)
    decrypted = cipher.decrypt(base64.b64decode(encodedEncrypted))[:16]

    for i in range(1, len(base64.b64decode(encodedEncrypted))/16):
        cipher = AES.new(key, AES.MODE_CBC, base64.b64decode(encodedEncrypted)[(i-1)*16:i*16])
        decrypted += cipher.decrypt(base64.b64decode(encodedEncrypted)[i*16:])[:16]

    return decrypted.strip()
于 2013-05-16T18:18:39.770 に答える
5

CryptoPyCryptodomexライブラリの両方を使用しましたが、非常に高速です...

import base64
import hashlib
from Cryptodome.Cipher import AES as domeAES
from Cryptodome.Random import get_random_bytes
from Crypto import Random
from Crypto.Cipher import AES as cryptoAES

BLOCK_SIZE = AES.block_size

key = "my_secret_key".encode()
__key__ = hashlib.sha256(key).digest()
print(__key__)

def encrypt(raw):
    BS = cryptoAES.block_size
    pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
    raw = base64.b64encode(pad(raw).encode('utf8'))
    iv = get_random_bytes(cryptoAES.block_size)
    cipher = cryptoAES.new(key= __key__, mode= cryptoAES.MODE_CFB,iv= iv)
    a= base64.b64encode(iv + cipher.encrypt(raw))
    IV = Random.new().read(BLOCK_SIZE)
    aes = domeAES.new(__key__, domeAES.MODE_CFB, IV)
    b = base64.b64encode(IV + aes.encrypt(a))
    return b

def decrypt(enc):
    passphrase = __key__
    encrypted = base64.b64decode(enc)
    IV = encrypted[:BLOCK_SIZE]
    aes = domeAES.new(passphrase, domeAES.MODE_CFB, IV)
    enc = aes.decrypt(encrypted[BLOCK_SIZE:])
    unpad = lambda s: s[:-ord(s[-1:])]
    enc = base64.b64decode(enc)
    iv = enc[:cryptoAES.block_size]
    cipher = cryptoAES.new(__key__, cryptoAES.MODE_CFB, iv)
    b=  unpad(base64.b64decode(cipher.decrypt(enc[cryptoAES.block_size:])).decode('utf8'))
    return b

encrypted_data =encrypt("Hi Steven!!!!!")
print(encrypted_data)
print("=======")
decrypted_data = decrypt(encrypted_data)
print(decrypted_data)
于 2019-07-25T07:26:53.720 に答える
3

遅くなりましたが、とても参考になると思います。PKCS#7 パディングのような使用スキームについては誰も言及していません。パディング (暗号化を行う場合) およびアンパディング (復号化を行う場合) の前の関数の代わりに使用できます。以下の完全なソース コードを提供します。

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
import pkcs7
class Encryption:

    def __init__(self):
        pass

    def Encrypt(self, PlainText, SecurePassword):
        pw_encode = SecurePassword.encode('utf-8')
        text_encode = PlainText.encode('utf-8')

        key = hashlib.sha256(pw_encode).digest()
        iv = Random.new().read(AES.block_size)

        cipher = AES.new(key, AES.MODE_CBC, iv)
        pad_text = pkcs7.encode(text_encode)
        msg = iv + cipher.encrypt(pad_text)

        EncodeMsg = base64.b64encode(msg)
        return EncodeMsg

    def Decrypt(self, Encrypted, SecurePassword):
        decodbase64 = base64.b64decode(Encrypted.decode("utf-8"))
        pw_encode = SecurePassword.decode('utf-8')

        iv = decodbase64[:AES.block_size]
        key = hashlib.sha256(pw_encode).digest()

        cipher = AES.new(key, AES.MODE_CBC, iv)
        msg = cipher.decrypt(decodbase64[AES.block_size:])
        pad_text = pkcs7.decode(msg)

        decryptedString = pad_text.decode('utf-8')
        return decryptedString

import StringIO
import binascii


def decode(text, k=16):
    nl = len(text)
    val = int(binascii.hexlify(text[-1]), 16)
    if val > k:
        raise ValueError('Input is not padded or padding is corrupt')

    l = nl - val
    return text[:l]


def encode(text, k=16):
    l = len(text)
    output = StringIO.StringIO()
    val = k - (l % k)
    for _ in xrange(val):
        output.write('%02x' % val)
    return text + binascii.unhexlify(output.getvalue())

于 2016-11-19T00:11:56.963 に答える