问题描述
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<script>
let intermediateKey;
let publicKey;
let privateKey;
let wrappedKey;
let iv;
async function rsaKeyPair() {
let keyPair = await crypto.subtle.generateKey({
name: "RSA-OAEP",modulusLength: 4096,publicExponent: new Uint8Array([1,1]),hash: "SHA-256",},true,["wrapKey","unwrapKey"]
);
publicKey = keyPair.publicKey;
privateKey = keyPair.privateKey;
}
async function encrypt(secret) {
// generating random intermediate key to encrypt and decrypt the secret
intermediateKey = await crypto.subtle.generateKey({
name: "aes-gcm",length: 256
},["encrypt","decrypt"]
);
// encrypt secret
// ...
// wrap intermediate key (export + encrypt) intermediateKey using publicKey.
iv = crypto.getRandomValues(new Uint8Array(12));
wrappedKey = await crypto.subtle.wrapKey(
"jwk",intermediateKey,publicKey,{
name: "aes-gcm",iv: iv
}
);
}
async function decrypt(cipher) {
// unwrap (decrypt + import) aes key using private key.
intermediateKey = await crypto.subtle.unwrapKey(
"jwk",wrappedKey,privateKey,iv: iv
},{
name: "aes-gcm"
},false,"decrypt"]
);
// decrypt the cipher
// ...
}
async function solve() {
// generate rsa-keypairs
await rsaKeyPair();
// encrypt secret
const cipher = await encrypt("secret");
// decrypt cipher
await decrypt(cipher);
}
solve();
</script>
</body>
</html>
生成RSA-OAEP密钥对(根据http://www.w3.org/TR/WebCryptoAPI/#algorithm-overview.)
当用户创建机密时,机密会使用 aes-gcm-256 和随机生成的中间密钥进行加密。最后,这个中间密钥用用户的公钥包装起来。
最后解开中间密钥和解密。
在解包中间密钥时产生错误。
解决方法
wrapKey()
和 unwrapKey()
调用都分别缺少用于指定加密密钥的算法的 wrapAlgo
和 unwrapAlgo
参数的正确规范.在此示例中,应用了带有 OAEP 的 RSA,因此必须将 RsaOaepParams
对象用于两个参数。
如果在两个函数中都正确指定了参数,则AES密钥将被正确加密和解密:
let intermediateKey;
let publicKey;
let privateKey;
let wrappedKey;
let iv;
async function rsaKeyPair() {
let keyPair = await crypto.subtle.generateKey(
{
name: 'RSA-OAEP',modulusLength: 4096,publicExponent: new Uint8Array([1,1]),hash: 'SHA-256',},true,['wrapKey','unwrapKey']
);
publicKey = keyPair.publicKey;
privateKey = keyPair.privateKey;
}
async function encrypt() {
// Generate AES key
intermediateKey = await crypto.subtle.generateKey(
{
name: 'AES-GCM',length: 256
},['encrypt','decrypt']
);
// Encrypt secret
// ...
// Wrap AES key
/*
iv = crypto.getRandomValues(new Uint8Array(12));
wrappedKey = await crypto.subtle.wrapKey(
'jwk',intermediateKey,publicKey,{
name: "AES-GCM",iv: iv
}
);
*/
wrappedKey = await crypto.subtle.wrapKey(
'raw',{ // wrapAlgo,here an RsaOaepParams object,s. https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams
name: 'RSA-OAEP'
}
);
console.log('Wrapped AES key: ',new Uint8Array(wrappedKey));
}
async function decrypt() {
// Unwrap AES key
/*
intermediateKey = await crypto.subtle.unwrapKey(
'jwk',wrappedKey,privateKey,iv: iv
},{
name: "AES-GCM"
},false,["encrypt","decrypt"]
);
*/
intermediateKey = await crypto.subtle.unwrapKey(
'raw',{ // unwrapAlgo,s. https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams
name: 'RSA-OAEP'
},{
name: 'AES-GCM'
},'decrypt']
);
console.log('Unwrapped AES key: ',intermediateKey);
// Decrypt ciphertext
// ...
}
async function solve() {
await rsaKeyPair();
await encrypt();
await decrypt();
}
solve();