英文:
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
:
<?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
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 (
"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
}
And in NodeJs - outputs 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');
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("bc7316929fe1545b")
In NodeJS: const key = Buffer.from("bc7316929fe1545b", "utf8")
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 <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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论