Encryption/Decryption using AES/CBC/PKCS7Padding [

2020-04-02 07:00发布

I need help in encrypting with AES/CBC/PKCS7Padding. I need the same results like here.

1条回答
Evening l夕情丶
2楼-- · 2020-04-02 07:42

Here's how to do this task using the popular cryptography library. This code was adapted from their documentation. It uses the data, key, and IV that were initially given in the question.

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
from base64 import b64decode, b64encode

backend = default_backend()
padder = padding.PKCS7(128).padder()
unpadder = padding.PKCS7(128).unpadder()

data = b'demo'
data = padder.update(data) + padder.finalize()
key = b64decode('HJkPmTz+uY7wd0p1+w//DABgbvPq9/230RwEG2sJ9mo=')
iv = b64decode('AAAAAAAAAAAAAAAAAAAAAA==')

cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()
ct = encryptor.update(data) + encryptor.finalize()
ct_out = b64encode(ct)
print(ct_out)

decryptor = cipher.decryptor()
plain = decryptor.update(ct) + decryptor.finalize()
plain = unpadder.update(plain) + unpadder.finalize()
print(plain)

output

b'W2FEImF2qrAjaJ/LV+bgQA=='
b'demo'

Just for fun, here's an implementation that requires no 3rd-party packages. Normally, one wouldn't do this sort of thing, since the first rule of crypto is "Don't roll your own crypto!". But here's some AES code I wrote as part of the Cryptopals challenge. ;) It does AES ECB encoding by directly calling the standard OpenSSL library via ctypes, and then uses that to perform CBC encryption / decryption.

This code was developed and tested on a Linux system running Python 3.6.0, but it should also run on Windows. I assume it will also run correctly on OSX.

import os
from base64 import b64decode, b64encode
from ctypes import *

AES_MAXNR = 14
AES_BLOCK_SIZE = 16

DECODE = 0
ENCODE = 1

class AES_KEY(Structure):
    _fields_ = [
        ("rd_key", c_long * 4 *(AES_MAXNR + 1)),
        ("rounds", c_int),
    ]

crypto = cdll.LoadLibrary("libeay32.dll" if os.name == "nt" else "libssl.so")

# Function prototypes
AES_set_encrypt_key = crypto.AES_set_encrypt_key
AES_set_encrypt_key.restype = c_int
# userKey, bits, key
AES_set_encrypt_key.argtypes = [c_char_p, c_int, POINTER(AES_KEY)]

AES_set_decrypt_key = crypto.AES_set_decrypt_key
AES_set_decrypt_key.restype = c_int
# userKey, bits, key
AES_set_decrypt_key.argtypes = [c_char_p, c_int, POINTER(AES_KEY)]

AES_ecb_encrypt = crypto.AES_ecb_encrypt
AES_ecb_encrypt.restype = None
#in, out, key, enc(1=encode, 0=decode) 
AES_ecb_encrypt.argtypes = [c_char_p, c_char_p, POINTER(AES_KEY), c_int]

set_key = (AES_set_decrypt_key, AES_set_encrypt_key)

def set_aes_key(key, encode):
    ''' Create an AES encoding or decoding key '''
    keylen = len(key)
    valid = {16, 24, 32}
    if keylen not in valid:
        msg = f'Key length must be one of {valid}, not {keylen}'
        raise ValueError(msg)

    aes_key = AES_KEY()
    rc = set_key[encode](c_char_p(key), keylen * 8, byref(aes_key))
    if rc != 0:
        # I don't think we can get here...
        raise ValueError('Error generating AES key', rc)
    return aes_key

def aes_ecb(block, aes_key, encode):
    ''' Encrypt or decrypt a single block '''
    outbuff = create_string_buffer(AES_BLOCK_SIZE)
    AES_ecb_encrypt(c_char_p(block), outbuff, byref(aes_key), encode)
    return outbuff.raw

def PKCS7_pad(data):
    padsize = AES_BLOCK_SIZE - len(data) % AES_BLOCK_SIZE
    return data + bytes([padsize]) * padsize

def PKCS7_unpad(data):
    offset = data[-1]
    return data[:-offset]

def xor_bytes(a, b):
    size = len(a)
    a = int.from_bytes(a, 'big')
    b = int.from_bytes(b, 'big')
    return (a ^ b).to_bytes(size, 'big')

def aes_cbc_encode(data, key, iv):
    ekey = set_aes_key(key, ENCODE)

    data = PKCS7_pad(data)
    cipher = []
    for block in zip(*[iter(data)] * AES_BLOCK_SIZE):
        block = bytes(block)
        coded = aes_ecb(xor_bytes(iv, block), ekey, ENCODE)
        cipher.append(coded)
        iv = coded

    return b''.join(cipher)

def aes_cbc_decode(data, key, iv):
    dkey = set_aes_key(key, DECODE)

    plain = []
    for block in zip(*[iter(data)] * AES_BLOCK_SIZE):
        block = bytes(block)
        decoded = aes_ecb(block, dkey, DECODE)
        plain.append(xor_bytes(iv, decoded))
        iv = block

    plain[-1] = PKCS7_unpad(plain[-1])
    return b''.join(plain)

# Test

data = b'demo'
key = b64decode('HJkPmTz+uY7wd0p1+w//DABgbvPq9/230RwEG2sJ9mo=')
iv = b64decode('AAAAAAAAAAAAAAAAAAAAAA==')
cipher = aes_cbc_encode(data, key, iv)
out = b64encode(cipher)
print(out)

plain = aes_cbc_decode(cipher, key, iv)
print(plain)

output

b'W2FEImF2qrAjaJ/LV+bgQA=='
b'demo'
查看更多
登录 后发表回答