fix: Poly1305 MAC accumulation bug

- Fixed ChaCha20-Poly1305 to properly accumulate data across multiple calls
- Changed from repeated se050_poly1305_mac() calls to poly1305_init/update/final
- Now correctly detects ciphertext tampering and AAD mismatches
- WireGuard packet encryption/decryption tests still failing - further investigation needed

Test results: 28 passed, 4 failed (improved from 12 failed)
This commit is contained in:
km
2026-03-28 20:34:57 +09:00
parent 999e7a6e19
commit 0210082b8c
2 changed files with 45 additions and 27 deletions
+42 -24
View File
@@ -591,43 +591,49 @@ int se050_chacha20_poly1305_encrypt(se050_chacha20_poly1305_ctx_t *ctx,
if (ctx) { if (ctx) {
key = ctx->key; key = ctx->key;
} else { } else {
/* One-shot mode requires key to be passed differently */
/* For now, return error - ctx is required */
return -1; return -1;
} }
/* Generate Poly1305 key using ChaCha20 */ /* Generate Poly1305 key using ChaCha20 */
uint8_t poly_key[32] = {0}; uint8_t poly_key[32] = {0};
uint8_t block[64]; uint8_t block[64];
se050_chacha20_block(block, ctx->key, 0, nonce); se050_chacha20_block(block, key, 0, nonce);
memcpy(poly_key, block, 32); memcpy(poly_key, block, 32);
/* Compute MAC over AAD + ciphertext */ /* Compute MAC over AAD + ciphertext using state */
uint8_t mac_key[32]; uint8_t mac_key[32];
memcpy(mac_key, poly_key, 32); memcpy(mac_key, poly_key, 32);
se050_poly1305_mac(tag, mac_key, aad, aad_len);
poly1305_state_t st;
poly1305_init(&st, mac_key);
/* Process AAD */
poly1305_update(&st, aad, aad_len);
/* Pad AAD */ /* Pad AAD */
uint8_t pad[16] = {0}; uint8_t pad[16] = {0};
size_t aad_pad = (16 - (aad_len % 16)) % 16; size_t aad_pad = (16 - (aad_len % 16)) % 16;
if (aad_pad) se050_poly1305_mac(tag, mac_key, pad, aad_pad); if (aad_pad) poly1305_update(&st, pad, aad_pad);
/* Encrypt plaintext */ /* Encrypt plaintext */
se050_chacha20(ciphertext, plaintext, plaintext_len, ctx->key, 1, nonce); se050_chacha20(ciphertext, plaintext, plaintext_len, key, 1, nonce);
/* Continue MAC over ciphertext */ /* Process ciphertext */
se050_poly1305_mac(tag, mac_key, ciphertext, plaintext_len); poly1305_update(&st, ciphertext, plaintext_len);
/* Pad ciphertext */ /* Pad ciphertext */
size_t ct_pad = (16 - (plaintext_len % 16)) % 16; size_t ct_pad = (16 - (plaintext_len % 16)) % 16;
if (ct_pad) se050_poly1305_mac(tag, mac_key, pad, ct_pad); if (ct_pad) poly1305_update(&st, pad, ct_pad);
/* Append lengths */ /* Append lengths */
uint8_t lengths[16]; uint8_t lengths[16];
memset(lengths, 0, 16); memset(lengths, 0, 16);
memcpy(lengths, &aad_len, 8); memcpy(lengths, &aad_len, 8);
memcpy(lengths + 8, &plaintext_len, 8); memcpy(lengths + 8, &plaintext_len, 8);
se050_poly1305_mac(tag, mac_key, lengths, 16); poly1305_update(&st, lengths, 16);
/* Finalize MAC */
poly1305_final(&st, tag);
/* Zeroize poly key */ /* Zeroize poly key */
memzero_explicit(poly_key, 32); memzero_explicit(poly_key, 32);
@@ -655,41 +661,53 @@ int se050_chacha20_poly1305_decrypt(se050_chacha20_poly1305_ctx_t *ctx,
uint8_t mac_key[32]; uint8_t mac_key[32];
memcpy(mac_key, poly_key, 32); memcpy(mac_key, poly_key, 32);
/* Compute expected MAC */ /* Compute expected MAC using state */
uint8_t expected_tag[16]; poly1305_state_t st;
se050_poly1305_mac(expected_tag, mac_key, aad, aad_len); poly1305_init(&st, mac_key);
/* Process AAD */
poly1305_update(&st, aad, aad_len);
/* Pad AAD */
uint8_t pad[16] = {0}; uint8_t pad[16] = {0};
size_t aad_pad = (16 - (aad_len % 16)) % 16; size_t aad_pad = (16 - (aad_len % 16)) % 16;
if (aad_pad) se050_poly1305_mac(expected_tag, mac_key, pad, aad_pad); if (aad_pad) poly1305_update(&st, pad, aad_pad);
se050_poly1305_mac(expected_tag, mac_key, ciphertext, ciphertext_len); /* Process ciphertext */
poly1305_update(&st, ciphertext, ciphertext_len);
/* Pad ciphertext */
size_t ct_pad = (16 - (ciphertext_len % 16)) % 16; size_t ct_pad = (16 - (ciphertext_len % 16)) % 16;
if (ct_pad) se050_poly1305_mac(expected_tag, mac_key, pad, ct_pad); if (ct_pad) poly1305_update(&st, pad, ct_pad);
/* Append lengths */
uint8_t lengths[16]; uint8_t lengths[16];
memset(lengths, 0, 16); memset(lengths, 0, 16);
memcpy(lengths, &aad_len, 8); memcpy(lengths, &aad_len, 8);
memcpy(lengths + 8, &ciphertext_len, 8); memcpy(lengths + 8, &ciphertext_len, 8);
se050_poly1305_mac(expected_tag, mac_key, lengths, 16); poly1305_update(&st, lengths, 16);
/* Finalize MAC */
uint8_t expected_tag[16];
poly1305_final(&st, expected_tag);
/* Constant-time comparison */ /* Constant-time comparison */
int ret = 0;
if (crypto_memneq(expected_tag, tag, 16) != 0) { if (crypto_memneq(expected_tag, tag, 16) != 0) {
memzero_explicit(poly_key, 32); ret = -1;
memzero_explicit(mac_key, 32);
memzero_explicit(block, 64);
return -1;
} }
/* Decrypt ciphertext */ /* Only decrypt if MAC is valid */
if (ret == 0) {
se050_chacha20(plaintext, ciphertext, ciphertext_len, ctx->key, 1, nonce); se050_chacha20(plaintext, ciphertext, ciphertext_len, ctx->key, 1, nonce);
}
/* Zeroize sensitive data */
memzero_explicit(poly_key, 32); memzero_explicit(poly_key, 32);
memzero_explicit(mac_key, 32); memzero_explicit(mac_key, 32);
memzero_explicit(block, 64); memzero_explicit(block, 64);
return 0; return ret;
} }
int se050_wireguard_encrypt(const uint8_t key[WG_KEY_SIZE], int se050_wireguard_encrypt(const uint8_t key[WG_KEY_SIZE],
+2 -2
View File
@@ -315,7 +315,7 @@ int se050_wireguard_decrypt_packet(se050_wireguard_session_t *session,
memset(nonce_buf, 0, 4); memset(nonce_buf, 0, 4);
memcpy(nonce_buf + 4, packet + 8, 8); memcpy(nonce_buf + 4, packet + 8, 8);
size_t ciphertext_len = packet_len - 16 - 16; /* Total - header - tag */ size_t ciphertext_len = plaintext_len = packet_len - 16 - 16; /* Total - header - tag */
uint8_t tag[16]; uint8_t tag[16];
memcpy(tag, packet + 16 + ciphertext_len, 16); memcpy(tag, packet + 16 + ciphertext_len, 16);
@@ -337,7 +337,7 @@ int se050_wireguard_decrypt_packet(se050_wireguard_session_t *session,
return -1; return -1;
} }
/* Update nonce */ /* Update plaintext length and nonce */
*plaintext_len = ciphertext_len; *plaintext_len = ciphertext_len;
session->receiving_nonce = nonce; session->receiving_nonce = nonce;