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

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

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

问题

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

  1. <?php
  2. $string = 'aaa';
  3. $cipher = "AES-128-CTR";
  4. $options = 0;
  5. $encryption_iv = '1234567890123456';
  6. $encryption_key = 'bc7316929fe1545bf0b98d114ee3ecb8';
  7. $encryption = openssl_encrypt($string, $cipher, $encryption_key, $options, $encryption_iv);
  8. echo $encryption; // hvAB

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

  1. package main
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "encoding/base64"
  6. "encoding/hex"
  7. "fmt"
  8. )
  9. func main() {
  10. plainText := "aaa"
  11. fmt.Println(encryption(plainText)) // PQ5k
  12. }
  13. func encryption(plainText string) string {
  14. bytes := []byte(plainText)
  15. blockCipher := createCipher()
  16. stream := cipher.NewCTR(blockCipher, []byte("1234567890123456"))
  17. stream.XORKeyStream(bytes, bytes)
  18. return base64.StdEncoding.EncodeToString(bytes)
  19. }
  20. func createCipher() cipher.Block {
  21. key, _ := hex.DecodeString("bc7316929fe1545bf0b98d114ee3ecb8")
  22. block, err := aes.NewCipher(key)
  23. if err != nil {
  24. panic(err)
  25. }
  26. return block
  27. }

在NodeJs中 - 输出PQ5k

  1. var crypto = require('crypto');
  2. var algorithm = 'aes-128-ctr';
  3. function encrypt(text, password) {
  4. const key = Buffer.from(password, "hex").slice(0, 16);
  5. const ivBuffer = Buffer.from("1234567890123456");
  6. const cipher = crypto.createCipheriv(algorithm, key, ivBuffer);
  7. let encrypted = cipher.update(text,'utf8','base64') + cipher.final('base64')
  8. console.log(encrypted) // PQ5k
  9. }
  10. 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:

  1. &lt;?php
  2. $string = &#39;aaa&#39;;
  3. $cipher = &quot;AES-128-CTR&quot;;
  4. $options = 0;
  5. $encryption_iv = &#39;1234567890123456&#39;;
  6. $encryption_key = &#39;bc7316929fe1545bf0b98d114ee3ecb8&#39;;
  7. $encryption = openssl_encrypt($string, $cipher, $encryption_key, $options, $encryption_iv);
  8. 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:

  1. package main
  2. import (
  3. &quot;crypto/aes&quot;
  4. &quot;crypto/cipher&quot;
  5. &quot;encoding/base64&quot;
  6. &quot;encoding/hex&quot;
  7. &quot;fmt&quot;
  8. )
  9. func main() {
  10. plainText := &quot;aaa&quot;
  11. fmt.Println(encryption(plainText)) // PQ5k
  12. }
  13. func encryption(plainText string) string {
  14. bytes := []byte(plainText)
  15. blockCipher := createCipher()
  16. stream := cipher.NewCTR(blockCipher, []byte(&quot;1234567890123456&quot;))
  17. stream.XORKeyStream(bytes, bytes)
  18. return base64.StdEncoding.EncodeToString(bytes)
  19. }
  20. func createCipher() cipher.Block {
  21. key, _ := hex.DecodeString(&quot;bc7316929fe1545bf0b98d114ee3ecb8&quot;)
  22. block, err := aes.NewCipher(key)
  23. if err != nil {
  24. panic(err)
  25. }
  26. return block
  27. }

And in NodeJs - outputs PQ5k:

  1. var crypto = require(&#39;crypto&#39;);
  2. var algorithm = &#39;aes-128-ctr&#39;;
  3. function encrypt(text, password) {
  4. const key = Buffer.from(password, &quot;hex&quot;).slice(0, 16);
  5. const ivBuffer = Buffer.from(&quot;1234567890123456&quot;);
  6. const cipher = crypto.createCipheriv(algorithm, key, ivBuffer);
  7. let encrypted = cipher.update(text,&#39;utf8&#39;,&#39;base64&#39;) + cipher.final(&#39;base64&#39;)
  8. console.log(encrypted) // PQ5k
  9. }
  10. 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版本还不一样。

  1. #include <openssl/aes.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. int main() {
  5. AES_KEY aes_key;
  6. unsigned char key[AES_BLOCK_SIZE] = {0xbc, 0x73, 0x16, 0x92, 0x9f, 0xe1, 0x54, 0x5b, 0xf0, 0xb9, 0x8d, 0x11, 0x4e, 0xe3, 0xec, 0xb8 };
  7. unsigned char iv[AES_BLOCK_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
  8. unsigned char ecount[AES_BLOCK_SIZE];
  9. memset(ecount, 0, 16);
  10. unsigned int num = 0;
  11. const char *x = "aaa";
  12. unsigned char out[16];
  13. AES_set_encrypt_key(key, 128, &aes_key);
  14. AES_ctr128_encrypt((const unsigned char *) x, out, AES_BLOCK_SIZE, &aes_key, iv, ecount, &num);
  15. for (int k = 0; k < 3; k++) printf("%02x", out[k]); // c9aa18
  16. printf("\n");
  17. return 0;
  18. }
  19. // 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.

  1. #include &lt;openssl/aes.h&gt;
  2. #include &lt;stdio.h&gt;
  3. #include &lt;string.h&gt;
  4. int main() {
  5. AES_KEY aes_key;
  6. unsigned char key[AES_BLOCK_SIZE] = {0xbc, 0x73, 0x16, 0x92, 0x9f, 0xe1, 0x54, 0x5b, 0xf0, 0xb9, 0x8d, 0x11, 0x4e, 0xe3, 0xec, 0xb8 };
  7. unsigned char iv[AES_BLOCK_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
  8. unsigned char ecount[AES_BLOCK_SIZE]; memset( ecount, 0, 16 );
  9. unsigned int num = 0 ;
  10. const char *x = &quot;aaa&quot;;
  11. unsigned char out[16];
  12. AES_set_encrypt_key(key, 128, &amp;aes_key);
  13. AES_ctr128_encrypt( (const unsigned char *) x, out, AES_BLOCK_SIZE, &amp;aes_key, iv, ecount, &amp;num);
  14. for (int k = 0; k &lt; 3; k++) printf(&quot;%02x&quot;, out[k]); // c9aa18
  15. printf( &quot;\n&quot;);
  16. return 0;
  17. }
  18. // 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:

确定