PHP实现AES-128-ECB并以PKCS5Padding填充方式加解密

aes

工作中提供给外部调用的api需要进行请求的内容进行加密,加密使用的AES/ECB/PKCS5Padding这种加密方式,公司开发使用的是Java,但是对接企业有使用Java,Go或者php进行开发的,客户会要求提供一下demo,Java语言还好搞,本身就是Java开发的,直接提供就好了,但是php和Go由于公司没有使用者,在客户来询问的时候就没有demo可以提供到,于是自己就研究了一下PHP的AES加密,并提供了一个demo。下边介绍一下具体的实现。

本文主要讲由Java转到PHP的实现,具体AES算法是怎么实现的不在本文的讨论范围,如果还不知道AES是什么自行搜索。

Java实现

在这里有必要先说明一下Java的实现,因为只有知道Java是怎么实现的,才能在其他语言里去实现。先上代码吧:

public class AesUtils {    
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";    
    private static final String ALGORITHM = "AES";
    public static String encrypt(String content, String key){    
        try {        
            Key secretKeySpec = secretKeySpec(key);        
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);// 创建密码器
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);// 初始化
            byte[] result = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(result); 
        } catch (Exception e) { 
        }
    }
    public static String decrypt(String content, String key) {
        try {
            Key keySpec = secretKeySpec(key);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] result = cipher.doFinal(Base64.getDecoder().decode(content));
            return new String(result, StandardCharsets.UTF_8);
        } catch (Exception e) {
        }
    }
    private static Key secretKeySpec(String key) throws EncryptException {
        KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
        generator.init(128, secureRandom);
        SecretKey secretKey = generator.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        return new SecretKeySpec(enCodeFormat, ALGORITHM);
    }
}

完整代码如上,整个代码也比较清晰,获取key然后对内容进行加解密。

 

但是问题就出现在key获取上,根据用户提供的key再使用RNG(Random Number Generator)算法:SHA1PRNG获取128位的key:generator.init(128, secureRandom);,由次可知完整的AES加密算法应该是AES-128-ECB并使用PKCS5Padding方式进行填充。

PHP实现

通过阅读Java的代码发现完整算法是AES-128-ECB并使用PKCS5Padding方式进行填充,获取key的时候使用SHA1PRNG,但是PHP并没有这种方式,于是就去询问GPT,查看网上各种资料,最终找到了解决办法,PHP的完整代码如下:

<?php
$plainText = isset($_GET['text']) ? $_GET['text'] : 'Hello, World!';
$key = isset($_GET['key']) ? $_GET['key'] : 'this_is_a_very_long_key_that_needs_to_be_shortened_or_hashed';

function encrypt($plainText, $key) {
    $key = substr(openssl_digest(openssl_digest($key, 'sha1', true), 'sha1', true), 0, 16);
    // openssl_encrypt 加密不同Mcrypt,对秘钥长度要求,超出16加密结果不变
    $data = openssl_encrypt($plainText, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
    //$data = strtolower(bin2hex($data));
    return base64_encode($data);
}

function decrypt($cipherText, $key) {
    $key = substr(openssl_digest(openssl_digest($key, 'sha1', true), 'sha1', true), 0, 16);
    $decrypted = openssl_decrypt(base64_decode($cipherText), 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
    return $decrypted;
}

// 示例用法
$encrypted = encrypt($plainText, $key);
echo "加密结果: " . $encrypted . "\n";

$decrypted = decrypt($encrypted, $key);
echo "解密结果: " . $decrypted . "\n";
?>

如上,在php中是对Key进行两次sha1并对结果进行截取16位。

在PHP中,openssl_encrypt和openssl_decrypt函数会自动处理PKCS#5/PKCS#7填充(padding),不需要手动实现填充。参数中指明OPENSSL_RAW_DATA就可以了。

以上就是在PHP中实现Java中SHA1PRNG生成key并以AES-128-ECB加密且以PKCS#5方式进行填充的实现。记录一下。

 

 

THE END