root/sys/crypto/aes/aes_selftest.c
/*      $NetBSD: aes_selftest.c,v 1.8 2025/12/22 16:35:34 nia Exp $     */

/*-
 * Copyright (c) 2020 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: aes_selftest.c,v 1.8 2025/12/22 16:35:34 nia Exp $");

#ifdef _KERNEL

#include <sys/types.h>
#include <sys/endian.h>
#include <sys/systm.h>

#include <lib/libkern/libkern.h>

#else  /* !_KERNEL */

#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

static void
hexdump(int (*prf)(const char *, ...) __printflike(1,2), const char *prefix,
    const void *buf, size_t len)
{
        const uint8_t *p = buf;
        size_t i;

        (*prf)("%s (%zu bytes)\n", prefix, len);
        for (i = 0; i < len; i++) {
                if (i % 16 == 8)
                        (*prf)("  ");
                else
                        (*prf)(" ");
                (*prf)("%02hhx", p[i]);
                if ((i + 1) % 16 == 0)
                        (*prf)("\n");
        }
        if (i % 16)
                (*prf)("\n");
}

#endif  /* _KERNEL */

#include <crypto/aes/aes.h>
#include <crypto/aes/aes_impl.h>

static const unsigned aes_keybytes[] __unused = { 16, 24, 32 };
static const unsigned aes_keybits[] __unused = { 128, 192, 256 };
static const unsigned aes_nrounds[] = { 10, 12, 14 };

#define aes_selftest_fail(impl, actual, expected, nbytes, fmt, args...)       \
({                                                                            \
        printf("%s "fmt": self-test failed\n", (impl)->ai_name, ##args);      \
        hexdump(printf, "was", (actual), (nbytes));                           \
        hexdump(printf, "expected", (expected), (nbytes));                    \
        -1;                                                                   \
})

static int
aes_selftest_encdec(const struct aes_impl *impl)
{
        /*
         * head -c 16 < /dev/zero | openssl enc -aes-{128,192,256}-ecb
         *     -nopad -K 000102030405060708090a0b0c0d... | hexdump -C
         */
        static const uint8_t expected[3][16] = {
                [0] = {
                        0xc6,0xa1,0x3b,0x37,0x87,0x8f,0x5b,0x82,
                        0x6f,0x4f,0x81,0x62,0xa1,0xc8,0xd8,0x79,
                },
                [1] = {
                        0x91,0x62,0x51,0x82,0x1c,0x73,0xa5,0x22,
                        0xc3,0x96,0xd6,0x27,0x38,0x01,0x96,0x07,
                },
                [2] = {
                        0xf2,0x90,0x00,0xb6,0x2a,0x49,0x9f,0xd0,
                        0xa9,0xf3,0x9a,0x6a,0xdd,0x2e,0x77,0x80,
                },
        };
        struct aesenc enc;
        struct aesdec dec;
        uint8_t key[32];
        uint8_t in[16];
        uint8_t outbuf[18] = { [0] = 0x1a, [17] = 0x1a }, *out = outbuf + 1;
        unsigned i;

        for (i = 0; i < 32; i++)
                key[i] = i;
        for (i = 0; i < 16; i++)
                in[i] = 0;

        for (i = 0; i < 3; i++) {
                impl->ai_setenckey(&enc, key, aes_nrounds[i]);
                impl->ai_setdeckey(&dec, key, aes_nrounds[i]);
                impl->ai_enc(&enc, in, out, aes_nrounds[i]);
                if (memcmp(out, expected[i], 16))
                        return aes_selftest_fail(impl, out, expected[i], 16,
                            "AES-%u enc", aes_keybits[i]);
                impl->ai_dec(&dec, out, out, aes_nrounds[i]);
                if (memcmp(out, in, 16))
                        return aes_selftest_fail(impl, out, in, 16,
                            "AES-%u dec", aes_keybits[i]);
        }

        if (outbuf[0] != 0x1a)
                return aes_selftest_fail(impl, outbuf,
                    (const uint8_t[1]){0x1a}, 1,
                    "AES overrun preceding");
        if (outbuf[17] != 0x1a)
                return aes_selftest_fail(impl, outbuf + 17,
                    (const uint8_t[1]){0x1a}, 1,
                    "AES overrun following");

        /* Success!  */
        return 0;
}

static int
aes_selftest_encdec_cbc(const struct aes_impl *impl)
{
        static const uint8_t expected[3][144] = {
                [0] = {
                        0xfe,0xf1,0xa8,0xb6,0x25,0xf0,0xc4,0x3a,
                        0x71,0x08,0xb6,0x23,0xa6,0xfb,0x90,0xca,
                        0x9e,0x64,0x6d,0x95,0xb5,0xf5,0x41,0x24,
                        0xd2,0xe6,0x60,0xda,0x6c,0x69,0xc4,0xa0,
                        0x4d,0xaa,0x94,0xf6,0x66,0x1e,0xaa,0x85,
                        0x68,0xc5,0x6b,0x2e,0x77,0x7a,0x68,0xff,
                        0x45,0x15,0x45,0xc5,0x9c,0xbb,0x3a,0x23,
                        0x08,0x3a,0x06,0xdd,0xc0,0x52,0xd2,0xb7,
                        0x47,0xaa,0x1c,0xc7,0xb5,0xa9,0x7d,0x04,
                        0x60,0x67,0x78,0xf6,0xb9,0xba,0x26,0x84,
                        0x45,0x72,0x44,0xed,0xa3,0xd3,0xa0,0x3f,
                        0x19,0xee,0x3f,0x94,0x59,0x52,0x4b,0x13,
                        0xfd,0x81,0xcc,0xf9,0xf2,0x29,0xd7,0xec,
                        0xde,0x03,0x56,0x01,0x4a,0x19,0x86,0xc0,
                        0x87,0xce,0xe1,0xcc,0x13,0xf1,0x2e,0xda,
                        0x3f,0xfe,0xa4,0x64,0xe7,0x48,0xb4,0x7b,
                        0x73,0x62,0x5a,0x80,0x5e,0x01,0x20,0xa5,
                        0x0a,0xd7,0x98,0xa7,0xd9,0x8b,0xff,0xc2,
                },
                [1] = {
                        0xa6,0x87,0xf0,0x92,0x68,0xc8,0xd6,0x42,
                        0xa8,0x83,0x1c,0x92,0x65,0x8c,0xd9,0xfe,
                        0x0b,0x1a,0xc6,0x96,0x27,0x44,0xd4,0x14,
                        0xfc,0xe7,0x85,0xb2,0x71,0xc7,0x11,0x39,
                        0xed,0x36,0xd3,0x5c,0xa7,0xf7,0x3d,0xc9,
                        0xa2,0x54,0x8b,0xb4,0xfa,0xe8,0x21,0xf9,
                        0xfd,0x6a,0x42,0x85,0xde,0x66,0xd4,0xc0,
                        0xa7,0xd3,0x5b,0xe1,0xe6,0xac,0xea,0xf9,
                        0xa3,0x15,0x68,0xf4,0x66,0x4c,0x23,0x75,
                        0x58,0xba,0x7f,0xca,0xbf,0x40,0x56,0x79,
                        0x2f,0xbf,0xdf,0x5f,0x56,0xcb,0xa0,0xe4,
                        0x22,0x65,0x6a,0x8f,0x4f,0xff,0x11,0x6b,
                        0x57,0xeb,0x45,0xeb,0x9d,0x7f,0xfe,0x9c,
                        0x8b,0x30,0xa8,0xb0,0x7e,0x27,0xf8,0xbc,
                        0x1f,0xf8,0x15,0x34,0x36,0x4f,0x46,0x73,
                        0x81,0x90,0x4b,0x4b,0x46,0x4d,0x01,0x45,
                        0xa1,0xc3,0x0b,0xa8,0x5a,0xab,0xc1,0x88,
                        0x66,0xc8,0x1a,0x94,0x17,0x64,0x6f,0xf4,
                },
                [2] = {
                        0x22,0x4c,0x27,0xf4,0xba,0x37,0x8b,0x27,
                        0xd3,0xd6,0x88,0x8a,0xdc,0xed,0x64,0x42,
                        0x19,0x60,0x31,0x09,0xf3,0x72,0xd2,0xc2,
                        0xd3,0xe3,0xff,0xce,0xc5,0x03,0x9f,0xce,
                        0x99,0x49,0x8a,0xf2,0xe1,0xba,0xe2,0xa8,
                        0xd7,0x32,0x07,0x2d,0xb0,0xb3,0xbc,0x67,
                        0x32,0x9a,0x3e,0x7d,0x16,0x23,0xe7,0x24,
                        0x84,0xe1,0x15,0x03,0x9c,0xa2,0x7a,0x95,
                        0x34,0xa8,0x04,0x4e,0x79,0x31,0x50,0x26,
                        0x76,0xd1,0x10,0xce,0xec,0x13,0xf7,0xfb,
                        0x94,0x6b,0x76,0x50,0x5f,0xb2,0x3e,0x7c,
                        0xbe,0x97,0xe7,0x13,0x06,0x9e,0x2d,0xc4,
                        0x46,0x65,0xa7,0x69,0x37,0x07,0x25,0x37,
                        0xe5,0x48,0x51,0xa8,0x58,0xe8,0x4d,0x7c,
                        0xb5,0xbe,0x25,0x13,0xbc,0x11,0xc2,0xde,
                        0xdb,0x00,0xef,0x1c,0x1d,0xeb,0xe3,0x49,
                        0x1c,0xc0,0x78,0x29,0x76,0xc0,0xde,0x3a,
                        0x0e,0x96,0x8f,0xea,0xd7,0x42,0x4e,0xb4,
                },
        };
        struct aesenc enc;
        struct aesdec dec;
        uint8_t key[32];
        uint8_t in[144];
        uint8_t outbuf[146] = { [0] = 0x1a, [145] = 0x1a }, *out = outbuf + 1;
        uint8_t iv0[16], iv[16];
        unsigned i, j;

        for (i = 0; i < 32; i++)
                key[i] = i;
        for (i = 0; i < 16; i++)
                iv0[i] = 0x20 ^ i;
        for (i = 0; i < 144; i++)
                in[i] = 0x80 ^ i;

        for (i = 0; i < 3; i++) {
                impl->ai_setenckey(&enc, key, aes_nrounds[i]);
                impl->ai_setdeckey(&dec, key, aes_nrounds[i]);

                /* Try one swell foop.  */
                memcpy(iv, iv0, 16);
                impl->ai_cbc_enc(&enc, in, out, 144, iv, aes_nrounds[i]);
                if (memcmp(out, expected[i], 144))
                        return aes_selftest_fail(impl, out, expected[i], 144,
                            "AES-%u-CBC enc", aes_keybits[i]);

                memcpy(iv, iv0, 16);
                impl->ai_cbc_dec(&dec, out, out, 144, iv, aes_nrounds[i]);
                if (memcmp(out, in, 144))
                        return aes_selftest_fail(impl, out, in, 144,
                            "AES-%u-CBC dec", aes_keybits[i]);

                /* Try incrementally, with IV update.  */
                for (j = 0; j < 144; j += 16) {
                        memcpy(iv, iv0, 16);
                        impl->ai_cbc_enc(&enc, in, out, j, iv, aes_nrounds[i]);
                        impl->ai_cbc_enc(&enc, in + j, out + j, 144 - j, iv,
                            aes_nrounds[i]);
                        if (memcmp(out, expected[i], 144))
                                return aes_selftest_fail(impl, out,
                                    expected[i], 144, "AES-%u-CBC enc inc %u",
                                    aes_keybits[i], j);

                        memcpy(iv, iv0, 16);
                        impl->ai_cbc_dec(&dec, out, out, j, iv,
                            aes_nrounds[i]);
                        impl->ai_cbc_dec(&dec, out + j, out + j, 144 - j, iv,
                            aes_nrounds[i]);
                        if (memcmp(out, in, 144))
                                return aes_selftest_fail(impl, out,
                                    in, 144, "AES-%u-CBC dec inc %u",
                                    aes_keybits[i], j);
                }
        }

        if (outbuf[0] != 0x1a)
                return aes_selftest_fail(impl, outbuf,
                    (const uint8_t[1]){0x1a}, 1,
                    "AES-CBC overrun preceding");
        if (outbuf[145] != 0x1a)
                return aes_selftest_fail(impl, outbuf + 145,
                    (const uint8_t[1]){0x1a}, 1,
                    "AES-CBC overrun following");

        /* Success!  */
        return 0;
}

static int
aes_selftest_encdec_xts(const struct aes_impl *impl)
{
        uint64_t blkno[3] = { 0, 1, 0xff };
        static const uint8_t expected[3][144] = {
                [0] = {
                        /* IEEE P1619-D16, XTS-AES-128, Vector 4, truncated */
                        0x27,0xa7,0x47,0x9b,0xef,0xa1,0xd4,0x76,
                        0x48,0x9f,0x30,0x8c,0xd4,0xcf,0xa6,0xe2,
                        0xa9,0x6e,0x4b,0xbe,0x32,0x08,0xff,0x25,
                        0x28,0x7d,0xd3,0x81,0x96,0x16,0xe8,0x9c,
                        0xc7,0x8c,0xf7,0xf5,0xe5,0x43,0x44,0x5f,
                        0x83,0x33,0xd8,0xfa,0x7f,0x56,0x00,0x00,
                        0x05,0x27,0x9f,0xa5,0xd8,0xb5,0xe4,0xad,
                        0x40,0xe7,0x36,0xdd,0xb4,0xd3,0x54,0x12,
                        0x32,0x80,0x63,0xfd,0x2a,0xab,0x53,0xe5,
                        0xea,0x1e,0x0a,0x9f,0x33,0x25,0x00,0xa5,
                        0xdf,0x94,0x87,0xd0,0x7a,0x5c,0x92,0xcc,
                        0x51,0x2c,0x88,0x66,0xc7,0xe8,0x60,0xce,
                        0x93,0xfd,0xf1,0x66,0xa2,0x49,0x12,0xb4,
                        0x22,0x97,0x61,0x46,0xae,0x20,0xce,0x84,
                        0x6b,0xb7,0xdc,0x9b,0xa9,0x4a,0x76,0x7a,
                        0xae,0xf2,0x0c,0x0d,0x61,0xad,0x02,0x65,
                        0x5e,0xa9,0x2d,0xc4,0xc4,0xe4,0x1a,0x89,
                        0x52,0xc6,0x51,0xd3,0x31,0x74,0xbe,0x51,
                },
                [1] = {
                },
                [2] = {
                        /* IEEE P1619-D16, XTS-AES-256, Vector 10, truncated */
                        0x1c,0x3b,0x3a,0x10,0x2f,0x77,0x03,0x86,
                        0xe4,0x83,0x6c,0x99,0xe3,0x70,0xcf,0x9b,
                        0xea,0x00,0x80,0x3f,0x5e,0x48,0x23,0x57,
                        0xa4,0xae,0x12,0xd4,0x14,0xa3,0xe6,0x3b,
                        0x5d,0x31,0xe2,0x76,0xf8,0xfe,0x4a,0x8d,
                        0x66,0xb3,0x17,0xf9,0xac,0x68,0x3f,0x44,
                        0x68,0x0a,0x86,0xac,0x35,0xad,0xfc,0x33,
                        0x45,0xbe,0xfe,0xcb,0x4b,0xb1,0x88,0xfd,
                        0x57,0x76,0x92,0x6c,0x49,0xa3,0x09,0x5e,
                        0xb1,0x08,0xfd,0x10,0x98,0xba,0xec,0x70,
                        0xaa,0xa6,0x69,0x99,0xa7,0x2a,0x82,0xf2,
                        0x7d,0x84,0x8b,0x21,0xd4,0xa7,0x41,0xb0,
                        0xc5,0xcd,0x4d,0x5f,0xff,0x9d,0xac,0x89,
                        0xae,0xba,0x12,0x29,0x61,0xd0,0x3a,0x75,
                        0x71,0x23,0xe9,0x87,0x0f,0x8a,0xcf,0x10,
                        0x00,0x02,0x08,0x87,0x89,0x14,0x29,0xca,
                        0x2a,0x3e,0x7a,0x7d,0x7d,0xf7,0xb1,0x03,
                        0x55,0x16,0x5c,0x8b,0x9a,0x6d,0x0a,0x7d,
                },
        };
        static const uint8_t key1[32] = {
                0x27,0x18,0x28,0x18,0x28,0x45,0x90,0x45,
                0x23,0x53,0x60,0x28,0x74,0x71,0x35,0x26,
                0x62,0x49,0x77,0x57,0x24,0x70,0x93,0x69,
                0x99,0x59,0x57,0x49,0x66,0x96,0x76,0x27,
        };
        static const uint8_t key2[32] = {
                0x31,0x41,0x59,0x26,0x53,0x58,0x97,0x93,
                0x23,0x84,0x62,0x64,0x33,0x83,0x27,0x95,
                0x02,0x88,0x41,0x97,0x16,0x93,0x99,0x37,
                0x51,0x05,0x82,0x09,0x74,0x94,0x45,0x92,
        };
        struct aesenc enc;
        struct aesdec dec;
        uint8_t in[144];
        uint8_t outbuf[146] = { [0] = 0x1a, [145] = 0x1a }, *out = outbuf + 1;
        uint8_t blkno_buf[16];
        uint8_t iv0[16], iv[16];
        unsigned i;

        for (i = 0; i < 144; i++)
                in[i] = i;

        for (i = 0; i < 3; i++) {
                if (i == 1)     /* XXX missing AES-192 test vector */
                        continue;

                /* Format the data unit sequence number.  */
                memset(blkno_buf, 0, sizeof blkno_buf);
                le64enc(blkno_buf, blkno[i]);

                /* Generate the tweak.  */
                impl->ai_setenckey(&enc, key2, aes_nrounds[i]);
                impl->ai_enc(&enc, blkno_buf, iv0, aes_nrounds[i]);

                /* Load the data encryption key.  */
                impl->ai_setenckey(&enc, key1, aes_nrounds[i]);
                impl->ai_setdeckey(&dec, key1, aes_nrounds[i]);

                /* Try one swell foop.  */
                memcpy(iv, iv0, 16);
                impl->ai_xts_enc(&enc, in, out, 144, iv, aes_nrounds[i]);
                if (memcmp(out, expected[i], 144))
                        return aes_selftest_fail(impl, out, expected[i], 144,
                            "AES-%u-XTS enc", aes_keybits[i]);

                memcpy(iv, iv0, 16);
                impl->ai_xts_dec(&dec, out, out, 144, iv, aes_nrounds[i]);
                if (memcmp(out, in, 144))
                        return aes_selftest_fail(impl, out, in, 144,
                            "AES-%u-XTS dec", aes_keybits[i]);

                /* Try incrementally, with IV update.  */
                memcpy(iv, iv0, 16);
                impl->ai_xts_enc(&enc, in, out, 16, iv, aes_nrounds[i]);
                impl->ai_xts_enc(&enc, in + 16, out + 16, 128, iv,
                    aes_nrounds[i]);
                if (memcmp(out, expected[i], 144))
                        return aes_selftest_fail(impl, out, expected[i], 144,
                            "AES-%u-XTS enc incremental", aes_keybits[i]);

                memcpy(iv, iv0, 16);
                impl->ai_xts_dec(&dec, out, out, 128, iv, aes_nrounds[i]);
                impl->ai_xts_dec(&dec, out + 128, out + 128, 16, iv,
                    aes_nrounds[i]);
                if (memcmp(out, in, 144))
                        return aes_selftest_fail(impl, out, in, 144,
                            "AES-%u-XTS dec incremental", aes_keybits[i]);
        }

        if (outbuf[0] != 0x1a)
                return aes_selftest_fail(impl, outbuf,
                    (const uint8_t[1]){0x1a}, 1,
                    "AES-XTS overrun preceding");
        if (outbuf[145] != 0x1a)
                return aes_selftest_fail(impl, outbuf + 145,
                    (const uint8_t[1]){0x1a}, 1,
                    "AES-XTS overrun following");

        /* Success!  */
        return 0;
}

static int
aes_selftest_cbcmac(const struct aes_impl *impl)
{
        static const uint8_t m[48] = {
                0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
                0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
                0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
                0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
                0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
                0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
        };
        static uint8_t auth16[16] = {
                0x7a,0xca,0x0f,0xd9, 0xbc,0xd6,0xec,0x7c,
                0x9f,0x97,0x46,0x66, 0x16,0xe6,0xa2,0x82,
        };
        static uint8_t auth48[16] = {
                0x26,0x9a,0xe5,0xfc, 0x8c,0x53,0x0f,0xf7,
                0x6b,0xd9,0xec,0x05, 0x40,0xf7,0x35,0x13,
        };
        static const uint8_t key[16];
        struct aesenc enc;
        uint8_t auth[16];
        const unsigned nr = AES_128_NROUNDS;

        memset(auth, 0, sizeof auth);

        impl->ai_setenckey(&enc, key, nr);
        impl->ai_cbcmac_update1(&enc, m, 16, auth, nr);
        if (memcmp(auth, auth16, 16))
                return aes_selftest_fail(impl, auth, auth16, 16,
                    "AES-128 CBC-MAC (16)");
        impl->ai_cbcmac_update1(&enc, m + 16, 32, auth, nr);
        if (memcmp(auth, auth48, 16))
                return aes_selftest_fail(impl, auth, auth48, 16,
                    "AES-128 CBC-MAC (48)");

        return 0;
}

static int
aes_selftest_ccm(const struct aes_impl *impl)
{
        static const uint8_t ptxt[48] = {
                0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
                0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
                0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
                0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
                0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
                0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
        };
        static uint8_t ctr0[16] = {
                /* L - 1, #octets in counter */
                [0] = 0x01,
                /* nonce */
                [1] = 0,1,2,3,4,5,6,7,8,9,10,11,12,
                [14] = 0,
                [15] = 254,
        };
        static uint8_t authctr16[32] = {
                /* authentication tag */
                0x7a,0xca,0x0f,0xd9, 0xbc,0xd6,0xec,0x7c,
                0x9f,0x97,0x46,0x66, 0x16,0xe6,0xa2,0x82,

                /* L - 1, #octets in counter */
                [16 + 0] = 0x01,
                /* nonce */
                [16 + 1] = 0,1,2,3,4,5,6,7,8,9,10,11,12,
                [16 + 14] = 0,
                [16 + 15] = 255,
        };
        static uint8_t authctr48[32] = {
                /* authentication tag */
                0x26,0x9a,0xe5,0xfc, 0x8c,0x53,0x0f,0xf7,
                0x6b,0xd9,0xec,0x05, 0x40,0xf7,0x35,0x13,

                /* L - 1, #octets in counter */
                [16 + 0] = 0x01,
                /* nonce */
                [16 + 1] = 0,1,2,3,4,5,6,7,8,9,10,11,12,
                [16 + 14] = 1,
                [16 + 15] = 1,
        };
        static uint8_t ctxt[48] = {
                0xa4,0x35,0x07,0x5c, 0xdf,0x2d,0x67,0xd3,
                0xbf,0x1f,0x36,0x93, 0xe4,0x43,0xcb,0x1e,
                0xa0,0x82,0x9c,0x2a, 0x0b,0x66,0x46,0x05,
                0x80,0x17,0x71,0xa1, 0x7b,0x09,0xa7,0xd5,
                0x91,0x0b,0xb3,0x96, 0xd1,0x5e,0x29,0x3e,
                0x74,0x94,0x74,0x6d, 0x6b,0x25,0x43,0x8c,
        };
        static const uint8_t key[16];
        struct aesenc enc;
        uint8_t authctr[32];
        uint8_t buf[48];
        const unsigned nr = AES_128_NROUNDS;
        int result = 0;

        impl->ai_setenckey(&enc, key, nr);

        memset(authctr, 0, 16);
        memcpy(authctr + 16, ctr0, 16);

        impl->ai_ccm_enc1(&enc, ptxt, buf, 16, authctr, nr);
        if (memcmp(authctr, authctr16, 32))
                result |= aes_selftest_fail(impl, authctr, authctr16, 32,
                    "AES-128 CCM encrypt auth/ctr (16)");
        impl->ai_ccm_enc1(&enc, ptxt + 16, buf + 16, 32, authctr, nr);
        if (memcmp(authctr, authctr48, 32))
                result |= aes_selftest_fail(impl, authctr, authctr48, 32,
                    "AES-128 CCM encrypt auth/ctr (48)");

        if (memcmp(buf, ctxt, 32))
                result |= aes_selftest_fail(impl, buf, ctxt, 48,
                    "AES-128 CCM ciphertext");

        memset(authctr, 0, 16);
        memcpy(authctr + 16, ctr0, 16);

        impl->ai_ccm_dec1(&enc, ctxt, buf, 16, authctr, nr);
        if (memcmp(authctr, authctr16, 32))
                result |= aes_selftest_fail(impl, authctr, authctr16, 32,
                    "AES-128 CCM decrypt auth/ctr (16)");
        impl->ai_ccm_dec1(&enc, ctxt + 16, buf + 16, 32, authctr, nr);
        if (memcmp(authctr, authctr48, 32))
                result |= aes_selftest_fail(impl, authctr, authctr48, 32,
                    "AES-128 CCM decrypt auth/ctr (48)");

        if (memcmp(buf, ptxt, 32))
                result |= aes_selftest_fail(impl, buf, ptxt, 48,
                    "AES-128 CCM plaintext");

        return result;
}

int
aes_selftest(const struct aes_impl *impl)
{
        int result = 0;

        if (impl->ai_probe())
                return -1;

        if (aes_selftest_encdec(impl))
                result = -1;
        if (aes_selftest_encdec_cbc(impl))
                result = -1;
        if (aes_selftest_encdec_xts(impl))
                result = -1;
        if (aes_selftest_cbcmac(impl))
                result = -1;
        if (aes_selftest_ccm(impl))
                result = -1;

        return result;
}