PHP AES-128-CTR与GoLang和Node.js的输出不同。

huangapple go评论86阅读模式
英文:

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将返回base64值。我需要将PHP变体翻译成GoLang,但是在(几乎)任何其他语言中的示例将不胜感激。

英文:

Can't figure out how does PHP openssl_encrypt work, and cannot reproduce its output in GoLang and NodeJs, here's a simplified code in PHP - outputs hvAB:

&lt;?php
$string = &#39;aaa&#39;;
$cipher = &quot;AES-128-CTR&quot;;
$options = 0;
$encryption_iv = &#39;1234567890123456&#39;;
$encryption_key = &#39;bc7316929fe1545bf0b98d114ee3ecb8&#39;;
$encryption = openssl_encrypt($string, $cipher, $encryption_key, $options, $encryption_iv);
echo $encryption; // hvAB

In GoLang, assuming key must be hex decoded to get the desired length of 16 so that AES 128 will be used - outputs PQ5k:

package main

import (
	&quot;crypto/aes&quot;
	&quot;crypto/cipher&quot;
	&quot;encoding/base64&quot;
	&quot;encoding/hex&quot;
	&quot;fmt&quot;
)

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

func encryption(plainText string) string {
	bytes := []byte(plainText)
	blockCipher := createCipher()
	stream := cipher.NewCTR(blockCipher, []byte(&quot;1234567890123456&quot;))
	stream.XORKeyStream(bytes, bytes)
	return base64.StdEncoding.EncodeToString(bytes)
}

func createCipher() cipher.Block {
	key, _ := hex.DecodeString(&quot;bc7316929fe1545bf0b98d114ee3ecb8&quot;)
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	return block
}

And in NodeJs - outputs PQ5k:

var crypto = require(&#39;crypto&#39;);
var algorithm = &#39;aes-128-ctr&#39;;

function encrypt(text, password) {
  const key = Buffer.from(password, &quot;hex&quot;).slice(0, 16);
  const ivBuffer = Buffer.from(&quot;1234567890123456&quot;);
  const cipher = crypto.createCipheriv(algorithm, key, ivBuffer);
  let encrypted = cipher.update(text,&#39;utf8&#39;,&#39;base64&#39;) +  cipher.final(&#39;base64&#39;)
  console.log(encrypted) // PQ5k
}

encrypt(&#39;aaa&#39;, &#39;bc7316929fe1545bf0b98d114ee3ecb8&#39;);

Thought it's an encoding issue at first, but I think that's correct - openssl_encrypt will return base64 value. I need to translate the PHP variant into GoLang, but an example in (almost) any other language will be much appreciated.

答案1

得分: 0

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

PHP/OpenSSL会隐式地通过只考虑前16个字节来截断密钥。

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

在NodeJS中,使用const key = Buffer.from("bc7316929fe1545b", "utf8")来获得PHP的结果。

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

英文:

In the PHP code, the key is not hex decoded, but is a binary string that is 32 bytes in size and thus too large for AES-128.

PHP/OpenSSL implicitly truncates the key by considering only the first 16 bytes.

In Go simply use key := []byte(&quot;bc7316929fe1545b&quot;)

In NodeJS: const key = Buffer.from(&quot;bc7316929fe1545b&quot;, &quot;utf8&quot;) to get the PHP result.

Conversely, in the PHP code the key can also be hex decoded using hex2bin().

答案2

得分: 0

这是C/C++版本的代码,但输出结果与Golang/Node.js版本还不一样。

#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
英文:

Here c/c++ version, but output is not yet the same with golang/nodejs.


       #include &lt;openssl/aes.h&gt;
       #include &lt;stdio.h&gt;
       #include &lt;string.h&gt;
    
       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 = &quot;aaa&quot;;        
        unsigned char out[16];         
        AES_set_encrypt_key(key, 128, &amp;aes_key); 
        AES_ctr128_encrypt( (const unsigned char *) x, out, AES_BLOCK_SIZE, &amp;aes_key, iv, ecount, &amp;num);
        for (int k = 0; k &lt; 3; k++)  printf(&quot;%02x&quot;, out[k]); // c9aa18
        printf( &quot;\n&quot;);
        return 0;
       }
       // g++ -o aes-simple aes-simple.cpp  -I/usr/local/ssl/include  -L/usr/local/ssl/lib -g    -lcrypto 

huangapple
  • 本文由 发表于 2021年8月27日 20:03:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/68953106.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定