Crypto module use

Introduction to AES

  • Advanced Encryption Standard (English: Advanced Encryption Standard, abbreviation: AES), also known as Rijndael encryption in cryptography, is a block encryption standard adopted by the US federal government. This standard is used to replace the original DES, which has been analyzed by many parties and is widely used all over the world. After five years of selection process, the Advanced Encryption Standard was published by the National Institute of Standards and Technology (NIST) in FIPS PUB 197 on November 26, 2001, and became an effective standard on May 26, 2002. In 2006, the Advanced Encryption Standard has become one of the most popular algorithms in symmetric key encryption.

  • There are three types of AES encryption: AES-128, AES-192, and AES-256, corresponding to the three key lengths: 128bits (16 bytes), 192bits (24 bytes), and 256bits (32 bytes). Of course, the longer the key, the higher the security, and the longer it takes for encryption and decryption. The default is AES-128, its security is completely sufficient.

  • The AES algorithm is the most common symmetric encryption algorithm (this encryption algorithm is used for WeChat applet encrypted transmission). The symmetric encryption algorithm uses the same key for encryption and decryption. The specific encryption process is as follows:
    Insert picture description here

AES is just a basic algorithm. There are several modes to implement AES, mainly ECB, CBC, CFB and OFB (in fact, there is a CTR):

  1. ECB mode (Electronic codebook mode: Electronic codebook)
    ECB is the simplest block cipher encryption mode. Before encryption, it is divided into several blocks according to the encryption block size (for example, AES is 128 bits), and then each block is encrypted separately with the same key. The same is true for decryption.

  2. CBC mode (Cipher-block chaining) In
    CBC mode, each cipher block to be encrypted will be XORed with the ciphertext of the previous cipher block before being encrypted, and then encrypted with an encryptor. The first plaintext block is XORed with a data block called the initialization vector.

  3. CFB mode (Cipher feedback)
    and ECB and CBC modes can only encrypt block data. CFB can convert block cipher text (Block Cipher) into stream cipher text (Stream Cipher).

  4. OFB mode (Output feedback)
    OFB uses a block cipher to generate a key stream (Keystream), and then XORs the key stream with the plaintext stream to obtain a ciphertext stream. Decryption is to use the block cipher to generate the key first. Stream, and then XOR the key stream with the ciphertext stream to obtain the plaintext. Due to the symmetry of the XOR operation, the encryption and decryption processes are exactly the same.

Code implementation and analysis

  1. ECB mode
from Crypto.Cipher import AES
import base64


class AEScoder():
    def __init__(self):
        self.__encryptKey = "iEpSxImA0vpMUAabsjJWug=="
        self.__key = base64.b64decode(self.__encryptKey)

    # AES加密
    def encrypt(self, data):
        BS = 16
        pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
        cipher = AES.new(self.__key, AES.MODE_ECB)
        encrData = cipher.encrypt(pad(data).encode('utf-8'))
        # encrData = base64.b64encode(encrData)
        return encrData

    # AES解密
    def decrypt(self, encrData):
        # encrData = base64.b64decode(encrData)
        # unpad = lambda s: s[0:-s[len(s)-1]]
        unpad = lambda s: s[0:-s[-1]]
        cipher = AES.new(self.__key, AES.MODE_ECB)
        decrData = unpad(cipher.decrypt(encrData))
        return decrData.decode('utf-8')


if __name__ == '__main__':
    aescoder = AEScoder()
    data = 'hello world'
    a = aescoder.encrypt(data)
    print("加密:", a)
    print("解密:", aescoder.decrypt(a))

  • Brief analysis 1: Object-oriented writing is used here, a class is created, and at the same time, the key is directly written as a class attribute. If there is a need to modify the key flexibly, just pass the key as a parameter.
  • Analysis 2: ECB mode is used in the example, which is the simplest and most commonly used mode for AES encryption. Another common mode is CBC, which will have one more initial offset vector iv than ECB mode: cipher = AES.new(self.__key, AES.MODE_CBC, iv).
  • Analysis 3: pad and unpad are padding function and inverse padding function respectively. Because AES encryption requires the length of the encrypted text, it must be a multiple of the number of key bytes. The length of encryptKey here after base64 decoding is 16 bytes.

Filling algorithm expansion

  • The padding algorithm used here actually has a proper term, called pkcs7padding.
    The simple explanation is to fill in the missing bits: the padding string consists of a sequence of bytes, and each byte pads the length of the padding byte sequence.
    If 8 bytes are to be filled, the value of the filled bytes is 0x08; if 7 bytes are to be filled, the value of the filled bytes is 0x07; and so on.
    If the text length is exactly a multiple of the BlockSize length, a value of the BlockSize length will also be filled. The advantage of this is that the number of filling bytes can be known according to the filling value of the last Byte.

  • In fact, the default mode for implementing the AES encryption algorithm in java is Cipher.getInstance("AES/ECB/PKCS5Padding")
    PKCS#5 is a subset of PKCS#7 in terms of padding: PKCS#5 is only for 8 bytes ( BlockSize=8) for padding, the padding content is 0x01-0x08; but PKCS#7 is not only padding for 8 bytes, the BlockSize range is 1-255 bytes.
    However, because AES does not have 64-bit (8-byte) blocks, if PKCS5 is used, then PKCS7 is essentially used.

  1. CBC mode
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex


# 如果text不足16位的倍数就用空格补足为16位
def add_to_16(text):
    if len(text.encode('utf-8')) % 16:
        add = 16 - (len(text.encode('utf-8')) % 16)
    else:
        add = 0
    text = text + ('\0' * add)
    return text.encode('utf-8')


# 加密函数
def encrypt(text):
    key = '9999999999999999'.encode('utf-8')
    mode = AES.MODE_CBC
    iv = b'qqqqqqqqqqqqqqqq'
    text = add_to_16(text)
    cryptos = AES.new(key, mode, iv)
    cipher_text = cryptos.encrypt(text)
    # 因为AES加密后的字符串不一定是ascii字符集的,输出保存可能存在问题,所以这里转为16进制字符串
    return b2a_hex(cipher_text)


# 解密后,去掉补足的空格用strip() 去掉
def decrypt(text):
    key = '9999999999999999'.encode('utf-8')
    iv = b'qqqqqqqqqqqqqqqq'
    mode = AES.MODE_CBC
    cryptos = AES.new(key, mode, iv)
    plain_text = cryptos.decrypt(a2b_hex(text))
    return bytes.decode(plain_text).rstrip('\0')


if __name__ == '__main__':
    e = encrypt("hello world")  # 加密
    d = decrypt(e)  # 解密
    print("加密:", e)
    print("解密:", d)

Add an RSA

import base64

from Crypto import Random
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5

# 1.伪随机生成器
random_generator = Random.new().read
print(random_generator)

# 2. rsa实例
rsa = RSA.generate(1024, random_generator)
print(rsa)

# 3. 生成私钥 公钥
private_key = rsa.export_key()
public_key = rsa.publickey().export_key()
print(private_key)
print(public_key)

# 4. 秘钥写入文件
with open('private_key.pem', 'wb') as f:
    f.write(private_key)

with open('public_key.pem', 'wb') as f:
    f.write(public_key)

# 5. 公钥加密
with open('public_key.pem', 'rb') as f:
    public_key = f.read()
    rsa_key = RSA.import_key(public_key)
    pkcs = Cipher_pkcs1_v1_5.new(rsa_key)
    text = base64.b64encode(pkcs.encrypt('1234'.encode(encoding='utf-8')))
    print("-" * 120)
    print(text)

# 6. 私钥解密
with open('private_key.pem', 'rb') as f:
    private_key = f.read()
    rsa_key = RSA.import_key(private_key)
    pkcs = Cipher_pkcs1_v1_5.new(rsa_key)
    text = pkcs.decrypt(base64.b64decode(text), random_generator).decode()
    print("-" * 120)
    print(text)

# 7. 签名和验签
# 7.1 私钥签名
print('私钥签名')
with open('private_key.pem') as f:
    key = f.read()
    rsa_key = RSA.importKey(key)
    signer = Signature_pkcs1_v1_5.new(rsa_key)
    digest = SHA.new()
    digest.update('签名和验签'.encode("utf8"))
    sign = signer.sign(digest)
    signature = base64.b64encode(sign)

print(signature)

# 7.2 公钥验签
print('公钥验签')
with open('public_key.pem') as f:
    key = f.read()
    rsa_key = RSA.importKey(key)
    verifier = Signature_pkcs1_v1_5.new(rsa_key)
    digest = SHA.new()
    digest.update('签名和验签'.encode("utf8"))
    is_verify = verifier.verify(digest, base64.b64decode(signature))

print(is_verify)

Guess you like

Origin blog.csdn.net/plan_jok/article/details/110133569