【问题标题】:PHP AES-128-CTR has different output than GoLang and NodeJsPHP AES-128-CTR 的输出与 GoLang 和 NodeJs 不同
【发布时间】:2021-10-27 09:00:48
【问题描述】:

无法弄清楚 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,但(几乎)任何其他语言的示例将不胜感激。

【问题讨论】:

    标签: php node.js go encryption openssl


    【解决方案1】:

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      这里是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 
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-22
        • 1970-01-01
        • 1970-01-01
        • 2018-12-11
        • 1970-01-01
        • 1970-01-01
        • 2018-08-18
        • 2020-08-13
        相关资源
        最近更新 更多