当前位置: 首页 > 知识库问答 >
问题:

在webcrypto中加密aes-cbc在php中使用openssl_decrypt解密aes-256-cbc

东方明亮
2023-03-14

我已经设法使它能够处理不包含og a-zA-Z0-9之外的字符和一些特殊字符的文本,但如果我使用丹麦字母,如ielouangØ,解密的文本会显示?而不是实际的字母。所有文件都保存为UTF-8,头字符集=UTF-8

Javascript - input: "tester for

var arrayBufferToString=function(buffer){
  var str = "";
  for (var iii = 0; iii < buffer.byteLength; iii++){
    str += String.fromCharCode(buffer[iii]);
  }
  return str;
}
var stringToArrayBuffer=function(str){
  var bytes = new Uint8Array(str.length);
  for (var iii = 0; iii < str.length; iii++){
    bytes[iii] = str.charCodeAt(iii);
  }
  return bytes;
}
var arrayBufferToHexDec=function(buffer) {
  return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}

var pwVector,key,sendData={};
var pwGenerateSymmetricKey=function(pw){
  if(this.crypto){
    if(!pwVector)pwVector = crypto.getRandomValues(new Uint8Array(16));
    crypto.subtle.digest({name: "SHA-256"}, stringToArrayBuffer(pw)).then(function(result){
      window.crypto.subtle.importKey("raw", result, {name: "AES-CBC",length:256}, false, ["encrypt", "decrypt"]).then(function(e){

        console.log(e+" gen SHA256 key: "+arrayBufferToHexDec(result));

        sendData.pwVector=btoa(arrayBufferToHexDec(pwVector.buffer));
        sendData.pwKey=btoa(arrayBufferToHexDec(result));

        sendData.pwVectorString=btoa(arrayBufferToString(pwVector));
        sendData.pwKeyString=btoa(arrayBufferToString(new Uint8Array(result)));

        key = e;
      },
      function(e){
        console.log(e);
      });
    });
  }else return;
} 
var pwEncryptData=function(input){
  crypto.subtle.encrypt({name: "AES-CBC", iv: this.pwVector},key,stringToArrayBuffer(input)).then(
    function(result){
      console.log('encrypted',result)

      var pwEncryptedDataArray=new Uint8Array(result);
      var pwEncryptedDataString=arrayBufferToString(pwEncryptedDataArray);

      sendData.pwData=arrayBufferToHexDec(result);
      sendData.pwDataString=btoa(pwEncryptedDataString);
    }, 
    function(e){
      console.log(e.message);
    }
  );
}       

php:

function strToHex($string){
    $hex = '';
    for ($i=0; $i<strlen($string); $i++){
        $ord = ord($string[$i]);
        $hexCode = dechex($ord);
        $hex .= substr('0'.$hexCode, -2);
    }
    return $hex;
}

$json_string = file_get_contents('php://input');
$json_object = json_decode($json_string);

$oEncryptedData=hex2bin($json_object->pwData);
$sEncryptedData=hex2bin(strToHex(base64_decode($json_object->pwDataString)));

$aesKey=hex2bin(base64_decode($json_object->pwKey));
$iv=hex2bin(base64_decode($json_object->pwVector));

$aesKeyStr=hex2bin(strToHex(base64_decode($json_object->pwKeyString)));
$ivStr=hex2bin(strToHex(base64_decode($json_object->pwVectorString)));

$oDecryptedData = decrypt($aesKey,$iv,$oEncryptedData);
$sDecryptedData = decrypt($aesKeyStr,$ivStr,$sEncryptedData);

function decrypt($aesKey,$iv, $dataTodecrypt) {
    $output = false;
    $output = openssl_decrypt($dataTodecrypt, 'AES-256-CBC',$aesKey,OPENSSL_RAW_DATA, $iv);
    return $output;
}
echo $oDecryptedData; // output: tester for ??????#?%&/
echo $sDecryptedData; // output: tester for ??????#?%&/

我试过选项0,OPENSSL_ZERO_PADDING和OPENSSL_RAW_DATA,结果相同。有人能帮我吗,因为我现在卡住了,找不到可能的错误。

解决办法

如果输入字符串在Javascript加密之前编码为utf-8,则通过选择以下行可以解决问题:

  crypto.subtle.encrypt({name: "AES-CBC", iv: this.pwVector},key,stringToArrayBuffer(input)).then(

对此:

  crypto.subtle.encrypt({name: "AES-CBC", iv: this.pwVector},key,stringToArrayBuffer(unescape(encodeURI(input)))).then(

非常简单。奇怪的是,HTML的输入并不是utf-8编码的,尽管

<meta charset="UTF-8">

已设置。但它在那里:-)

共有1个答案

丁光华
2023-03-14

Javascript端看起来像这样:

function stringToArrayBuffer(str) {
    var buf = new ArrayBuffer(str.length);
    var bufView = new Uint8Array(buf);
    for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

function arrayBufferToString(str) {
    var byteArray = new Uint8Array(str);
    var byteString = '';
    for (var i = 0; i < byteArray.byteLength; i++) {
        byteString += String.fromCodePoint(byteArray[i]);
    }
    return byteString;
}

var text = "tester for æøåÆØÅ#¤%&/";
console.log("what we will encrypt:");
console.log(text);

var data = stringToArrayBuffer(text);
console.log("what we encode to:");
console.log(data);

window.crypto.subtle.generateKey({
            name: "AES-CBC",
            length: 256, //can be  128, 192, or 256
        },
        false, //whether the key is extractable (i.e. can be used in exportKey)
        ["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey"
    )
    .then(function(key) {
        //returns a key object
        console.log("our key:");
        console.log(key);

        window.crypto.subtle.encrypt({
                    name: "AES-CBC",
                    //Don't re-use initialization vectors!
                    //Always generate a new iv every time your encrypt!
                    iv: window.crypto.getRandomValues(new Uint8Array(16)),
                },
                key, //from generateKey or importKey above
                data //ArrayBuffer of data you want to encrypt
            )
            .then(function(encrypted) {
                //returns an ArrayBuffer containing the encrypted data
                console.log("our ciphertext:");
                console.log(new Uint8Array(encrypted));
            })
            .catch(function(err) {
                console.error(err);
            });
    })
    .catch(function(err) {
        console.error(err);
    });

只要字符串被编码成一个数组,应该只需要把数组的另一端变成一个字符串:

$decrypted = openssl_decrypt(
    $EncryptedData,
    'AES-256-CBC',
    $AesKeyData,
    OPENSSL_NO_PADDING,
    $InitializationVectorData
);

您真的也应该使用AES-GCM,它是一种经过身份验证的模式,肯定也会在PHP中得到支持。

 类似资料:
  • 我只想用这3种模式测试openSSL中的AES:128192和256密钥长度,但我解密的文本与我的输入不同,我不知道为什么。此外,当我传递一个巨大的输入长度(比如1024字节)时,我的程序显示。。。我的意见总是一样的,但这并不重要,至少现在是这样。代码如下: 编辑: 当我将输出大小更改为而不是时,我得到了结果: 那么,是否有可能存在Outpus大小和IV大小的问题?它们应该有什么尺寸(AES-CB

  • 我希望有一个用C编写的程序,可以在没有openssl这样的大型库的帮助下,用AES-CBC对字符串进行编码/解码。 目标: 使用密码短语对字符串进行编码/解码: 因此,应用程序需要接受3个输入参数。。。 输入字符串(待编码)/或已编码字符串(待解码) 用于编码/解码字符串的密码 编码或解码指示器 我对C语言不熟悉(我可以用C#编码)。 我已经找到了https://github.com/kokke/

  • 我遇到的情况是,JSON在PHP的中加密,需要在JAVA中解密。 此包含正确的数据,现在已解密。 现在,问题是当我试图做同样的事情在Java它不起作用:( 这是: 我已经访问了类似的问题,如 AES-256 CBC用php加密,用Java解密,反之亦然 openssl_在java中加密256个CBC原始_数据 无法在Java和PHP之间交换使用AES-256加密的数据 名单还在继续。。。。但是运气

  • Java输出: PHP输出: 生成的密码是不同的,即使它们使用相同的密钥和 IV。这怎么可能?

  • 就像我说的,一切都很好,除了这个小的decypt...我搜索了谷歌和所有的东西,尝试了示例代码,但似乎我的代码有些东西不对。