I have some code in JavaScript running inside the browser using WebCrypto. It uses AES-GCM to encrypt some data.
I generate a key and then export it to hex, then generate an initialization vector, and then use that to encode some data which I convert to hex as well.
function generateKey() {
window.crypto.subtle
.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"],
)
.then(key => {
log('Got key back');
setKey(key);
})
}
// Export the given key and write it into the "exported-key" space.
async function exportCryptoKey(key) {
const exported = await window.crypto.subtle.exportKey("raw", key);
const exportedKeyBuffer = new Uint8Array(exported);
hex = buf2hex(exportedKeyBuffer);
log('HEX is', hex );
}
function buf2hex(buffer) { // buffer is an ArrayBuffer
return [...new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join('');
}
function setKey(_key) {
log('Key is', key);
key = _key;
if (key.extractable) {
exportCryptoKey(key);
} else {
log('Cannot export key, sadface');
}
}
async function encrypt() {
log('Key is', key );
const iv = window.crypto.getRandomValues(new Uint8Array(16));
let enc = new TextEncoder();
const data = enc.encode('Hi there');
const result = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv,
},
key,
data
);
encrypted = new Uint8Array(result);
log('Encrypted is', buf2hex(encrypted));
log('IV is', buf2hex(iv));
}
I want to decode it using python. I see some python examples use a nonce with some of the data plucked out. Is that the same as the initialization vector used in the JavaScript? What is wrong? When I run the python code, I get Decryption failed
# pip install pycryptodome
from Crypto.Cipher import AES
hex_key = '0db43c44650a8b71547dbc6951432f0c545509814d6bca1a10e387ad2d16bc4a'
encrypted_message = '37183efb9e4ce92265d1144110cdbe1e768a85f9630bf872'
iv = '43005ad454f6e3c6e3ead90f7137f007'
key = bytes.fromhex(hex_key)
data = bytes.fromhex(encrypted_message)
nonce = bytes.fromhex(iv)
cipher = AES.new(key, AES.MODE_GCM, nonce)
try:
dec = cipher.decrypt_and_verify(data, nonce) # ciphertext, tag
print(dec)
except ValueError:
print("Decryption failed")
cipher.decrypt_and_verify(data[:-16], data[-16:]). Note that for GCM a 12 bytes IV/nonce is recommended.cipherobject:cipher = AES.new(key, AES.MODE_GCM, nonce)The tag is required during authentication:dec = cipher.decrypt_and_verify(data[:-16], data[-16:]). Neither IV/nonce nor tag are secret.