为了实现我所写的主题,我有这个 php 代码:
<?php
require 'vendor/autoload.php';
use phpseclib3\Crypt\AES; // Per l'encryptMessage
use phpseclib3\Crypt\Random; // Per la generateSharedKey
function generateSharedKey() {
return base64_encode(Random::string(16));
}
function encryptMessage($messaggio_da_criptare, $chiave) {
$aes = new AES('gcm');
$aes->setKey($chiave);
$iv=base64_encode(openssl_random_pseudo_bytes(12));
$aes->setNonce($iv);
$testo_cifrato = $aes->encrypt($messaggio_da_criptare);
$tag = $aes->getTag();
$dati_criptati = ['messaggio_criptato_con_tag' => base64_encode($testo_cifrato.$tag),'iv' => $iv];
return $dati_criptati;
}
$messaggio = "Hello, this is a secret message!";
echo "Messaggio di esempio da criptare: ".$messaggio."<br>";
$chiave = generateSharedKey();
echo "Chiave segreta: ".$chiave."<br>";
$dati_criptati = encryptMessage($messaggio, $chiave);
echo "Messaggio criptato con tag incluso: ".$dati_criptati["messaggio_criptato_con_tag"]."<br>";
echo "IV: ".$dati_criptati["iv"]."<br>";
?>
还有这个html代码
<!DOCTYPE html>
<html>
<script>
var phpkey = "TWw4QCkeZEnXoCDkI1GEHQ==";
var phpiv = "CRKTyQoWdWB2n56f";
var phpmessageencrypted = "7K+HAB7Ch9V4jJ1XJPM0sANXA2ocJok=";
(async () => {
function _base64ToArrayBuffer(base64) {
var binary_string = atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
async function _importKeyAes(key) {
return await window.crypto.subtle.importKey("raw",key,{ name: "AES-GCM" },false,["encrypt", "decrypt"]);
}
async function decryptMessageSymetric(key, data, iv) {
var keyArrayBuffer = _base64ToArrayBuffer(key);
var keyt = await _importKeyAes(keyArrayBuffer);
var ivt = new TextEncoder().encode(iv);
var datat = _base64ToArrayBuffer(data);
var result = await window.crypto.subtle.decrypt({ name: "AES-GCM", iv: ivt, tagLength: 128 },keyt,datat);
return new TextDecoder().decode(result);
}
var result = await decryptMessageSymetric(phpkey, phpmessageencrypted, phpiv);
console.log(result);
})();
</script>
</html>type here
问题是: 如果您启动 php 脚本并使用如下在线工具测试结果: 文字 它有效并且似乎加密步骤是正确的。
如果您启动 html 页面并与检查员进行检查,则使用提供的示例数据它可以工作。
但是,如果你更换:
var phpkey = "TWw4QCkeZEnXoCDkI1GEHQ=="; var phpiv = "CRKTyQoWdWB2n56f"; var phpmessageencrypted = "7K+HAB7Ch9V4jJ1XJPM0sANXA2ocJok=";
使用 php 给定的数据,它不起作用,浏览器给出以下(且无用的)错误代码:
Uncaught (in promise) DOMException: The operation failed for an operation-specific reason
而在线工具报告了这一点:
我真的不知道我做错了什么。可能与 KEY 和 IV 有关,但为什么它们被在线工具接受,而不被 html/js 脚本接受?
感谢您的帮助。
我期待它以确定性的方式工作。
问题在于,在 PHP 代码中,直接使用 Base64 编码密钥,即不进行 Base64 解码。如果这也是在 JavaScript 代码中完成的,则解密有效,如以下示例所示(数据是使用您发布的 PHP 代码生成的):
// Attention: works e.g. in Firefox, but not in Chrome and Chrome-based browsers, for an explanation see below!
var phpkey = "YIUDaeHCjlX3gQb2nxFIxg==";
var phpiv = "BwKuWNyG/PBKr4H/";
var phpmessageencrypted = "J1DQz24HB6ka4tZhhz08hV3TrMIrms/+56ah8n2z3N02LeDEYWzIBIMH2BC6RcyW";
(async () => {
function _base64ToArrayBuffer(base64) {
var binary_string = atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
async function _importKeyAes(key) {
return await window.crypto.subtle.importKey("raw",key,{ name: "AES-GCM" },false,["encrypt", "decrypt"]);
}
async function decryptMessageSymetric(key, data, iv) {
// var keyArrayBuffer = _base64ToArrayBuffer(key);
var keyArrayBuffer = new TextEncoder().encode(key); // Fix!
var keyt = await _importKeyAes(keyArrayBuffer);
var ivt = new TextEncoder().encode(iv);
var datat = _base64ToArrayBuffer(data);
var result = await window.crypto.subtle.decrypt({ name: "AES-GCM", iv: ivt, tagLength: 128 },keyt,datat);
return new TextDecoder().decode(result);
}
var result = await decryptMessageSymetric(phpkey, phpmessageencrypted, phpiv);
console.log(result);
})();
请注意,如果没有 Base64 解码 24 字节密钥,则使用 AES-192!因此,
该代码不适用于 Chrome 和基于 Chrome 的浏览器,因为它们不支持 AES-192。可以运行代码的可能浏览器是 Firefox。
但是,使用 AES-192,尤其是浏览器限制可能不是您想要的,而是使用 AES-128 以及对 Chrome 和基于 Chrome 的浏览器的支持。generateSharedKey()
提供的密钥是 Base64 编码的,因此在解密之前必须对其进行 Base64 解码:
...
$chiave = generateSharedKey(); // Base64 encoded key
echo "Chiave segreta: ".$chiave."<br>";
$dati_criptati = encryptMessage($messaggio, base64_decode($chiave)); // Fix: Base64 decode key before encryption
...
无需修复 JavaScript 代码。