Java AES/ECB/PKCS5padding Encryption conversion Python

Note: Encryption mode 128-bit AES encryption mode is USED for ECB encryption, and Base64 transcoding is used after encryption.

Recently, I encountered AES encryption algorithm when docking with Java project. The Java code has securerandom.getInstance (“SHA1PRNG”). Converted to a Python

AES encryption

Advanced Encryption Standard (AES) is a specification established by the National Institute of Standards and Technology (NIST) in 2001 to encrypt electronic data. It is one of the most classical symmetric encryption and decryption algorithms. It is a grouping encryption standard. Each encryption block size is 128 bits, and the key length allowed is 128, 192 and 256 bits. This section describes only the ECB encryption mode. AES encryption mode: the ECB/CBC/CTR/OFB/CFB filling: pkcs5padding pkcs7padding/zeropadding/iso10126 / ansix923 data blocks: 128 a / 192 a / 256 aCopy the code

The ECB mode

The ECB mode, as the simplest working mode, directly groups the plaintext. Each group is encrypted separately, and each group is independent and has no context

Java encrypts Demo by default

Java’s default AES encryption mode is “AES/ECB/PKCS5Padding”.

Java Code Presentation

package com.qzd.hit.util;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Demo {

	/*** main
    * @author qizai
    * data: params
    * encStr: Here, the length of the key must be a multiple of 16
    */
	public static void main(String[] args) throws Exception {
		// Encrypt Data
        String key = "ROcb6JybnKILLOlO"; // Secret Key length must be (16 24 32)
		String data = "[\" 123456789 \ "]"; // Content to be encrypted
		String encStr = encrypt(data, key);  // Content to be decrypted
		System.out.println(encStr); //Encrypted data: w6oijM0xddQrItnH3UybLQ==
		// Decrypt Data
		String decStr = decrypt(encStr, key);
		System.out.println(decStr); //Decrypted data: ["123456789"]
	}

	public static String encrypt(String content, String password) {
		if (StringUtils.isEmpty(content) || StringUtils.isEmpty(password)) {
			System.out.println("AES encryption params is null");
			return null;
		}
		try {
			// Create cipher
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			byte[] byteContent = content.getBytes("UTF-8");
			// Initialize as cryptographic cipher
			cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
			byte[] encryptByte = cipher.doFinal(byteContent);
			return org.apache.commons.codec.binary.Base64.encodeBase64String(encryptByte);
		} catch (Exception e) {
			System.out.println("AES encryption operation has exception,content:{},password:{}", content, password, e);
		}
		return null;
	}

	public static String decrypt(String encryptContent, String password) throws Exception {
		if (StringUtils.isEmpty(encryptContent) || StringUtils.isEmpty(password)) {
			System.out.println("AES The request parameter is null");
			return null;
		}
		Cipher cipher = null;
		cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		// Set to decryption mode
		cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
		// Perform decryption operation
		byte[] result = cipher.doFinal(org.apache.commons.codec.binary.Base64.decodeBase64(encryptContent));
		return new String(result, "UTF-8");
	}

	private static SecretKeySpec getSecretKey(final String password) throws NoSuchAlgorithmException {
		// Generates the generator for the specified algorithm key
		KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
		SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
		random.setSeed(password.getBytes());
		keyGenerator.init(128, random);
		// Grnerate Key
		SecretKey secretKey = keyGenerator.generateKey();
		// Key converted to AES
		return new SecretKeySpec(secretKey.getEncoded(), "AES"); }}Copy the code

Encryption notes:

KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); // Generates the generator for the specified algorithm key
SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); // SHA1PRNG Random number algorithm
random.setSeed(password.getBytes());
keyGenerator.init(128, random);
SecretKey secretKey = keyGenerator.generateKey();
Copy the code

Python implementation AES/ECB/PKCS5padding

Install AES libraries (Windows)

pip install pycryptodome
Copy the code

Under Linux installation

pip install pycrypto
Copy the code

Related code implementation steps

import base64
import hashlib

import requests
from Crypto.Cipher import AES as _AES


class AES:

    def __init__(self, key: str) :
        """Init aes object used by encrypt or decrypt. AES/ECB/PKCS5Padding same as aes in java default. """

        self.aes = _AES.new(self.get_sha1prng_key(key), _AES.MODE_ECB)

    @staticmethod
    def get_sha1prng_key(key: str) - >bytes:
        """encrypt key with SHA1PRNG. same as java AES crypto key generator SHA1PRNG. SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" ); secureRandom.setSeed(decryptKey.getBytes()); keygen.init(128, secureRandom); :param string key: original key. :return bytes: encrypt key with SHA1PRNG, 128 bits or 16 long bytes. """

        signature: bytes = hashlib.sha1(key.encode()).digest()
        signature: bytes = hashlib.sha1(signature).digest()
        return signature[:16]

    @staticmethod
    def padding(s: str) - >str:
        """Padding PKCS5"""

        pad_num: int = 16 - len(s) % 16
        return s + pad_num * chr(pad_num)

    @staticmethod
    def unpadding(s) :
        """Unpadding PKCS5"""

        padding_num: int = ord(s[-1])
        return s[: -padding_num]

    def encrypt_to_bytes(self, content_str) :
        """From string encrypt to bytes ciphertext. """

        content_bytes = self.padding(content_str).encode()
        ciphertext_bytes = self.aes.encrypt(content_bytes)
        return ciphertext_bytes

    def encrypt_to_base64(self, content_str) :
        """From string encrypt to base64 ciphertext. """

        ciphertext_bytes = self.encrypt_to_bytes(content_str)
        ciphertext_bs64 = base64.b64encode(ciphertext_bytes).decode()
        return ciphertext_bs64

    def decrypt_from_bytes(self, ciphertext_bytes) :
        """From bytes ciphertext decrypt to string. """

        content_bytes = self.aes.decrypt(ciphertext_bytes)
        content_str = self.unpadding(content_bytes.decode())
        return content_str

    def decrypt_from_base64(self, ciphertext_bs64) :
        """From base64 ciphertext decrypt to string. """

        ciphertext_bytes = base64.b64decode(ciphertext_bs64)
        content_str = self.decrypt_from_bytes(ciphertext_bytes)
        return content_str


def encrypt_to_bytes(content_str, encrypt_key: str) :
    """From string encrypt to bytes ciphertext. """

    aes: AES = AES(encrypt_key)
    ciphertext_bytes = aes.encrypt_to_bytes(content_str)
    return ciphertext_bytes


def encrypt_to_base64(content_str, encrypt_key: str) - >str:
    """From string encrypt to base64 ciphertext. """

    aes: AES = AES(encrypt_key)
    ciphertext_bs64 = aes.encrypt_to_base64(content_str)
    return ciphertext_bs64


def decrypt_from_bytes(ciphertext_bytes, decrypt_key: str) - >str:
    """From bytes ciphertext decrypt to string. """

    aes: AES = AES(decrypt_key)
    content_str = aes.decrypt_from_bytes(ciphertext_bytes)
    return content_str


def decrypt_from_base64(ciphertext_bs64, decrypt_key: str) - >str:
    """From base64 ciphertext decrypt to string. """

    aes: AES = AES(decrypt_key)
    content_str = aes.decrypt_from_base64(ciphertext_bs64)
    return content_str


if __name__ == "__main__":
    key = "iC6qfFyiza8aq"
    encrypt_str_data = "[\" 13811111111 \ "]"
    et = encrypt_to_base64(encrypt_str_data, key)
    print("Encrypted data:", et)
    ret = decrypt_from_base64(et, key)
    print("Decrypted data:", ret)

Copy the code

The key code

This method implements the conversion of key, the contents of the key encryption code in Java, which is returned as a hexadecimal string.

    @staticmethod
    def get_sha1prng_key(key: str) - >bytes:
        """encrypt key with SHA1PRNG. same as java AES crypto key generator SHA1PRNG. SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" ); secureRandom.setSeed(decryptKey.getBytes()); keygen.init(128, secureRandom); :param string key: original key. :return bytes: encrypt key with SHA1PRNG, 128 bits or 16 long bytes. """

        signature: bytes = hashlib.sha1(key.encode()).digest()
        signature: bytes = hashlib.sha1(signature).digest()
        return signature[:16]
Copy the code

Simple version of

import base64
import hashlib

from Crypto.Cipher import AES

SECRET_KEY = 'iC6qfFyiza8aq'  # key


class AesEncrypt(object) :
    def __init__(self) :
        self.key = self.getKey(SECRET_KEY)
        self.mode = AES.MODE_ECB

    def pading(self, text) :
        "" processing of encrypted characters ""
        return text + (len(self.key) - len(text) % len(self.key)) * chr(len(self.key) - len(text) % len(self.key))

    def unpading(self, text) :
        "" processing of decrypted characters ""
        return text[0: -ord(text[-1:]]def getKey(self, key) :
        """ processing of key,key length 16,24,32 ""
        signature: bytes = hashlib.sha1(key.encode()).digest()
        signature: bytes = hashlib.sha1(signature).digest()
        return signature[:16]

    def encrypt(self, text) :
        """ Encryption function """
        ecb_encrypt = AES.new(self.key, self.mode)  # the ECB mode
        ecb_text = ecb_encrypt.encrypt(bytes(self.pading(text), encoding="utf8"))
        encrypt_string = base64.b64encode(ecb_text).decode()
        return encrypt_string

    def decrypt(self, text) :
        """ Decryption function ""
        decode = base64.b64decode(text)
        ecb_decrypt = AES.new(self.key, self.mode)  # the ECB mode
        plain_text = ecb_decrypt.decrypt(decode)
        decrypt_string = self.unpading(plain_text).decode()
        return decrypt_string


if __name__ == '__main__':
    aes_encrypt = AesEncrypt()
    data = "[\" 13811111111 \ "]"
    en = aes_encrypt.encrypt(data)
    print("Encrypt data:", en)
    dr = aes_encrypt.decrypt(en)
    print("Decrypt data:", dr)

Copy the code

1. Perform sha1PRng encryption on the key, which is the get_sha1PRNG_key method in this article. Use the encrypted ciphertext as the AES key

Determine the AES encryption mode, such as ECB and CBC. The AES encryption mode is ECB/CBC/CTR/OFB/CFB

Padding, key and original text can be filled, NoPadding, NoPadding, 0 padding, and pkcs5padding.

4. Generally speaking, the incompatibility of encrypted content is basically caused by different key processing or incorrect filling.

[Refer to SHA1 algorithm]