I got a code to encrypt some text in PHP, it looks like this:
$key = '1234aaaff80b56233525ac2355ac3456'; // something like this
$utf16Content = \mb_convert_encoding('Some text', 'UTF-16LE');
$cipher = 'aes-256-gcm';
$nonceLength = \openssl_cipher_iv_length($cipher);
$nonce = \openssl_random_pseudo_bytes($nonceLength);
$encryptedContent = \openssl_encrypt($utf16Content, $cipher, $key, $options=0, $nonce, $tag);
echo 'Nonce: '.\base64_encode($nonce);
echo 'Auth Tag: '.\base64_encode($tag);
echo 'Content: '.$encryptedContent;
How could I implement the same behavior in JS webcrypto? (I need that for the k6 tests) I found a documentation but it isn't clear for me.
For now I have code like this but I cannot decrypt that successfully so I guess something isn't right.
const rawKey = Uint8Array.from(new String('1234aaaff80b56233525ac2355ac3456'), (x) => x.charCodeAt(0));
const key = await crypto.subtle.importKey(
'raw',
rawKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
const nonce = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt({
name: 'AES-GCM',
iv: nonce,
tagLength: 128,
},
key,
stringToArrayBuffer('Some text')
);
const sentData = {};
sentData.content = b64encode(encrypted);
sentData.nonce = b64encode(nonce);
sentData.authTag = b64encode(GetTag(encrypted, 128));
function stringToArrayBuffer(str) {
const buf = new ArrayBuffer(str.length * 2);
const bufView = new Uint16Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function GetTag(encrypted, tagLength) {
if (tagLength === void 0) tagLength = 128;
return encrypted.slice(encrypted.byteLength - ((tagLength + 7) >> 3))
}
I think the main problem is creating correct authTag
and changing String rawKey to ArrayBuffer.
BTW decription code looks like this (PHP):
// $content, $nonce, $authenticationTag - from PHP encription script output
$content = \base64_decode($content, true);
$nonce = \base64_decode($nonce, true);
$authenticationTag = \base64_decode($authenticationTag, true);
$result = \openssl_decrypt(
$content,
'aes-256-gcm',
'1234aaaff80b56233525ac2355ac3456',
\OPENSSL_RAW_DATA,
$nonce,
$authenticationTag
);
For the record: I figured out how I can get authTag
from encrypted text using k6/experimental/webcrypto
import { crypto } from 'k6/experimental/webcrypto';
const encrypted = await crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: nonce,
tagLength: 128,
},
key,
plaintext
);
const [ value, authTag] = [
encrypted.slice(0, encrypted.byteLength - 16),
encrypted.slice(encrypted.byteLength - 16),
];