PHP AES-128-CTR加密输出与Go、NodeJS不一致,如何实现结果对齐?
AES跨语言加密结果不一致问题原因及解决方案
问题根源
Go和NodeJS中对密钥的处理逻辑和PHP的openssl_encrypt默认逻辑不一致:
- AES-128要求密钥长度为16字节,PHP的
openssl_encrypt接收字符串类型的密钥时,不会自动做hex解码,只会直接截取输入字符串的前16字节作为实际密钥。你示例中的密钥字符串是bc7316929fe1545bf0b98d114ee3ecb8(共32字符),PHP实际使用的密钥是前16个字符组成的字符串:bc7316929fe1545b。 - 你的Go和NodeJS代码中将32字符的密钥做了hex解码,得到的16字节二进制数据和PHP截取的16字符字符串完全不同,因此加密结果不一致。
对齐PHP逻辑的迁移方案(Go/NodeJS实现)
因为需求是把PHP逻辑迁移到Go,只需要修改Go/Node的密钥处理逻辑,取消hex解码、直接取密钥字符串前16字节即可。
Go实现代码
package main import ( "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" ) func main() { plainText := "aaa" fmt.Println(encryption(plainText)) // 输出hvAB } func encryption(plainText string) string { bytes := []byte(plainText) blockCipher := createCipher() stream := cipher.NewCTR(blockCipher, []byte("1234567890123456")) stream.XORKeyStream(bytes, bytes) return base64.StdEncoding.EncodeToString(bytes) } func createCipher() cipher.Block { // 取消hex解码,直接取密钥字符串前16字节 key := []byte("bc7316929fe1545bf0b98d114ee3ecb8")[:16] block, err := aes.NewCipher(key) if err != nil { panic(err) } return block }
NodeJS实现代码
var crypto = require('crypto'); var algorithm = 'aes-128-ctr'; function encrypt(text, password) { // 取消hex解码,直接取密钥字符串前16字节 const key = Buffer.from(password).slice(0, 16); const ivBuffer = Buffer.from("1234567890123456"); const cipher = crypto.createCipheriv(algorithm, key, ivBuffer); let encrypted = cipher.update(text,'utf8','base64') + cipher.final('base64') console.log(encrypted) // 输出hvAB } encrypt('aaa', 'bc7316929fe1545bf0b98d114ee3ecb8');
反向对齐方案(可选)
如果需要让PHP适配现有Go/Node的加密逻辑,只需要在PHP中把密钥先做hex转二进制处理即可:
<?php $string = 'aaa'; $cipher = "AES-128-CTR"; $options = 0; $encryption_iv = '1234567890123456'; // 密钥先做hex解码再传入 $encryption_key = hex2bin('bc7316929fe1545bf0b98d114ee3ecb8'); $encryption = openssl_encrypt($string, $cipher, $encryption_key, $options, $encryption_iv); echo $encryption; // 输出PQ5k,和原Go/Node结果一致
内容的提问来源于stack exchange,提问作者Kn Ko
相关产品推荐
相关产品推荐

