使用AES / CBC / PKCS7Padding进行加密/解密

时间:2018-04-27 12:42:22

标签: php android python encryption cryptography

我需要帮助加密AES / CBC / PKCS7Padding。我需要像here一样的结果。

1 个答案:

答案 0 :(得分:1)

以下是使用常用cryptography库执行此任务的方法。此代码是根据他们的文档改编的。它使用最初在问题中给出的数据,密钥和IV。

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)

<强>输出

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

只是为了好玩,这是一个不需要第三方软件包的实现。 通常情况下,人们不会这样做,因为加密的第一条规则是“不要滚动你自己的加密!”。但是这里有一些我编写的AES代码作为Cryptopals挑战的一部分。 ;)它通过ctypes直接调用标准OpenSSL库来进行AES ECB编码,然后使用它来执行CBC加密/解密。

此代码是在运行Python 3.6.0的Linux系统上开发和测试的,但它也应该在Windows上运行。我假设它也可以在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)

<强>输出

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