Python Encrypting with PyCrypto AES

匿名 (未验证) 提交于 2019-12-03 02:27:02

问题:

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:])

回答1:

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).



回答2:

from hashlib import md5 from Crypto.Cipher import AES from Crypto import Random import base64  def derive_key_and_iv(password, salt, key_length, iv_length):     d = d_i = ''     while len(d) < key_length + iv_length:         d_i = md5(d_i + password + salt).digest()         d += d_i     return d[:key_length], d[key_length:key_length+iv_length]  def encrypt(in_file, out_file, password, key_length=32):     bs =        
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!