Module Name: src Committed By: riastradh Date: Fri Jul 26 18:32:15 UTC 2024
Modified Files: src/sys/crypto/sodium: sodium_selftest.h src/sys/external/isc/libsodium/src: sodium_selftest.c Log Message: sys/crypto/sodium: Add self-test for XChaCha20/Poly1305 AEAD. PR kern/58468 To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/crypto/sodium/sodium_selftest.h cvs rdiff -u -r1.1 -r1.2 src/sys/external/isc/libsodium/src/sodium_selftest.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/crypto/sodium/sodium_selftest.h diff -u src/sys/crypto/sodium/sodium_selftest.h:1.1 src/sys/crypto/sodium/sodium_selftest.h:1.2 --- src/sys/crypto/sodium/sodium_selftest.h:1.1 Fri Jul 26 18:25:03 2024 +++ src/sys/crypto/sodium/sodium_selftest.h Fri Jul 26 18:32:15 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: sodium_selftest.h,v 1.1 2024/07/26 18:25:03 riastradh Exp $ */ +/* $NetBSD: sodium_selftest.h,v 1.2 2024/07/26 18:32:15 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -30,6 +30,7 @@ #define _SYS_CRYPTO_SODIUM_SODIUM_SELFTEST_H_ int crypto_aead_chacha20poly1305_ietf_selftest(void); +int crypto_aead_xchacha20poly1305_ietf_selftest(void); int sodium_selftest(void); Index: src/sys/external/isc/libsodium/src/sodium_selftest.c diff -u src/sys/external/isc/libsodium/src/sodium_selftest.c:1.1 src/sys/external/isc/libsodium/src/sodium_selftest.c:1.2 --- src/sys/external/isc/libsodium/src/sodium_selftest.c:1.1 Fri Jul 26 18:25:03 2024 +++ src/sys/external/isc/libsodium/src/sodium_selftest.c Fri Jul 26 18:32:15 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: sodium_selftest.c,v 1.1 2024/07/26 18:25:03 riastradh Exp $ */ +/* $NetBSD: sodium_selftest.c,v 1.2 2024/07/26 18:32:15 riastradh Exp $ */ /*- * Copyright (c) 2024 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ #ifdef _KERNEL #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sodium_selftest.c,v 1.1 2024/07/26 18:25:03 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sodium_selftest.c,v 1.2 2024/07/26 18:32:15 riastradh Exp $"); #include <sys/types.h> @@ -40,7 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: sodium_selft #else #include <sys/cdefs.h> -__RCSID("$NetBSD: sodium_selftest.c,v 1.1 2024/07/26 18:25:03 riastradh Exp $"); +__RCSID("$NetBSD: sodium_selftest.c,v 1.2 2024/07/26 18:32:15 riastradh Exp $"); #include <stdint.h> #include <stdio.h> @@ -70,6 +70,7 @@ hexdump(int (*prf)(const char *, ...) __ #endif #include <crypto/sodium/crypto_aead_chacha20poly1305.h> +#include <crypto/sodium/crypto_aead_xchacha20poly1305.h> #include <crypto/sodium/sodium_selftest.h> /* @@ -321,11 +322,255 @@ crypto_aead_chacha20poly1305_ietf_selfte } int +crypto_aead_xchacha20poly1305_ietf_selftest(void) +{ + /* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.3.1 */ + static const uint8_t plaintext[] = { + 0x4c,0x61,0x64,0x69, 0x65,0x73,0x20,0x61, + 0x6e,0x64,0x20,0x47, 0x65,0x6e,0x74,0x6c, + 0x65,0x6d,0x65,0x6e, 0x20,0x6f,0x66,0x20, + 0x74,0x68,0x65,0x20, 0x63,0x6c,0x61,0x73, + 0x73,0x20,0x6f,0x66, 0x20,0x27,0x39,0x39, + 0x3a,0x20,0x49,0x66, 0x20,0x49,0x20,0x63, + 0x6f,0x75,0x6c,0x64, 0x20,0x6f,0x66,0x66, + 0x65,0x72,0x20,0x79, 0x6f,0x75,0x20,0x6f, + 0x6e,0x6c,0x79,0x20, 0x6f,0x6e,0x65,0x20, + 0x74,0x69,0x70,0x20, 0x66,0x6f,0x72,0x20, + 0x74,0x68,0x65,0x20, 0x66,0x75,0x74,0x75, + 0x72,0x65,0x2c,0x20, 0x73,0x75,0x6e,0x73, + 0x63,0x72,0x65,0x65, 0x6e,0x20,0x77,0x6f, + 0x75,0x6c,0x64,0x20, 0x62,0x65,0x20,0x69, + 0x74,0x2e, + }; + static const uint8_t aad[] = { + 0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3, + 0xc4,0xc5,0xc6,0xc7, + }; + static const uint8_t key[] = { + 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97, + 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f, + }; + static const uint8_t nonce[] = { + 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b, 0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53, 0x54,0x55,0x56,0x57, + 0x00,0x00,0x00,0x00, + }; + static const uint8_t ciphertext[] = { + 0xbd,0x6d,0x17,0x9d, 0x3e,0x83,0xd4,0x3b, + 0x95,0x76,0x57,0x94, 0x93,0xc0,0xe9,0x39, + 0x57,0x2a,0x17,0x00, 0x25,0x2b,0xfa,0xcc, + 0xbe,0xd2,0x90,0x2c, 0x21,0x39,0x6c,0xbb, + 0x73,0x1c,0x7f,0x1b, 0x0b,0x4a,0xa6,0x44, + 0x0b,0xf3,0xa8,0x2f, 0x4e,0xda,0x7e,0x39, + 0xae,0x64,0xc6,0x70, 0x8c,0x54,0xc2,0x16, + 0xcb,0x96,0xb7,0x2e, 0x12,0x13,0xb4,0x52, + 0x2f,0x8c,0x9b,0xa4, 0x0d,0xb5,0xd9,0x45, + 0xb1,0x1b,0x69,0xb9, 0x82,0xc1,0xbb,0x9e, + 0x3f,0x3f,0xac,0x2b, 0xc3,0x69,0x48,0x8f, + 0x76,0xb2,0x38,0x35, 0x65,0xd3,0xff,0xf9, + 0x21,0xf9,0x66,0x4c, 0x97,0x63,0x7d,0xa9, + 0x76,0x88,0x12,0xf6, 0x15,0xc6,0x8b,0x13, + 0xb5,0x2e, + + 0xc0,0x87,0x59,0x24, 0xc1,0xc7,0x98,0x79, + 0x47,0xde,0xaf,0xd8, 0x78,0x0a,0xcf,0x49, + }; + uint8_t inbuf[sizeof(ciphertext) + TESTALIGN]; + uint8_t outbuf[sizeof(ciphertext) + TESTALIGN]; + uint8_t aadbuf[sizeof(aad) + TESTALIGN]; + uint8_t noncebuf[sizeof(nonce) + TESTALIGN]; + uint8_t keybuf[sizeof(key) + TESTALIGN]; + unsigned i, j, k, L, M; + + /* + * Iterate over alignment and misalignment of all four inputs + * (plaintext/ciphertext, associated data, nonce, and key), and + * the output (ciphertext/plaintext). + * + * With apologies for the quirky nonindentation here -- it just + * gets nested a little too much. + */ + for (i = 0; i <= TESTALIGN; i++) { + for (j = 0; j <= TESTALIGN; j++) { + for (k = 0; k <= TESTALIGN; k++) { + for (L = 0; L <= TESTALIGN; L++) { + for (M = 0; M <= TESTALIGN; M++) { + unsigned long long outsize = 0; + int error; + char t[128]; + unsigned u; + + /* + * Verify encryption produces the expected ciphertext. + */ + memset(inbuf, 0, sizeof(inbuf)); + memset(aadbuf, 0, sizeof(aadbuf)); + memset(noncebuf, 0, sizeof(noncebuf)); + memset(keybuf, 0, sizeof(keybuf)); + memset(outbuf, 0, sizeof(outbuf)); + + memcpy(inbuf + i, plaintext, sizeof(plaintext)); + memcpy(aadbuf + j, aad, sizeof(aad)); + memcpy(noncebuf + k, nonce, sizeof(nonce)); + memcpy(keybuf + L, key, sizeof(key)); + + error = crypto_aead_xchacha20poly1305_ietf_encrypt(outbuf + M, + &outsize, + inbuf + i, sizeof(plaintext), + aadbuf + j, sizeof(aad), + NULL, /* secret nonce, not supported */ + noncebuf + k, + keybuf + L); + if (error) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "encrypt", i, j, k, L, M); + printf("%s: encrypt error=%d\n", t, error); + return -1; + } + if (outsize != sizeof(ciphertext)) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "encrypt", i, j, k, L, M); + printf("%s: outsize=%llu is not %zu\n", t, + outsize, sizeof(ciphertext)); + return -1; + } + if (memcmp(outbuf + M, ciphertext, sizeof(ciphertext)) != 0) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "encrypt", i, j, k, L, M); + hexdump(printf, t, outbuf + M, sizeof(ciphertext)); + return -1; + } + + /* + * Verify decryption of the valid ciphertext succeeds + * and produces the expected plaintext. + */ + memset(inbuf, 0, sizeof(inbuf)); + memset(aadbuf, 0, sizeof(aadbuf)); + memset(noncebuf, 0, sizeof(noncebuf)); + memset(keybuf, 0, sizeof(keybuf)); + memset(outbuf, 0, sizeof(outbuf)); + + memcpy(inbuf + i, ciphertext, sizeof(ciphertext)); + memcpy(aadbuf + j, aad, sizeof(aad)); + memcpy(noncebuf + k, nonce, sizeof(nonce)); + memcpy(keybuf + L, key, sizeof(key)); + + error = crypto_aead_xchacha20poly1305_ietf_decrypt(outbuf + M, + &outsize, + NULL, /* secret nonce, not supported */ + inbuf + i, sizeof(ciphertext), + aadbuf + j, sizeof(aad), + noncebuf + k, + keybuf + L); + if (error) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "decrypt", i, j, k, L, M); + printf("%s: decrypt error=%d\n", t, error); + return -1; + } + if (outsize != sizeof(plaintext)) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "decrypt", i, j, k, L, M); + printf("%s: outsize=%llu is not %zu\n", t, + outsize, sizeof(plaintext)); + return -1; + } + if (memcmp(outbuf + M, plaintext, sizeof(plaintext)) != 0) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "decrypt", i, j, k, L, M); + hexdump(printf, t, outbuf + M, sizeof(ciphertext)); + return -1; + } + + /* + * Verify decryption of a corrupted ciphertext fails + * and produces all-zero output. + */ + memset(outbuf, 0x5a, sizeof(outbuf)); + inbuf[i] ^= 0x80; + error = crypto_aead_xchacha20poly1305_ietf_decrypt(outbuf + M, + &outsize, + NULL, /* secret nonce, not supported */ + inbuf + i, sizeof(ciphertext), + aadbuf + j, sizeof(aad), + noncebuf + k, + keybuf + L); + inbuf[i] ^= 0x80; + if (error == 0) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "msg forgery", i, j, k, L, M); + printf("%s: wrongly accepted\n", t); + return -1; + } + for (u = 0; u < sizeof(plaintext); u++) { + if (outbuf[M + u] != 0) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "msg forgery", i, j, k, L, M); + hexdump(printf, t, outbuf + M, + sizeof(plaintext)); + return -1; + } + } + + /* + * Verify decryption with corrupted associated data + * fails and produces all-zero output. + */ + memset(outbuf, 0xac, sizeof(outbuf)); + aadbuf[j] ^= 0x80; + error = crypto_aead_xchacha20poly1305_ietf_decrypt(outbuf + M, + &outsize, + NULL, /* secret nonce, not supported */ + inbuf + i, sizeof(ciphertext), + aadbuf + j, sizeof(aad), + noncebuf + k, + keybuf + L); + aadbuf[j] ^= 0x80; + if (error == 0) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "aad forgery", i, j, k, L, M); + printf("%s: wrongly accepted\n", t); + return -1; + } + for (u = 0; u < sizeof(plaintext); u++) { + if (outbuf[M + u] != 0) { + snprintf(t, sizeof(t), + "%s: %s i=%u j=%u k=%u L=%u M=%u", + __func__, "aad forgery", i, j, k, L, M); + hexdump(printf, t, outbuf + M, + sizeof(plaintext)); + return -1; + } + } + } + } + } + } + } + + return 0; +} + +int sodium_selftest(void) { int result = 0; result |= crypto_aead_chacha20poly1305_ietf_selftest(); + result |= crypto_aead_xchacha20poly1305_ietf_selftest(); return result; }