I am trying to have AES encryption on the server side, and decryption on the client side. I have followed an example where CryptoJS is used on the client side for encryption and SubtleCrypto on the client side as well for decryption, but in my case I have the encryption and decryption separated.
Suppose I have the following encryption function within React Native:
const encrypt = (str: string) => {
const iv = crypto.randomBytes(12);
const myHexToken = "0x...."
const cipher = crypto.createCipheriv('aes-256-gcm', myHexToken.slice(0,32), iv)
let encrypted = cipher.update(str, 'utf8', 'hex')
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
return {
message: encrypted,
tag: tag.toString('hex'),
iv: iv.toString('hex'),
};
};
This json is then posted to the client through a webview postMessage.
The client side has the following javascript injected:
var myHexToken = "0x....";
window.addEventListener("message", async function (event) {
var responseData = JSON.parse(event.data);
try {
var decryptedData = await decrypt(responseData.iv, responseData.message, responseData.tag);
} catch (e) {
alert(e);
}
// ...
How can I decrypt responseData.message
within the WebView through SubtleCrypto of the Web Crypto API?
I have tried various things with the following methods, but I keep getting "OperationalError":
function fromHex(hexString) {
return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
}
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function fromBase64(base64String) {
return Uint8Array.from(window.atob(base64String), c => c.charCodeAt(0));
}
async function importKey(rawKey) {
var key = await crypto.subtle.importKey(
"raw",
rawKey,
"AES-GCM",
true,
["encrypt", "decrypt"]
);
return key;
}
async function decrypt(iv, data, tag) {
var rawKey = fromHex(myHexToken.slice(0,32));
var iv = fromHex(iv);
var ciphertext = str2ab(data + tag);
var cryptoKey = await importKey(rawKey)
var decryptedData = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
},
cryptoKey,
ciphertext
)
var decoder = new TextDecoder();
var plaintext = decoder.decode(decryptedData);
return plaintext;
}
UPDATE 1: Added the getAuthTag implementation server side. Changed IV to have length of 12 bytes. Attempt to concatenate ciphertext and tag client side.
I have verified that "myHexToken" is the same both client and server side. Also, the return values of the server side "encrypt()" method are correctly sent to the client.