我已经设法让它使用不包含og a-zA-Z0-9之外的字符的文本和一些特殊的字符,但是如果我使用像æøåÆØÅ这样的丹麦字母,那么解密后的文字会显示出来吗?而不是实际的字母。所有文件都保存为UTF-8,标题字符串为charset = utf-8
Javascript ---输入:“测试员æøåÆØÅ#¤%& /”
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);
}
);
}
腓:
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">
已设定。但它是: - )
答案 0 :(得分:2)
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中受到支持。