使用 PyCrypto AES 进行 Python 加密 [英] Python Encrypting with PyCrypto AES

查看:43
本文介绍了使用 PyCrypto AES 进行 Python 加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天刚发现 pycrypto,我一直在研究我的 AES 加密类.不幸的是,它只起作用了一半.self.h.md5 以十六进制格式输出 md5 哈希,并且是 32 字节.这是输出.它似乎解密了消息,但它在解密后放置了随机字符,在这种情况下\n\n\n...我想我对 self.data 的块大小有问题,有人知道如何解决这个问题吗?<块引用>

Jans-MacBook-Pro:test2 jan$ ../../bin/python3 data.pyb'RLfGmn5jf5WTJphnmW0hXG7IaIYcCRpjaTTqwXR6yiJCUytnDib+GQYlFORm+jIctest1 2 3 4 5 结束测试\n\n\n\n\n\n\n\n\n\n'

from Crypto.Cipher import AES从 base64 导入 b64encode, b64decode从 os 导入 urandom类加密():def __init__(self):self.h = Hash()定义值(自我,数据,键):self.data = 数据self.key = 键self.mode = AES.MODE_CBCself.iv = urandom(16)如果不是 self.key:self.key = Cfg_Encrypt_Keyself.key = self.h.md5(self.key, True)def 加密(自我,数据,密钥):self.values(数据,键)返回 b64encode(self.iv + AES.new(self.key, self.mode, self.iv).encrypt(self.data))def解密(自我,数据,密钥):self.values(数据,键)self.iv = b64decode(self.data)[:16]返回 AES.new(self.key, self.mode, self.iv).decrypt(b64decode(self.data)[16:])

解决方案

老实说,字符 "\n\n\n\n\n\n\n\n\n\n" 在我看来不要那么随意.;-)

您在 CBC 模式下使用 AES.这要求明文和密文的长度始终是 16 字节的倍数.使用您显示的代码,您实际上应该看到当 data 传递给 encrypt() 不满足此类条件时引发的异常.看起来您添加了足够多的新行字符('\n' 到任何输入,直到纯文本碰巧对齐.

除此之外,还有两种常见的方法可以解决对齐问题:

  1. 从 CBC (AES.MODE_CBC) 切换到 CFB (AES.MODE_CFB).使用 PyCrypto 使用的默认 segment_size,您将不会对明文和密文长度有任何限制.

  2. 保留 CBC 并使用像 PKCS#7 这样的填充方案,即:

    • 在加密 X 字节的明文之前,将尽可能多的字节附加到后面以达到下一个 16 字节边界.所有填充字节都具有相同的值:您要添加的字节数:

      length = 16 - (len(data) % 16)数据 += 字节([长度])*长度

      那是 Python 3 风格.在 Python 2 中,您将:

      length = 16 - (len(data) % 16)数据 += 字符(长度)*长度

    • 解密后,从明文后面去掉padding表示的字节数:

      data = data[:-data[-1]]

尽管我理解在您的情况下这只是课堂练习,但我想指出的是,在没有任何形式的身份验证(例如 MAC)的情况下发送数据是不安全的.

I just found pycrypto today, and I've been working on my AES encryption class. Unfortunately it only half-works. self.h.md5 outputs md5 hash in hex format, and is 32byte. This is the output. It seems to decrypt the message, but it puts random characters after decryption, in this case \n\n\n... I think I have a problem with block size of self.data, anyone know how to fix this?

Jans-MacBook-Pro:test2 jan$ ../../bin/python3 data.py b'RLfGmn5jf5WTJphnmW0hXG7IaIYcCRpjaTTqwXR6yiJCUytnDib+GQYlFORm+jIctest 1 2 3 4 5 endtest\n\n\n\n\n\n\n\n\n\n'

from Crypto.Cipher import AES
from base64 import b64encode, b64decode
from os import urandom

class Encryption():
    def __init__(self):
        self.h = Hash()

    def values(self, data, key):
        self.data = data
        self.key = key
        self.mode = AES.MODE_CBC
        self.iv = urandom(16)
        if not self.key:
            self.key = Cfg_Encrypt_Key
        self.key = self.h.md5(self.key, True)

    def encrypt(self, data, key):
        self.values(data, key)
        return b64encode(self.iv + AES.new(self.key, self.mode, self.iv).encrypt(self.data))

    def decrypt(self, data, key):
        self.values(data, key)
        self.iv = b64decode(self.data)[:16]
        return AES.new(self.key, self.mode, self.iv).decrypt(b64decode(self.data)[16:])

解决方案

To be honest, the characters "\n\n\n\n\n\n\n\n\n\n" don't look that random to me. ;-)

You are using AES in CBC mode. That requires length of plaintext and ciphertext to be always a multiple of 16 bytes. With the code you show, you should actually see an exception being raised when data passed to encrypt() does not fulfill such condition. It looks like you added enough new line characters ('\n' to whatever the input is until the plaintext happened to be aligned.

Apart from that, there are two common ways to solve the alignment issue:

  1. Switch from CBC (AES.MODE_CBC) to CFB (AES.MODE_CFB). With the default segment_size used by PyCrypto, you will not have any restriction on plaintext and ciphertext lengths.

  2. Keep CBC and use a padding scheme like PKCS#7, that is:

    • before encrypting a plaintext of X bytes, append to the back as many bytes you need to to reach the next 16 byte boundary. All padding bytes have the same value: the number of bytes that you are adding:

      length = 16 - (len(data) % 16)
      data += bytes([length])*length
      

      That's Python 3 style. In Python 2, you would have:

      length = 16 - (len(data) % 16)
      data += chr(length)*length
      

    • after decrypting, remove from the back of the plaintext as many bytes as indicated by padding:

      data = data[:-data[-1]]
      

Even though I understand in your case it is just a class exercise, I would like to point out that it is insecure to send data without any form of authentication (e.g. a MAC).

这篇关于使用 PyCrypto AES 进行 Python 加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆