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;
 }

Reply via email to