oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
71.73k stars 2.55k forks source link

AES-GCM fails with empty data #1466

Open panva opened 1 year ago

panva commented 1 year ago

What version of Bun is running?

No response

What platform is your computer?

No response

What steps can reproduce the bug?

const name = "AES-GCM";
const key = await crypto.subtle.generateKey({ name, length: 128 }, false, [
  "encrypt",
  "decrypt",
]);
const data = new Uint8Array();
const iv = crypto.getRandomValues(new Uint8Array(16));
const algorithm = { name, iv, tagLength: 128 };

const ciphertext = await crypto.subtle.encrypt(algorithm, key, data);

await crypto.subtle.decrypt(algorithm, key, ciphertext);

How often does it reproduce? Is there a required condition?

No response

What is the expected behavior?

No response

What do you see instead?

OperationError: The operation failed for an operation-specific reason

Additional information

No response

Jarred-Sumner commented 1 year ago

I think line 96 is returning an error:

https://github.com/oven-sh/bun/blob/be9bab5c297756f3548345b8b9e78e809ddbcfca/src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_GCMOpenSSL.cpp#L95-L98

From openssl/cipher.h:

// EVP_EncryptFinal_ex writes at most a block of ciphertext to |out| and sets
// |*out_len| to the number of bytes written. If padding is enabled (the
// default) then standard padding is applied to create the final block. If
// padding is disabled (with |EVP_CIPHER_CTX_set_padding|) then any partial
// block remaining will cause an error. The function returns one on success and
// zero otherwise.
OPENSSL_EXPORT int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out,
                                       int *out_len);

So I'm guessing that "any partial block remaining" is the problem.

image
Jarred-Sumner commented 1 year ago

@robobun

test repro bot

const name = "AES-GCM";
const key = await crypto.subtle.generateKey({ name, length: 128 }, false, [
  "encrypt",
  "decrypt",
]);
const data = new Uint8Array();
const iv = crypto.getRandomValues(new Uint8Array(16));
const algorithm = { name, iv, tagLength: 128 };

const ciphertext = await crypto.subtle.encrypt(algorithm, key, data);

console.log(await crypto.subtle.decrypt(algorithm, key, ciphertext));
Jarred-Sumner commented 1 year ago

@robobun

test #2

const name = "AES-GCM";
const key = await crypto.subtle.generateKey({ name, length: 128 }, false, [
  "encrypt",
  "decrypt",
]);
const data = new Uint8Array();
const iv = crypto.getRandomValues(new Uint8Array(16));
const algorithm = { name, iv, tagLength: 128 };

const ciphertext = await crypto.subtle.encrypt(algorithm, key, data);

console.log(await crypto.subtle.decrypt(algorithm, key, ciphertext));
robobun commented 1 year ago

@Jarred-Sumner here you go!

OperationError: The operation failed for an operation-specific reason
Code ```tsx const name = "AES-GCM"; const key = await crypto.subtle.generateKey({ name, length: 128 }, false, [ "encrypt", "decrypt", ]); const data = new Uint8Array(); const iv = crypto.getRandomValues(new Uint8Array(16)); const algorithm = { name, iv, tagLength: 128 }; const ciphertext = await crypto.subtle.encrypt(algorithm, key, data); console.log(await crypto.subtle.decrypt(algorithm, key, ciphertext)); ```

Ran using the latest build of Bun, an all-in-one JavaScript runtime.

xieyuheng commented 9 months ago

I meet the same issue in my project.

Jarred-Sumner commented 1 week ago

Confirmed this still reproduces in Bun v1.1.15