Home | History | Annotate | Line # | Download | only in src
      1 /*	$NetBSD: sodium_selftest.c,v 1.2 2024/07/26 18:32:15 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2024 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #ifdef _KERNEL
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: sodium_selftest.c,v 1.2 2024/07/26 18:32:15 riastradh Exp $");
     33 
     34 #include <sys/types.h>
     35 
     36 #include <sys/systm.h>
     37 
     38 #include <lib/libkern/libkern.h>
     39 
     40 #else
     41 
     42 #include <sys/cdefs.h>
     43 __RCSID("$NetBSD: sodium_selftest.c,v 1.2 2024/07/26 18:32:15 riastradh Exp $");
     44 
     45 #include <stdint.h>
     46 #include <stdio.h>
     47 #include <string.h>
     48 
     49 static void
     50 hexdump(int (*prf)(const char *, ...) __printflike(1,2), const char *prefix,
     51     const void *buf, size_t len)
     52 {
     53 	const uint8_t *p = buf;
     54 	size_t i;
     55 
     56 	(*prf)("%s (%zu bytes @ %p)\n", prefix, len, buf);
     57 	for (i = 0; i < len; i++) {
     58 		if (i % 16 == 8)
     59 			(*prf)("  ");
     60 		else
     61 			(*prf)(" ");
     62 		(*prf)("%02hhx", p[i]);
     63 		if ((i + 1) % 16 == 0)
     64 			(*prf)("\n");
     65 	}
     66 	if (i % 16)
     67 		(*prf)("\n");
     68 }
     69 
     70 #endif
     71 
     72 #include <crypto/sodium/crypto_aead_chacha20poly1305.h>
     73 #include <crypto/sodium/crypto_aead_xchacha20poly1305.h>
     74 #include <crypto/sodium/sodium_selftest.h>
     75 
     76 /*
     77  * Test misalignments up to and including this.  Would be nice to do
     78  * this up to, say, 15, but that takes 16^5 = 2^20 ~ 1m trials, which
     79  * is a bit steep as a self-test.
     80  */
     81 #define	TESTALIGN	1
     82 
     83 int
     84 crypto_aead_chacha20poly1305_ietf_selftest(void)
     85 {
     86 	/* https://datatracker.ietf.org/doc/html/rfc8439#section-2.8.2 */
     87 	static const uint8_t plaintext[] = {
     88 		0x4c,0x61,0x64,0x69, 0x65,0x73,0x20,0x61,
     89 		0x6e,0x64,0x20,0x47, 0x65,0x6e,0x74,0x6c,
     90 		0x65,0x6d,0x65,0x6e, 0x20,0x6f,0x66,0x20,
     91 		0x74,0x68,0x65,0x20, 0x63,0x6c,0x61,0x73,
     92 		0x73,0x20,0x6f,0x66, 0x20,0x27,0x39,0x39,
     93 		0x3a,0x20,0x49,0x66, 0x20,0x49,0x20,0x63,
     94 		0x6f,0x75,0x6c,0x64, 0x20,0x6f,0x66,0x66,
     95 		0x65,0x72,0x20,0x79, 0x6f,0x75,0x20,0x6f,
     96 		0x6e,0x6c,0x79,0x20, 0x6f,0x6e,0x65,0x20,
     97 		0x74,0x69,0x70,0x20, 0x66,0x6f,0x72,0x20,
     98 		0x74,0x68,0x65,0x20, 0x66,0x75,0x74,0x75,
     99 		0x72,0x65,0x2c,0x20, 0x73,0x75,0x6e,0x73,
    100 		0x63,0x72,0x65,0x65, 0x6e,0x20,0x77,0x6f,
    101 		0x75,0x6c,0x64,0x20, 0x62,0x65,0x20,0x69,
    102 		0x74,0x2e,
    103 	};
    104 	static const uint8_t aad[] = {
    105 		0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3,
    106 		0xc4,0xc5,0xc6,0xc7,
    107 	};
    108 	static const uint8_t key[] = {
    109 		0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
    110 		0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
    111 		0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
    112 		0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
    113 	};
    114 	static const uint8_t nonce[] = {
    115 		0x07,0x00,0x00,0x00,
    116 		0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47,
    117 	};
    118 	static const uint8_t ciphertext[] = {
    119 		0xd3,0x1a,0x8d,0x34, 0x64,0x8e,0x60,0xdb,
    120 		0x7b,0x86,0xaf,0xbc, 0x53,0xef,0x7e,0xc2,
    121 		0xa4,0xad,0xed,0x51, 0x29,0x6e,0x08,0xfe,
    122 		0xa9,0xe2,0xb5,0xa7, 0x36,0xee,0x62,0xd6,
    123 		0x3d,0xbe,0xa4,0x5e, 0x8c,0xa9,0x67,0x12,
    124 		0x82,0xfa,0xfb,0x69, 0xda,0x92,0x72,0x8b,
    125 		0x1a,0x71,0xde,0x0a, 0x9e,0x06,0x0b,0x29,
    126 		0x05,0xd6,0xa5,0xb6, 0x7e,0xcd,0x3b,0x36,
    127 		0x92,0xdd,0xbd,0x7f, 0x2d,0x77,0x8b,0x8c,
    128 		0x98,0x03,0xae,0xe3, 0x28,0x09,0x1b,0x58,
    129 		0xfa,0xb3,0x24,0xe4, 0xfa,0xd6,0x75,0x94,
    130 		0x55,0x85,0x80,0x8b, 0x48,0x31,0xd7,0xbc,
    131 		0x3f,0xf4,0xde,0xf0, 0x8e,0x4b,0x7a,0x9d,
    132 		0xe5,0x76,0xd2,0x65, 0x86,0xce,0xc6,0x4b,
    133 		0x61,0x16,
    134 
    135 		0x1a,0xe1,0x0b,0x59, 0x4f,0x09,0xe2,0x6a,
    136 		0x7e,0x90,0x2e,0xcb, 0xd0,0x60,0x06,0x91,
    137 	};
    138 	uint8_t inbuf[sizeof(ciphertext) + TESTALIGN];
    139 	uint8_t outbuf[sizeof(ciphertext) + TESTALIGN];
    140 	uint8_t aadbuf[sizeof(aad) + TESTALIGN];
    141 	uint8_t noncebuf[sizeof(nonce) + TESTALIGN];
    142 	uint8_t keybuf[sizeof(key) + TESTALIGN];
    143 	unsigned i, j, k, L, M;
    144 
    145 	/*
    146 	 * Iterate over alignment and misalignment of all four inputs
    147 	 * (plaintext/ciphertext, associated data, nonce, and key), and
    148 	 * the output (ciphertext/plaintext).
    149 	 *
    150 	 * With apologies for the quirky nonindentation here -- it just
    151 	 * gets nested a little too much.
    152 	 */
    153 	for (i = 0; i <= TESTALIGN; i++) {
    154 	for (j = 0; j <= TESTALIGN; j++) {
    155 	for (k = 0; k <= TESTALIGN; k++) {
    156 	for (L = 0; L <= TESTALIGN; L++) {
    157 	for (M = 0; M <= TESTALIGN; M++) {
    158 		unsigned long long outsize = 0;
    159 		int error;
    160 		char t[128];
    161 		unsigned u;
    162 
    163 		/*
    164 		 * Verify encryption produces the expected ciphertext.
    165 		 */
    166 		memset(inbuf, 0, sizeof(inbuf));
    167 		memset(aadbuf, 0, sizeof(aadbuf));
    168 		memset(noncebuf, 0, sizeof(noncebuf));
    169 		memset(keybuf, 0, sizeof(keybuf));
    170 		memset(outbuf, 0, sizeof(outbuf));
    171 
    172 		memcpy(inbuf + i, plaintext, sizeof(plaintext));
    173 		memcpy(aadbuf + j, aad, sizeof(aad));
    174 		memcpy(noncebuf + k, nonce, sizeof(nonce));
    175 		memcpy(keybuf + L, key, sizeof(key));
    176 
    177 		error = crypto_aead_chacha20poly1305_ietf_encrypt(outbuf + M,
    178 		    &outsize,
    179 		    inbuf + i, sizeof(plaintext),
    180 		    aadbuf + j, sizeof(aad),
    181 		    NULL,	/* secret nonce, not supported */
    182 		    noncebuf + k,
    183 		    keybuf + L);
    184 		if (error) {
    185 			snprintf(t, sizeof(t),
    186 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    187 			    __func__, "encrypt", i, j, k, L, M);
    188 			printf("%s: encrypt error=%d\n", t, error);
    189 			return -1;
    190 		}
    191 		if (outsize != sizeof(ciphertext)) {
    192 			snprintf(t, sizeof(t),
    193 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    194 			    __func__, "encrypt", i, j, k, L, M);
    195 			printf("%s: outsize=%llu is not %zu\n", t,
    196 			    outsize, sizeof(ciphertext));
    197 			return -1;
    198 		}
    199 		if (memcmp(outbuf + M, ciphertext, sizeof(ciphertext)) != 0) {
    200 			snprintf(t, sizeof(t),
    201 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    202 			    __func__, "encrypt", i, j, k, L, M);
    203 			hexdump(printf, t, outbuf + M, sizeof(ciphertext));
    204 			return -1;
    205 		}
    206 
    207 		/*
    208 		 * Verify decryption of the valid ciphertext succeeds
    209 		 * and produces the expected plaintext.
    210 		 */
    211 		memset(inbuf, 0, sizeof(inbuf));
    212 		memset(aadbuf, 0, sizeof(aadbuf));
    213 		memset(noncebuf, 0, sizeof(noncebuf));
    214 		memset(keybuf, 0, sizeof(keybuf));
    215 		memset(outbuf, 0, sizeof(outbuf));
    216 
    217 		memcpy(inbuf + i, ciphertext, sizeof(ciphertext));
    218 		memcpy(aadbuf + j, aad, sizeof(aad));
    219 		memcpy(noncebuf + k, nonce, sizeof(nonce));
    220 		memcpy(keybuf + L, key, sizeof(key));
    221 
    222 		error = crypto_aead_chacha20poly1305_ietf_decrypt(outbuf + M,
    223 		    &outsize,
    224 		    NULL,	/* secret nonce, not supported */
    225 		    inbuf + i, sizeof(ciphertext),
    226 		    aadbuf + j, sizeof(aad),
    227 		    noncebuf + k,
    228 		    keybuf + L);
    229 		if (error) {
    230 			snprintf(t, sizeof(t),
    231 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    232 			    __func__, "decrypt", i, j, k, L, M);
    233 			printf("%s: decrypt error=%d\n", t, error);
    234 			return -1;
    235 		}
    236 		if (outsize != sizeof(plaintext)) {
    237 			snprintf(t, sizeof(t),
    238 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    239 			    __func__, "decrypt", i, j, k, L, M);
    240 			printf("%s: outsize=%llu is not %zu\n", t,
    241 			    outsize, sizeof(plaintext));
    242 			return -1;
    243 		}
    244 		if (memcmp(outbuf + M, plaintext, sizeof(plaintext)) != 0) {
    245 			snprintf(t, sizeof(t),
    246 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    247 			    __func__, "decrypt", i, j, k, L, M);
    248 			hexdump(printf, t, outbuf + M, sizeof(ciphertext));
    249 			return -1;
    250 		}
    251 
    252 		/*
    253 		 * Verify decryption of a corrupted ciphertext fails
    254 		 * and produces all-zero output.
    255 		 */
    256 		memset(outbuf, 0x5a, sizeof(outbuf));
    257 		inbuf[i] ^= 0x80;
    258 		error = crypto_aead_chacha20poly1305_ietf_decrypt(outbuf + M,
    259 		    &outsize,
    260 		    NULL,	/* secret nonce, not supported */
    261 		    inbuf + i, sizeof(ciphertext),
    262 		    aadbuf + j, sizeof(aad),
    263 		    noncebuf + k,
    264 		    keybuf + L);
    265 		inbuf[i] ^= 0x80;
    266 		if (error == 0) {
    267 			snprintf(t, sizeof(t),
    268 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    269 			    __func__, "msg forgery", i, j, k, L, M);
    270 			printf("%s: wrongly accepted\n", t);
    271 			return -1;
    272 		}
    273 		for (u = 0; u < sizeof(plaintext); u++) {
    274 			if (outbuf[M + u] != 0) {
    275 				snprintf(t, sizeof(t),
    276 				    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    277 				    __func__, "msg forgery", i, j, k, L, M);
    278 				hexdump(printf, t, outbuf + M,
    279 				    sizeof(plaintext));
    280 				return -1;
    281 			}
    282 		}
    283 
    284 		/*
    285 		 * Verify decryption with corrupted associated data
    286 		 * fails and produces all-zero output.
    287 		 */
    288 		memset(outbuf, 0xac, sizeof(outbuf));
    289 		aadbuf[j] ^= 0x80;
    290 		error = crypto_aead_chacha20poly1305_ietf_decrypt(outbuf + M,
    291 		    &outsize,
    292 		    NULL,	/* secret nonce, not supported */
    293 		    inbuf + i, sizeof(ciphertext),
    294 		    aadbuf + j, sizeof(aad),
    295 		    noncebuf + k,
    296 		    keybuf + L);
    297 		aadbuf[j] ^= 0x80;
    298 		if (error == 0) {
    299 			snprintf(t, sizeof(t),
    300 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    301 			    __func__, "aad forgery", i, j, k, L, M);
    302 			printf("%s: wrongly accepted\n", t);
    303 			return -1;
    304 		}
    305 		for (u = 0; u < sizeof(plaintext); u++) {
    306 			if (outbuf[M + u] != 0) {
    307 				snprintf(t, sizeof(t),
    308 				    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    309 				    __func__, "aad forgery", i, j, k, L, M);
    310 				hexdump(printf, t, outbuf + M,
    311 				    sizeof(plaintext));
    312 				return -1;
    313 			}
    314 		}
    315 	}
    316 	}
    317 	}
    318 	}
    319 	}
    320 
    321 	return 0;
    322 }
    323 
    324 int
    325 crypto_aead_xchacha20poly1305_ietf_selftest(void)
    326 {
    327 	/* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.3.1 */
    328 	static const uint8_t plaintext[] = {
    329 		0x4c,0x61,0x64,0x69, 0x65,0x73,0x20,0x61,
    330 		0x6e,0x64,0x20,0x47, 0x65,0x6e,0x74,0x6c,
    331 		0x65,0x6d,0x65,0x6e, 0x20,0x6f,0x66,0x20,
    332 		0x74,0x68,0x65,0x20, 0x63,0x6c,0x61,0x73,
    333 		0x73,0x20,0x6f,0x66, 0x20,0x27,0x39,0x39,
    334 		0x3a,0x20,0x49,0x66, 0x20,0x49,0x20,0x63,
    335 		0x6f,0x75,0x6c,0x64, 0x20,0x6f,0x66,0x66,
    336 		0x65,0x72,0x20,0x79, 0x6f,0x75,0x20,0x6f,
    337 		0x6e,0x6c,0x79,0x20, 0x6f,0x6e,0x65,0x20,
    338 		0x74,0x69,0x70,0x20, 0x66,0x6f,0x72,0x20,
    339 		0x74,0x68,0x65,0x20, 0x66,0x75,0x74,0x75,
    340 		0x72,0x65,0x2c,0x20, 0x73,0x75,0x6e,0x73,
    341 		0x63,0x72,0x65,0x65, 0x6e,0x20,0x77,0x6f,
    342 		0x75,0x6c,0x64,0x20, 0x62,0x65,0x20,0x69,
    343 		0x74,0x2e,
    344 	};
    345 	static const uint8_t aad[] = {
    346 		0x50,0x51,0x52,0x53, 0xc0,0xc1,0xc2,0xc3,
    347 		0xc4,0xc5,0xc6,0xc7,
    348 	};
    349 	static const uint8_t key[] = {
    350 		0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
    351 		0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
    352 		0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
    353 		0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
    354 	};
    355 	static const uint8_t nonce[] = {
    356 		0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47,
    357 		0x48,0x49,0x4a,0x4b, 0x4c,0x4d,0x4e,0x4f,
    358 		0x50,0x51,0x52,0x53, 0x54,0x55,0x56,0x57,
    359 		0x00,0x00,0x00,0x00,
    360 	};
    361 	static const uint8_t ciphertext[] = {
    362 		0xbd,0x6d,0x17,0x9d, 0x3e,0x83,0xd4,0x3b,
    363 		0x95,0x76,0x57,0x94, 0x93,0xc0,0xe9,0x39,
    364 		0x57,0x2a,0x17,0x00, 0x25,0x2b,0xfa,0xcc,
    365 		0xbe,0xd2,0x90,0x2c, 0x21,0x39,0x6c,0xbb,
    366 		0x73,0x1c,0x7f,0x1b, 0x0b,0x4a,0xa6,0x44,
    367 		0x0b,0xf3,0xa8,0x2f, 0x4e,0xda,0x7e,0x39,
    368 		0xae,0x64,0xc6,0x70, 0x8c,0x54,0xc2,0x16,
    369 		0xcb,0x96,0xb7,0x2e, 0x12,0x13,0xb4,0x52,
    370 		0x2f,0x8c,0x9b,0xa4, 0x0d,0xb5,0xd9,0x45,
    371 		0xb1,0x1b,0x69,0xb9, 0x82,0xc1,0xbb,0x9e,
    372 		0x3f,0x3f,0xac,0x2b, 0xc3,0x69,0x48,0x8f,
    373 		0x76,0xb2,0x38,0x35, 0x65,0xd3,0xff,0xf9,
    374 		0x21,0xf9,0x66,0x4c, 0x97,0x63,0x7d,0xa9,
    375 		0x76,0x88,0x12,0xf6, 0x15,0xc6,0x8b,0x13,
    376 		0xb5,0x2e,
    377 
    378 		0xc0,0x87,0x59,0x24, 0xc1,0xc7,0x98,0x79,
    379 		0x47,0xde,0xaf,0xd8, 0x78,0x0a,0xcf,0x49,
    380 	};
    381 	uint8_t inbuf[sizeof(ciphertext) + TESTALIGN];
    382 	uint8_t outbuf[sizeof(ciphertext) + TESTALIGN];
    383 	uint8_t aadbuf[sizeof(aad) + TESTALIGN];
    384 	uint8_t noncebuf[sizeof(nonce) + TESTALIGN];
    385 	uint8_t keybuf[sizeof(key) + TESTALIGN];
    386 	unsigned i, j, k, L, M;
    387 
    388 	/*
    389 	 * Iterate over alignment and misalignment of all four inputs
    390 	 * (plaintext/ciphertext, associated data, nonce, and key), and
    391 	 * the output (ciphertext/plaintext).
    392 	 *
    393 	 * With apologies for the quirky nonindentation here -- it just
    394 	 * gets nested a little too much.
    395 	 */
    396 	for (i = 0; i <= TESTALIGN; i++) {
    397 	for (j = 0; j <= TESTALIGN; j++) {
    398 	for (k = 0; k <= TESTALIGN; k++) {
    399 	for (L = 0; L <= TESTALIGN; L++) {
    400 	for (M = 0; M <= TESTALIGN; M++) {
    401 		unsigned long long outsize = 0;
    402 		int error;
    403 		char t[128];
    404 		unsigned u;
    405 
    406 		/*
    407 		 * Verify encryption produces the expected ciphertext.
    408 		 */
    409 		memset(inbuf, 0, sizeof(inbuf));
    410 		memset(aadbuf, 0, sizeof(aadbuf));
    411 		memset(noncebuf, 0, sizeof(noncebuf));
    412 		memset(keybuf, 0, sizeof(keybuf));
    413 		memset(outbuf, 0, sizeof(outbuf));
    414 
    415 		memcpy(inbuf + i, plaintext, sizeof(plaintext));
    416 		memcpy(aadbuf + j, aad, sizeof(aad));
    417 		memcpy(noncebuf + k, nonce, sizeof(nonce));
    418 		memcpy(keybuf + L, key, sizeof(key));
    419 
    420 		error = crypto_aead_xchacha20poly1305_ietf_encrypt(outbuf + M,
    421 		    &outsize,
    422 		    inbuf + i, sizeof(plaintext),
    423 		    aadbuf + j, sizeof(aad),
    424 		    NULL,	/* secret nonce, not supported */
    425 		    noncebuf + k,
    426 		    keybuf + L);
    427 		if (error) {
    428 			snprintf(t, sizeof(t),
    429 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    430 			    __func__, "encrypt", i, j, k, L, M);
    431 			printf("%s: encrypt error=%d\n", t, error);
    432 			return -1;
    433 		}
    434 		if (outsize != sizeof(ciphertext)) {
    435 			snprintf(t, sizeof(t),
    436 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    437 			    __func__, "encrypt", i, j, k, L, M);
    438 			printf("%s: outsize=%llu is not %zu\n", t,
    439 			    outsize, sizeof(ciphertext));
    440 			return -1;
    441 		}
    442 		if (memcmp(outbuf + M, ciphertext, sizeof(ciphertext)) != 0) {
    443 			snprintf(t, sizeof(t),
    444 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    445 			    __func__, "encrypt", i, j, k, L, M);
    446 			hexdump(printf, t, outbuf + M, sizeof(ciphertext));
    447 			return -1;
    448 		}
    449 
    450 		/*
    451 		 * Verify decryption of the valid ciphertext succeeds
    452 		 * and produces the expected plaintext.
    453 		 */
    454 		memset(inbuf, 0, sizeof(inbuf));
    455 		memset(aadbuf, 0, sizeof(aadbuf));
    456 		memset(noncebuf, 0, sizeof(noncebuf));
    457 		memset(keybuf, 0, sizeof(keybuf));
    458 		memset(outbuf, 0, sizeof(outbuf));
    459 
    460 		memcpy(inbuf + i, ciphertext, sizeof(ciphertext));
    461 		memcpy(aadbuf + j, aad, sizeof(aad));
    462 		memcpy(noncebuf + k, nonce, sizeof(nonce));
    463 		memcpy(keybuf + L, key, sizeof(key));
    464 
    465 		error = crypto_aead_xchacha20poly1305_ietf_decrypt(outbuf + M,
    466 		    &outsize,
    467 		    NULL,	/* secret nonce, not supported */
    468 		    inbuf + i, sizeof(ciphertext),
    469 		    aadbuf + j, sizeof(aad),
    470 		    noncebuf + k,
    471 		    keybuf + L);
    472 		if (error) {
    473 			snprintf(t, sizeof(t),
    474 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    475 			    __func__, "decrypt", i, j, k, L, M);
    476 			printf("%s: decrypt error=%d\n", t, error);
    477 			return -1;
    478 		}
    479 		if (outsize != sizeof(plaintext)) {
    480 			snprintf(t, sizeof(t),
    481 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    482 			    __func__, "decrypt", i, j, k, L, M);
    483 			printf("%s: outsize=%llu is not %zu\n", t,
    484 			    outsize, sizeof(plaintext));
    485 			return -1;
    486 		}
    487 		if (memcmp(outbuf + M, plaintext, sizeof(plaintext)) != 0) {
    488 			snprintf(t, sizeof(t),
    489 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    490 			    __func__, "decrypt", i, j, k, L, M);
    491 			hexdump(printf, t, outbuf + M, sizeof(ciphertext));
    492 			return -1;
    493 		}
    494 
    495 		/*
    496 		 * Verify decryption of a corrupted ciphertext fails
    497 		 * and produces all-zero output.
    498 		 */
    499 		memset(outbuf, 0x5a, sizeof(outbuf));
    500 		inbuf[i] ^= 0x80;
    501 		error = crypto_aead_xchacha20poly1305_ietf_decrypt(outbuf + M,
    502 		    &outsize,
    503 		    NULL,	/* secret nonce, not supported */
    504 		    inbuf + i, sizeof(ciphertext),
    505 		    aadbuf + j, sizeof(aad),
    506 		    noncebuf + k,
    507 		    keybuf + L);
    508 		inbuf[i] ^= 0x80;
    509 		if (error == 0) {
    510 			snprintf(t, sizeof(t),
    511 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    512 			    __func__, "msg forgery", i, j, k, L, M);
    513 			printf("%s: wrongly accepted\n", t);
    514 			return -1;
    515 		}
    516 		for (u = 0; u < sizeof(plaintext); u++) {
    517 			if (outbuf[M + u] != 0) {
    518 				snprintf(t, sizeof(t),
    519 				    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    520 				    __func__, "msg forgery", i, j, k, L, M);
    521 				hexdump(printf, t, outbuf + M,
    522 				    sizeof(plaintext));
    523 				return -1;
    524 			}
    525 		}
    526 
    527 		/*
    528 		 * Verify decryption with corrupted associated data
    529 		 * fails and produces all-zero output.
    530 		 */
    531 		memset(outbuf, 0xac, sizeof(outbuf));
    532 		aadbuf[j] ^= 0x80;
    533 		error = crypto_aead_xchacha20poly1305_ietf_decrypt(outbuf + M,
    534 		    &outsize,
    535 		    NULL,	/* secret nonce, not supported */
    536 		    inbuf + i, sizeof(ciphertext),
    537 		    aadbuf + j, sizeof(aad),
    538 		    noncebuf + k,
    539 		    keybuf + L);
    540 		aadbuf[j] ^= 0x80;
    541 		if (error == 0) {
    542 			snprintf(t, sizeof(t),
    543 			    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    544 			    __func__, "aad forgery", i, j, k, L, M);
    545 			printf("%s: wrongly accepted\n", t);
    546 			return -1;
    547 		}
    548 		for (u = 0; u < sizeof(plaintext); u++) {
    549 			if (outbuf[M + u] != 0) {
    550 				snprintf(t, sizeof(t),
    551 				    "%s: %s i=%u j=%u k=%u L=%u M=%u",
    552 				    __func__, "aad forgery", i, j, k, L, M);
    553 				hexdump(printf, t, outbuf + M,
    554 				    sizeof(plaintext));
    555 				return -1;
    556 			}
    557 		}
    558 	}
    559 	}
    560 	}
    561 	}
    562 	}
    563 
    564 	return 0;
    565 }
    566 
    567 int
    568 sodium_selftest(void)
    569 {
    570 	int result = 0;
    571 
    572 	result |= crypto_aead_chacha20poly1305_ietf_selftest();
    573 	result |= crypto_aead_xchacha20poly1305_ietf_selftest();
    574 
    575 	return result;
    576 }
    577 
    578 #ifdef SODIUM_SELFTEST_MAIN
    579 int
    580 main(void)
    581 {
    582 
    583 	return sodium_selftest();
    584 }
    585 #endif
    586