使用openssl_decrypt在php中解密AES-256-CBC,来自Sirtle Crypto JavaScript有效载荷
我正在尝试使用webcrypto/window.crypto到aes-256-cbc中加密在js中进行 demrypt 它使用php的 openssl_decrypt
功能。
我的问题是,瘫痪功能只是返回 false
,因此似乎不起作用。
const encoder = new TextEncoder();
const encoded = encoder.encode('Hello this is a test.');
const encryptionKey = await window.crypto.subtle.generateKey(
{
name: 'AES-CBC',
length: 256,
},
true,
['encrypt', 'decrypt'],
);
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const cipher = await window.crypto.subtle.encrypt(
{
name: 'AES-CBC',
iv,
},
encryptionKey,
encoded,
);
const exportedKey = await window.crypto.subtle.exportKey(
'jwk',
encryptionKey,
);
console.log(exportedKey.k);
sendToBackend({
cipher: btoa(new Uint8Array(cipher)), // "MTMsMjIzLDE5NSwxNzYsMjA0LDE5MSwxOTYsMjEyLDIwNCwyMzAsMjcsMSwxMjAsMTQzLDE2MSwxMTgsMTYwLDIzOSw4NywyMDksMjQ0LDIwNCwyMzgsODYsMTgzLDIyOCwxMzksMjIwLDcwLDY5LDI0OSwxODQ="
iv: btoa(new Uint8Array(iv)), // "MTQ5LDE2Nyw4LDE2NywyMjAsMTA4LDEwMSw1Niw4Miw3MiwxMjAsMjM5LDE4NCw0OCwyNTIsMTE=",
password: exportedKey.k, // "szq1aOg-F_72vWrdJatWyQp3iOXIus-cE19sO4bSOLs"
});
现在,当我尝试使用PHP在后端解密它时,我会得到 false
:
$key = "szq1aOg-F_72vWrdJatWyQp3iOXIus-cE19sO4bSOLs";
$payload = "MTMsMjIzLDE5NSwxNzYsMjA0LDE5MSwxOTYsMjEyLDIwNCwyMzAsMjcsMSwxMjAsMTQzLDE2MSwxMTgsMTYwLDIzOSw4NywyMDksMjQ0LDIwNCwyMzgsODYsMTgzLDIyOCwxMzksMjIwLDcwLDY5LDI0OSwxODQ=";
$iv = "MTQ5LDE2Nyw4LDE2NywyMjAsMTA4LDEwMSw1Niw4Miw3MiwxMjAsMjM5LDE4NCw0OCwyNTIsMTE=";
$dec = openssl_decrypt($payload, 'AES-256-GCM', $key, false, $iv);
var_dump($dec); // false
我缺少一些东西吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在JavaScript侧,基本64编码失败,从结果的长度可以看出。在以下JavaScript代码中,函数
ab2b64()
用于此转换:可能的输出:
在PHP侧使用了错误的模式,IE GCM必须由CBC替换为与JavaScript代码的兼容性(尽管GCM实际上是更安全的选择)。
此外,钥匙必须是base64url(不是base64),而iv和ciphertext必须是基础64。对于ciphertext and intagit base64解码可以通过设置
openssl_decrypt()
to0
0 :edit: edit:
虽然CBC仅提供机密性,但。
对于JavaScript侧的GCM,必须从
AES> aes-cbc
gentatekey() and codekekey()中的算法() GCM 。 GCM的NONCE的建议长度为12个字节(尽管支持16个字节在内的其他非CEN长度),这需要在> getrandomvalues()
中进行相应的更改:可能的输出是:
如上所述,GCM是一种身份验证的加密模式,并使用标签进行身份验证。 WebCrypto隐式串联ciphertext和TAG(默认情况下为16个字节),而PHP则分别处理。因此,必须将密文和标签在PHP侧分开:
On the JavaScript side, the Base64 encoding fails, as can be seen from the length of the result. In the following JavaScript code the function
ab2b64()
is used for this conversion:Possible output:
On the PHP side the wrong mode is used, i.e. GCM must be replaced by CBC for compatibility with the JavaScript code (although GCM would actually be the more secure choice).
Furthermore, the key must be Base64url (not Base64) decoded, while IV and ciphertext must be Base64 decoded. For the ciphertext an implicit Base64 decoding can be done by setting the 4th parameter of
openssl_decrypt()
to0
:Edit:
While CBC only provides confidentiality, GCM provides confidentiality and authenticity/integrity, making GCM more secure. Note that with CBC, a message authentication code (MAC) can be used so that (in addition to confidentiality) also authenticity is provided; however, the advantage of GCM is that this is done implicitly.
For GCM on the JavaScript side the algorithm in
generateKey()
andencrypt()
must be changed fromAES-CBC
toAES-GCM
. The recommended length of the nonce for GCM is 12 bytes (although other nonce lengths including 16 bytes are supported), which requires a corresponding change ingetRandomValues()
:A possible output is:
As mentioned above, GCM is an authenticated encryption mode and uses a tag for authentication. WebCrypto implicitly concatenates ciphertext and tag (16 bytes long by default) in this order, while PHP processes both separately. Therefore, ciphertext and tag must be separated on the PHP side: