Implementation code of AES/ECB/PKCS5Padding algorithm for secret key encryption and decryption of any length consistent with JAVA, Python and PHP

Encryption

Recently, I encountered an AES encryption algorithm that needs to be implemented in Java, Python, and PHP. In fact, it is not very complicated in nature, but the parameter adjustment is quite troublesome.
I found some reference materials and finally got it. The actual code is as follows:

Main features

The three languages of JAVA, Python and PHP are unified

Unified and consistent encryption and decryption implementation of the AES/ECB/PKCS5Padding algorithm;

Key of any length

Many code implementations on the Internet are based on specified 16-bit length keys. In many enterprise scenarios, keys of custom length are used, so specific processing is required. Here, support for keys of any length is implemented and unified across three languages.

Support utf-8 encoding

No longer;

Code implementation

Java code implementation

CryptUtilPublic.java

/**
 * @author: https://www.baihezi.com
 */
package com.baihezi.www.utils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class CryptUtilPublic {<!-- -->

    /** Key length: 128, 192 or 256, the default is 128, do not change it at will */
    private static final int KEY_SIZE = 128;

    /** Encryption/decryption algorithm name */
    private static final String ALGORITHM = "AES"; // AES = AES/ECB/PKCS5Padding

    /** Random number generator (RNG) algorithm name */
    private static final String RNG_ALGORITHM = "SHA1PRNG";

    /**
     * Generate key object
     */
    private static SecretKey generateKey(String key) throws Exception {<!-- -->

        //Create a secure random number generator
        SecureRandom random = SecureRandom.getInstance(RNG_ALGORITHM);
        //Set the byte array of key as the seed of the secure random number generator
        random.setSeed(key.getBytes());
        // Create AES algorithm generator
        KeyGenerator gen = KeyGenerator.getInstance(ALGORITHM);
        //Initialize algorithm generator
        gen.init(KEY_SIZE, random);
        return gen.generateKey();
    }
    /**
     *
     * @param originalData original text
     * @param key
     * @return
     * @throwsException
     */

    public static String encrypt(String originalData, String key) throws Exception {<!-- -->
        byte[] plainBytes = originalData.getBytes(StandardCharsets.UTF_8);
        if (plainBytes == null || plainBytes.length == 0) {<!-- -->
            return "";
        }
        if (key == null || key.length()== 0) {<!-- -->
            return "";
        }

        SecretKey secKey = generateKey(key);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secKey);
        byte[] cipherBytes = cipher.doFinal(plainBytes);

        return parseByte2HexStr(cipherBytes);
    }

    /**
     * Convert binary to hexadecimal
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {<!-- -->
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < buf.length; i + + ) {<!-- -->
            String hex = Integer.toHexString(buf[i] & amp; 0xFF);
            if (hex.length() == 1) {<!-- -->
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * Convert hexadecimal to binary
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {<!-- -->
        if (hexStr.length() < 1) {<!-- -->
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i + + ) {<!-- -->
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }


    public static String decrypt(String encryptedData, String key) throws Exception {<!-- -->

        byte[] cipherBytes = parseHexStr2Byte(encryptedData);
        SecretKey secKey = generateKey(key);

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secKey);

        byte[] plainBytes = cipher.doFinal(cipherBytes);
        return new String(plainBytes, StandardCharsets.UTF_8);
    }

// public static void main(String[] args) {<!-- -->
// try {<!-- -->
// String originalData = "14464614210 Chinese 001";
// String key = "asdfasdasdfsdfasdf23434tgsdfhxcvau4IKf";
// String encryptedData = encrypt(originalData, key);
//
// String decryptedText = decrypt(encryptedData, key);
// System.out.println("original value: " + originalData);
// System.out.println("encrypted value: " + encryptedData);
// System.out.println("original value: " + decryptedText);
// } catch (Exception e) {<!-- -->
// e.printStackTrace();
// }
// }



}

Java code running result output:

original value: 14464614210 Chinese 001
encrypted value: 7C7F99DFC543F6E2DD18BAA96E6E889D6C690C860DC959E5CD91E47E8F6F2B69
original value: 14464614210 Chinese 001

Python code implementation

CryptUtilPublic.py (python3)

# AES-ECB encryption
# by https://www.baihezi.com
import hashlib
import binascii
from crypto.Cipher import AES


class EncryptUtil:
    def __init__(self, key):
        self.key = self.get_sha1prng_key(key) #Initialize key
        self.length = AES.block_size #Initialize data block size
        self.aes = AES.new(self.key, AES.MODE_ECB) # Initialize AES, ECB mode instances
        # Truncate function to remove padding characters
        self.unpad = lambda date: date[0:-ord(date[-1])]
    # Use the random number generated by the SHA1 method to process the key
    def get_sha1prng_key(self, key):
        signature = hashlib.sha1(key.encode("utf-8")).digest()
        signature = hashlib.sha1(signature).digest()

        return signature[:16]

    def pad(self, text):
        """
        #Padding function so that the bytecode length of the encrypted data is an integer multiple of block_size
        """
        count = len(text.encode('utf-8'))
        add = self.length - (count % self.length)
        context = text + (chr(add) * add)
        return context

    def encrypt(self, originalData): # Encryption function
        res = self.aes.encrypt(self.pad(originalData).encode("utf8"))
        hex_string = binascii.b2a_hex(res)
        return hex_string.decode().upper()

    def decrypt(self, encryptedData): # Decryption function
        res = binascii.a2b_hex(encrypedData.encode("utf8"))
        msg = self.aes.decrypt(res).decode("utf8")
        return self.unpad(msg)

# Secret key
secret = 'asdfasdasdfsdfasdf23434tgsdfhxcvau4IKf'
eg = EncryptUtil(secret) # The length of the key here can be any length

data = "14464614210中文001"
encryptData = eg.encrypt(data)
decryptData = eg.decrypt(encryptData)
print("original value: " + data)
print("encrypted value: " + encryptData)
print("decrypted value: " + decryptData)

The output of running the python code is:

original value: 14464614210 Chinese 001
encrypted value: 7C7F99DFC543F6E2DD18BAA96E6E889D6C690C860DC959E5CD91E47E8F6F2B69
decrypted value: 14464614210 Chinese 001

PHP code implementation

EncryptUtil.php

<?php
/**
 * EncryptUtil symmetric encryption
 * Align Java's AES/ECB/PKCS5Padding
 * @author: https://www.baihezi.com
 */
class EncryptUtil{<!-- -->
    /**
     * encrypt aes encryption
     * @param $originalData Data to be encrypted
     * @param $secretKey encrypted secret key
     * @return
     */
    public static function encrypt($originalData, $secretKey){<!-- -->
        $secretKey = self::_sha1prng($secretKey);
        $iv = '';
        $data = openssl_encrypt($originalData, 'AES-128-ECB', $secretKey, OPENSSL_RAW_DATA, $iv);
        $data = strtoupper(bin2hex($data));
        return $data;
    }

    /**
     * decrypt aes decryption
     * @param $encryptedData The data to be decrypted
     * @param $secretKey encrypted secret key
     * @return
     */
    public static function decrypt($encryptedData, $secretKey){<!-- -->
        $secretKey = self::_sha1prng($secretKey);
        $iv = '';
        $decrypted = openssl_decrypt(hex2bin($encryptedData), 'AES-128-ECB', $secretKey, OPENSSL_RAW_DATA, $iv);
        return $decrypted;
    }

    /**
     *SHA1PRNG algorithm
     * @param $secretKey encrypted secret key
     * @return
     */
    private static function _sha1prng($secretKey){<!-- -->
        return substr(openssl_digest(openssl_digest($secretKey, 'sha1', true), 'sha1', true), 0, 16);
    }
}

$aesModel = new EncryptUtil();
$data = '14464614210中文001';
$secret = "asdfasdasdfsdfasdf23434tgsdfhxcvau4IKf";
//encryption
$encryptData = EncryptUtil::encrypt($data, $secret);
//Decrypt
$decryptData = EncryptUtil::decrypt($encryptData, $secret);
print_r("original value: " . $data."n");
print("encrypted value: " . $encryptData."n");
print("decrypted value: ". $decryptData."n");

PHP code running result output:

original value: 14464614210 Chinese 001
encrypted value: 7C7F99DFC543F6E2DD18BAA96E6E889D6C690C860DC959E5CD91E47E8F6F2B69
decrypted value: 14464614210 Chinese 001

Original text published at: https://www.baihezi.com/language/151502937.html

  • References
    https://juejin.cn/post/6844903859349880845
    https://blog.csdn.net/mouday/article/details/103646639
    https://blog.csdn.net/sevenlater/article/details/50317999
    https://www.jianshu.com/p/f941a309b087
    https://cloud.tencent.com/developer/article/1873784