在 Python 中实现 AES/ECB/PKCS5 填充

我正在尝试实现一个 python 程序来使用 AES/ECB/PKCS5 填充来加密纯文本。我得到的输出与预期略有不同。


Python3程序:


import base64

from Crypto.Cipher import AES


 

def add_to_16(value):

    while len(value) % 16 != 0:

        value += '\0'

    return str.encode (value) # returns bytes

 


# Encryption method

def encrypt(text):

         # Secret key 

    key='92oifgGh893*cj%7' 


         # Text to be encrypted

         # Initialize encryptor

    aes = AES.new(key, AES.MODE_ECB) 


         # Aes encryption to be

    encrypt_aes = aes.encrypt(add_to_16(text)) 


         # Converted into a string with base64

    encrypted_text = str(base64.encodebytes (encrypt_aes), encoding = 'utf-8')


    print(encrypted_text)

    return encrypted_text


if __name__ == '__main__': 


    text = '{  "Message": "hello this is a plain text" , "user":"john.doe", "Email":"john.doe@example.com}'

    entrypted_text = encrypt(text)


上述程序的输出是:


oo8jwHQNQnBwVUsJ5piShFRM3PFFIfULwcoFOEQhPMTAvexSr6eE9aFLVQTpAKBFkGi8vNbtScvyexSxHBlwVapJ5Szz1JPR9q9cHHJYYMzGocln4TRPFQ6S3e8jjVud

使用第三方工具在线验证时,结果为:


oo8jwHQNQnBwVUsJ5piShFRM3PFFIfULwcoFOEQhPMTAvexSr6eE9aFLVQTpAKBFkGi8vNbtScvyexSxHBlwVapJ5Szz1JPR9q9cHHJYYMwnIIuNCUVn/IExpxebqXV1

有人可以指导我哪里做错了吗?


当年话下
浏览 473回答 5
5回答

慕雪6442864

这是完整的代码,以防有人仍在寻找。测试针对:python3.6python3.8** 使用pycryptodomeencrypt_aes.pyimport hashlibfrom Crypto.Cipher import AESimport base64 class AES_pkcs5:    def __init__(self,key:str, mode:AES.MODE_ECB=AES.MODE_ECB,block_size:int=16):        self.key = self.setKey(key)        self.mode = mode        self.block_size = block_size    def pad(self,byte_array:bytearray):        """        pkcs5 padding        """        pad_len = self.block_size - len(byte_array) % self.block_size        return byte_array + (bytes([pad_len]) * pad_len)        # pkcs5 - unpadding     def unpad(self,byte_array:bytearray):        return byte_array[:-ord(byte_array[-1:])]    def setKey(self,key:str):        # convert to bytes        key = key.encode('utf-8')        # get the sha1 method - for hashing        sha1 = hashlib.sha1        # and use digest and take the last 16 bytes        key = sha1(key).digest()[:16]        # now zero pad - just incase        key = key.zfill(16)        return key    def encrypt(self,message:str)->str:        # convert to bytes        byte_array = message.encode("UTF-8")        # pad the message - with pkcs5 style        padded = self.pad(byte_array)        # new instance of AES with encoded key        cipher = AES.new(self.key, AES.MODE_ECB)        # now encrypt the padded bytes        encrypted = cipher.encrypt(padded)        # base64 encode and convert back to string        return base64.b64encode(encrypted).decode('utf-8')    def decrypt(self,message:str)->str:        # convert the message to bytes        byte_array = message.encode("utf-8")        # base64 decode        message = base64.b64decode(byte_array)        # AES instance with the - setKey()        cipher= AES.new(self.key, AES.MODE_ECB)        # decrypt and decode        decrypted = cipher.decrypt(message).decode('utf-8')        # unpad - with pkcs5 style and return         return self.unpad(decrypted)        if __name__ == '__main__':    # message to encrypt     message = 'hello world'    secret_key = "65715AC165715AC165715AC165715AC1"    AES_pkcs5_obj = AES_pkcs5(secret_key)        encrypted_message = AES_pkcs5_obj.encrypt(message)    print(encrypted_message)    decrypted_message = AES_pkcs5_obj.decrypt(encrypted_message)    print(decrypted_message)输出:>>> python encrypt_aes.py>>> PDhIFEVqLrJiZQC90FPHiQ== # encrypted message>>> hello world # and the decrypted one我已经测试了许多已经可用的代码,但没有一个提供像 java 那样的精确加密。所以,这是所有找到的博客和早期编写的与 python2 兼容的代码的组合

BIG阳

我已经用下面的代码构建了 PKCS5 填充,并且按预期工作。block_size=16pad = lambda s: s + (block_size - len(s) % block_size) * chr(block_size - len(s) % block_size)加密方法重写如下:def encrypt(plainText,key):        aes = AES.new(key, AES.MODE_ECB)        encrypt_aes = aes.encrypt(pad(plainText))       encrypted_text = str(base64.encodebytes (encrypt_aes), encoding = 'utf-8')    return encrypted_text

SMILET

PKCS 5(或7)填充不是添加0个字节,而是添加一个c字节with valuec&nbsp;(where1 <= c <= 16&nbsp;) if you're c`字节,短于块长度倍数。因此,如果您已经有 16 的倍数,请添加完整的 16 个字节的值 16,并且如果您的最后一个块是“停止”(4 个字节),我们将添加 12 个字节的值(十六进制的 12)来填充该块0xc。ETC。这样,接收者(在解密最终块之后)可以检查最后一个字节c并检查该值是否为1 <= c <= 16(如果不是,则拒绝解密),然后检查最后一个c字节确实都是相同的值,然后将它们从解密。这样,接收方不必猜测最后一个块的多少字节只是填充或实际上是纯文本的一部分。以 PKCS 方式执行此操作是明确的。我将把编码留给你。

慕哥6287543

您可以使用aes-pkcs5包。我是作者,它使用cryptography包而不是pycrypto其他答案中使用的过时的包,并且与 Python 3.7+ 兼容。您可以通过 pip 安装:pip&nbsp;install&nbsp;aes-pkcs5您使用以下方式发布的相同代码aes-pkcs5:from aes_pkcs5.algorithms.aes_ecb_pkcs5_padding import AESECBPKCS5Paddingkey = "92oifgGh893*cj%7"cipher = AESECBPKCS5Padding(key, "b64")text = '{&nbsp; "Message": "hello this is a plain text" , "user":"john.doe", "Email":"john.doe@example.com}'encrypted_text = cipher.encrypt(text)

繁花不似锦

有时,您可以使用由空字节分隔的随机字符串进行填充,以添加一点随机性。import randomimport stringfrom Crypto.Cipher import AESNULL_BYTE = '\x00'def random_string(size: int) -> str:&nbsp; &nbsp; return ''.join([&nbsp; &nbsp; &nbsp; &nbsp; random.choice(string.printable) for _ in range(size)&nbsp; &nbsp; ])def encode_aes(value: str, key: str) -> bytes:&nbsp; &nbsp; cipher = AES.new(key[:32], AES.MODE_ECB)&nbsp; &nbsp; mod = len(value) % cipher.block_size&nbsp; &nbsp; padding = (cipher.block_size - mod) % cipher.block_size&nbsp; &nbsp; if padding > 0:&nbsp; &nbsp; &nbsp; &nbsp; value += NULL_BYTE + random_string(padding - 1)&nbsp; &nbsp; return cipher.encrypt(value)def decode_aes(value: bytes, key: str) -> str:&nbsp; &nbsp; cipher = AES.new(key[:32], AES.MODE_ECB)&nbsp; &nbsp; decrypted = cipher.decrypt(value).decode('utf8')&nbsp; &nbsp; return decrypted.rsplit(NULL_BYTE, 1)[0]
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python