fix(crypto): forbid zero-length IV in AES-GCM
What changed, and why it matters
This commit tightens validation in the hardware wallet's AES-GCM encryption code by rejecting initialization vectors (IVs) of length zero. Previously, a zero-length IV was silently accepted, which violates the NIST standard and can lead to weak or broken encryption. The change also makes the higher-level encrypt/decrypt functions properly report this error instead of ignoring it.
Verify that all callers of gcm_encrypt_message/gcm_decrypt_message handle RETURN_ERROR correctly, and audit other cryptographic entry points for similar missing IV/nonce length validation and ignored error codes.
Security signals we found
Violation of NIST SP 800-38D (AES-GCM IV must not be zero length)
Missing input validation on cryptographic parameter
Ignored return value from security-critical initialization function
Potential nonce/IV misuse in authenticated encryption
Evidence from the diff
In crypto/aes/aesgcm.c, gcm_init_message() now returns RETURN_ERROR when iv_len == 0, citing NIST SP 800-38D Section 5.2.1.1. The wrapper functions gcm_encrypt_message() and gcm_decrypt_message() now check the return value of gcm_init_message() and propagate RETURN_ERROR. Before this patch, a zero-length IV would fall through to memset() and subsequent IV handling, and the wrappers ignored any failure from gcm_init_message().
Changed components
crypto/aes/aesgcm.cgcm_init_message()gcm_encrypt_message()gcm_decrypt_message()Inspect captured patch +9 / −2
diff --git a/crypto/aes/aesgcm.c b/crypto/aes/aesgcm.c
index 96b029fb..b488ae69 100644
--- a/crypto/aes/aesgcm.c
+++ b/crypto/aes/aesgcm.c
@@ -165,6 +165,11 @@ ret_type gcm_init_message( /* initialise a new message */
{ uint32_t i = 0, n_pos = 0;
uint8_t *p = NULL;
+ /* NIST SP 800-38D, Section 5.2.1.1 forbids IV length of 0 */
+ /* https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf */
+ if(iv_len == 0)
+ return RETURN_ERROR;
+
memset(ctx->ctr_val, 0, BLOCK_SIZE);
if(iv_len == CTR_POS)
{
@@ -517,7 +522,8 @@ ret_type gcm_encrypt_message( /* encrypt an entire message */
unsigned long tag_len, /* and its length in bytes */
gcm_ctx ctx[1]) /* the mode context */
{
- gcm_init_message(iv, iv_len, ctx);
+ if(gcm_init_message(iv, iv_len, ctx) != RETURN_GOOD)
+ return RETURN_ERROR;
gcm_auth_header(hdr, hdr_len, ctx);
gcm_encrypt(msg, msg_len, ctx);
return gcm_compute_tag(tag, tag_len, ctx) ? RETURN_ERROR : RETURN_GOOD;
@@ -536,7 +542,8 @@ ret_type gcm_decrypt_message( /* decrypt an entire message */
{ uint8_t local_tag[BLOCK_SIZE] = {0};
ret_type rr = 0;
- gcm_init_message(iv, iv_len, ctx);
+ if(gcm_init_message(iv, iv_len, ctx) != RETURN_GOOD)
+ return RETURN_ERROR;
gcm_auth_header(hdr, hdr_len, ctx);
gcm_decrypt(msg, msg_len, ctx);
rr = gcm_compute_tag(local_tag, tag_len, ctx);
Why this scored 44/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.