Skip to content

crypto Decipher: setAuthTag() must be called before update() #22421

Closed
@achronos0

Description

@achronos0
  • Version: v8.11.3
  • Platform: Darwin foo.local 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64
  • Subsystem: crypto

crypto Decipher docs say that setAuthTag() must be called before final().
In fact setAuthTag must be called before any call to update(), in GCM mode at least.

If you call update() before setAuthTag(), final() will throw regardless of the correctness of the ciphertext and tag.

Test case:

const authTagBeforeUpdate = false; // true works, false throws

const crypto = require('crypto');
const cleartext = Buffer.from("abcdefghijklmnopqrstuvwxyz0123");
const key = Buffer.from("abcdefghijklmnopqrstuvwxyz012345");
const iv = Buffer.from("0123456789ab");
console.log('cleartext', cleartext);
console.log('key      ', key);
console.log('iv       ', iv);

const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const ciphertext = Buffer.concat([cipher.update(cleartext), cipher.final()]);
const authTag = cipher.getAuthTag();
console.log('authTag  ', authTag);

const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
if (authTagBeforeUpdate) {
    decipher.setAuthTag(authTag);
}
let result_update = decipher.update(ciphertext);
if (!authTagBeforeUpdate) {
    decipher.setAuthTag(authTag);
}
let result_final = decipher.final();
let result_cleartext = Buffer.concat([result_update, result_final]);
console.log('result   ', result_cleartext);

I suggest changing the API docs to make it clear that the auth tag must be supplied before any data is read in. setAuthTag() must be called before final() and should be called before any call to update().

Second: is this actually the desired behaviour?

As far as I can tell, there is no requirement for GCM to know the auth tag prior to deciphering data. OpenSSL's own example provides it after EVP_DecryptUpdate, before EVP_DecryptFinal_ex (https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Decryption_using_GCM_mode).

In cases where the auth tag is appended to the ciphertext (e.g. Java), as things stand the entire ciphertext must be buffered. For large data this is a serious problem. It would make more sense to decrypt chunks as they are received, treating them carefully and discarding everything if the auth tag eventually proves to be incorrect.

Metadata

Metadata

Assignees

Labels

cryptoIssues and PRs related to the crypto subsystem.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions