PHP AES-128-CTR 的输出与 GoLang 和 NodeJs 不同

PHP AES-128-CTR has different output than GoLang and NodeJs

无法弄清楚 PHP openssl_encrypt 是如何工作的,并且无法在 GoLang 和 NodeJs 中重现其输出,这是 PHP 中的简化代码 - 输出 hvAB:

<?php
$string = 'aaa';
$cipher = "AES-128-CTR";
$options = 0;
$encryption_iv = '1234567890123456';
$encryption_key = 'bc7316929fe1545bf0b98d114ee3ecb8';
$encryption = openssl_encrypt($string, $cipher, $encryption_key, $options, $encryption_iv);
echo $encryption; // hvAB

在 GoLang 中,假设必须对密钥进行十六进制解码以获得所需的长度 16,以便使用 AES 128 - 输出 PQ5k:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "encoding/hex"
    "fmt"
)

func main() {
    plainText := "aaa"
    fmt.Println(encryption(plainText)) // PQ5k
}

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 {
    key, _ := hex.DecodeString("bc7316929fe1545bf0b98d114ee3ecb8")
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    return block
}

在 NodeJs 中 - 输出 PQ5k:

var crypto = require('crypto');
var algorithm = 'aes-128-ctr';

function encrypt(text, password) {
  const key = Buffer.from(password, "hex").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) // PQ5k
}

encrypt('aaa', 'bc7316929fe1545bf0b98d114ee3ecb8');

起初以为是编码问题,但我认为这是正确的 - openssl_encrypt 将 return base64 值。我需要将 PHP 变体翻译成 GoLang,但是(几乎)任何其他语言的示例将不胜感激。

在 PHP 代码中,密钥未经过十六进制解码,而是一个大小为 32 字节的二进制字符串,因此对于 AES-128 来说太大了。

PHP/OpenSSL 通过仅考虑前 16 个字节隐式截断密钥。

在 Go 中只需使用 key := []byte("bc7316929fe1545b")

在 NodeJS 中:const key = Buffer.from("bc7316929fe1545b", "utf8") 得到 PHP 结果。

相反,在 PHP 代码中,密钥也可以使用 hex2bin() 进行十六进制解码。

此处为 c/c++ 版本,但输出与 golang/nodejs 不同。


       #include <openssl/aes.h>
       #include <stdio.h>
       #include <string.h>
    
       int main() {
        AES_KEY aes_key;
        unsigned char key[AES_BLOCK_SIZE] = {0xbc, 0x73, 0x16, 0x92, 0x9f, 0xe1, 0x54, 0x5b, 0xf0, 0xb9, 0x8d, 0x11, 0x4e, 0xe3, 0xec, 0xb8 }; 
        unsigned char iv[AES_BLOCK_SIZE]  = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6}; 
        unsigned char ecount[AES_BLOCK_SIZE]; memset( ecount, 0, 16 );
        unsigned int num = 0 ; 
        const  char *x = "aaa";        
        unsigned char out[16];         
        AES_set_encrypt_key(key, 128, &aes_key); 
        AES_ctr128_encrypt( (const unsigned char *) x, out, AES_BLOCK_SIZE, &aes_key, iv, ecount, &num);
        for (int k = 0; k < 3; k++)  printf("%02x", out[k]); // c9aa18
        printf( "\n");
        return 0;
       }
       // g++ -o aes-simple aes-simple.cpp  -I/usr/local/ssl/include  -L/usr/local/ssl/lib -g    -lcrypto