我们有一个世博反应本地项目使用加密。我们当前的加密基于SubtleCrypto / Web window.subtle.crypto,使用的是AES-GCM 128,现在我们需要使用一个在所有平台上普遍可用的库-- Web、iOS和Android。从我前面的问题中,我们找到了支持GCM模式的SJCL,我们可以完全替换所有基于web的代码,但挑战是我们需要确保所有当前加密的数据也在这个新的库中解密,我们必须这样做:
window.crypto.subtle.encrypt AES-GCM 128 => (a) -> SJCL.mode.gcm.decrypt(a)
一旦我们成功地做到了这一点,我们就可以完全取代这个库,并具有通用的平台支持和向后兼容性。
这意味着我们根本无法改变加密的处理方式,因为这是必需的,而且我们正在加密它,就像下面的代码一样。
我通过一条很好的线索获得了Neneil94,但在编码/格式方面仍然面临问题;下面是当前的代码:
function arrayBufferToString(buffer){
var str = "";
for (var iii = 0; iii < buffer.byteLength; iii++){
str += String.fromCharCode(buffer[iii]);
}
return str;
}
const generateKey = async () =>
{
const key = await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 128
}, true, ["encrypt", "decrypt"]);
const key_exported = await window.crypto.subtle.exportKey("jwk", key);
return key_exported.k;
}
const text = "This is an encrypted message";
const printCurrent = async () =>
{
let kkey = await generateKey();
await window.crypto.subtle.importKey(
"jwk",
{
k: kkey,
alg: "A128GCM",
ext: true,
key_ops: ["encrypt", "decrypt"],
kty: "oct",
},
{
name: "AES-GCM",
length: 128
},
false,
["encrypt", "decrypt"]
).then(function(key)
{
window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: new Uint8Array(12)
}, key, new TextEncoder().encode(JSON.stringify(text))).then(function(encryptedObject)
{
console.log({kkey}); //{kkey: 'eKM_Cen2Z-jhedM284cltA'}
let bkey = sjcl.codec.utf8String.toBits(kkey);
console.log({bkey}); //{bkey: Array(6)}
let cipher = new sjcl.cipher.aes(bkey);
//let bdata = sjcl.codec.base64.toBits(encryptedObject); //gives error of a.replace
let bdata = arrayBufferToString(encryptedObject);
let ivvv = new Uint8Array(12);
let ivv = Buffer.from(ivvv).toString('base64');
let ive = sjcl.codec.base64.toBits(ivv);
// decrypt
let decbits = sjcl.mode.gcm.decrypt(cipher, bdata, ive);
// convert into utf8string
decryptedData = sjcl.codec.utf8String.fromBits(decbits);
});
});
}我得到的错误是:
损坏: gcm:标记不匹配
我不知道aesKey在Neneil上面链接的代码到底是什么,是CryptoKey对象还是从JsonWebKey生成的22个字符?对于“encryptedObject”,我将如何将其转换为BitArray。对于静脉输液,我只是提供了加密所做的事情,但我也不确定..
尽管如此,任何洞察力都会很有帮助,谢谢你的时间!
发布于 2021-12-12 11:25:00
代码中有两个问题:
kkey是Base64url编码的原始密钥。这必须首先转换为Base64,然后转换为bitArray。let kkeyB64 = kkey.replace(/-/g, '+').replace(/_/g, '/'); // Base64url -> Base64 (ignore optional padding)
let bkey = sjcl.codec.base64.toBits(kkeyB64); // conert to bitArray<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sjcl@1.0.8/core/codecArrayBuffer.js"></script>let bdata = sjcl.codec.arrayBuffer.toBits(encryptedObject)
let ive = sjcl.codec.arrayBuffer.toBits(new Uint8Array(12).buffer)通过这些更改,使用sjcl解密是成功的。
完整代码:
const generateKey = async () =>
{
const key = await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 128
}, true, ["encrypt", "decrypt"]);
const key_exported = await window.crypto.subtle.exportKey("jwk", key);
return key_exported.k;
}
const text = "This is an encrypted message";
const printCurrent = async () =>
{
let kkey = await generateKey();
await window.crypto.subtle.importKey(
"jwk",
{
k: kkey,
alg: "A128GCM",
ext: true,
key_ops: ["encrypt", "decrypt"],
kty: "oct",
},
{
name: "AES-GCM",
length: 128
},
false,
["encrypt", "decrypt"]
).then(function(key)
{
window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: new Uint8Array(12)
}, key, new TextEncoder().encode(JSON.stringify(text))).then(function(encryptedObject)
{
//console.log({kkey}); //{kkey: 'eKM_Cen2Z-jhedM284cltA'}
let kkeyB64 = kkey.replace(/-/g, '+').replace(/_/g, '/'); // Fix 1
let bkey = sjcl.codec.base64.toBits(kkeyB64);
//console.log({bkey}); //{bkey: Array(6)}
let cipher = new sjcl.cipher.aes(bkey);
let bdata = sjcl.codec.arrayBuffer.toBits(encryptedObject) // Fix 2
let ive = sjcl.codec.arrayBuffer.toBits(new Uint8Array(12).buffer) // Fix 3
// decrypt
let decbits = sjcl.mode.gcm.decrypt(cipher, bdata, ive);
// convert into utf8string
decryptedData = sjcl.codec.utf8String.fromBits(decbits);
document.getElementById("pt").innerHTML = JSON.parse(decryptedData);
});
});
}
printCurrent();<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sjcl@1.0.8/sjcl.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sjcl@1.0.8/core/codecArrayBuffer.js"></script>
<p style="font-family:'Courier New', monospace;" id="pt"></p>
如果由于某些原因(我不确定),ArrayBuffer编解码器在您的环境中不可用,那么ArrayBuffer也可以显式十六进制或Base64编码,然后转换为bitArray,例如:
// https://stackoverflow.com/a/40031979/9014097
function buf2hex(buffer) {
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
...
let bdata = sjcl.codec.hex.toBits(buf2hex(encryptedObject))
let ive = sjcl.codec.hex.toBits(buf2hex(new Uint8Array(12).buffer)) 安保:
静态IV (与new Uint8Array(12)一样)是GCM上下文中的致命错误,例如这里。相反,将为每个加密生成一个随机IV,这些加密将与密文一起传递(通常是级联的)。因此,除非静态IV只用于测试目的,否则这必须是固定的。
https://stackoverflow.com/questions/70321733
复制相似问题