From aa97731e4bed9049af62683a09b92f34d3eaa124 Mon Sep 17 00:00:00 2001 From: jek Date: Tue, 13 Jan 2026 02:09:38 +0400 Subject: [PATCH] Refactor tests and improve packet normalizer - Move all test files to tests/ directory - Update Makefile to build tests in tests/ directory - Add fragment reassembly timeout mechanism (500ms default) - Add error count API (pkt_normalizer_get_error_count, pkt_normalizer_reset_error_count) - Enhance error handling with timeout callbacks - Add comprehensive stress tests and edge case tests - Update .gitignore for build artifacts --- .gitignore | 20 + Makefile | 44 + ll_queue.c | 183 + ll_queue.h | 102 + pkt_normalizer.c | 421 + pkt_normalizer.h | 53 + sc_lib.c | 265 + sc_lib.h | 119 + settings.c | 6 + settings.h | 11 + tests/test_ecc_encrypt.c | 179 + tests/test_pkt_normalizer.c | 533 ++ tests/test_sc_lib.c | 172 + tests/test_udp_secure.c | 202 + tinycrypt/.gitignore | 5 + tinycrypt/AUTHORS | 14 + tinycrypt/LICENSE | 61 + tinycrypt/Makefile | 21 + tinycrypt/README | 76 + tinycrypt/VERSION | 1 + tinycrypt/config.mk | 35 + tinycrypt/documentation/tinycrypt.rst | 352 + tinycrypt/lib/Makefile | 39 + tinycrypt/lib/include/tinycrypt/aes.h | 130 + tinycrypt/lib/include/tinycrypt/cbc_mode.h | 151 + tinycrypt/lib/include/tinycrypt/ccm_mode.h | 211 + tinycrypt/lib/include/tinycrypt/cmac_mode.h | 194 + tinycrypt/lib/include/tinycrypt/constants.h | 61 + tinycrypt/lib/include/tinycrypt/ctr_mode.h | 108 + tinycrypt/lib/include/tinycrypt/ctr_prng.h | 166 + tinycrypt/lib/include/tinycrypt/ecc.h | 545 ++ tinycrypt/lib/include/tinycrypt/ecc_dh.h | 131 + tinycrypt/lib/include/tinycrypt/ecc_dsa.h | 139 + .../include/tinycrypt/ecc_platform_specific.h | 81 + tinycrypt/lib/include/tinycrypt/hmac.h | 139 + tinycrypt/lib/include/tinycrypt/hmac_prng.h | 164 + tinycrypt/lib/include/tinycrypt/sha256.h | 129 + tinycrypt/lib/include/tinycrypt/utils.h | 121 + tinycrypt/lib/source/aes_decrypt.c | 164 + tinycrypt/lib/source/aes_encrypt.c | 191 + tinycrypt/lib/source/cbc_mode.c | 114 + tinycrypt/lib/source/ccm_mode.c | 266 + tinycrypt/lib/source/cmac_mode.c | 254 + tinycrypt/lib/source/ctr_mode.c | 85 + tinycrypt/lib/source/ctr_prng.c | 283 + tinycrypt/lib/source/ecc.c | 942 +++ tinycrypt/lib/source/ecc_dh.c | 192 + tinycrypt/lib/source/ecc_dsa.c | 290 + tinycrypt/lib/source/ecc_platform_specific.c | 105 + tinycrypt/lib/source/hmac.c | 147 + tinycrypt/lib/source/hmac_prng.c | 230 + tinycrypt/lib/source/sha256.c | 217 + tinycrypt/lib/source/utils.c | 74 + tinycrypt/tests/Makefile | 70 + tinycrypt/tests/include/test_ecc_utils.h | 100 + tinycrypt/tests/include/test_utils.h | 125 + tinycrypt/tests/pseudo-random-data.bin | Bin 0 -> 524288 bytes tinycrypt/tests/test_aes.c | 2078 +++++ tinycrypt/tests/test_cbc_mode.c | 176 + tinycrypt/tests/test_ccm_mode.c | 545 ++ tinycrypt/tests/test_client_server | Bin 0 -> 31400 bytes tinycrypt/tests/test_client_server.c | 161 + tinycrypt/tests/test_cmac_mode.c | 314 + tinycrypt/tests/test_ctr_mode.c | 138 + tinycrypt/tests/test_ctr_prng.c | 565 ++ tinycrypt/tests/test_ecc_dh.c | 521 ++ tinycrypt/tests/test_ecc_dsa.c | 669 ++ tinycrypt/tests/test_ecc_utils.c | 271 + tinycrypt/tests/test_hmac.c | 362 + tinycrypt/tests/test_hmac_prng.c | 7434 +++++++++++++++++ tinycrypt/tests/test_sha256.c | 511 ++ u_async.c | 276 + u_async.h | 33 + 73 files changed, 23287 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 ll_queue.c create mode 100644 ll_queue.h create mode 100644 pkt_normalizer.c create mode 100644 pkt_normalizer.h create mode 100644 sc_lib.c create mode 100644 sc_lib.h create mode 100644 settings.c create mode 100644 settings.h create mode 100644 tests/test_ecc_encrypt.c create mode 100644 tests/test_pkt_normalizer.c create mode 100644 tests/test_sc_lib.c create mode 100644 tests/test_udp_secure.c create mode 100644 tinycrypt/.gitignore create mode 100644 tinycrypt/AUTHORS create mode 100644 tinycrypt/LICENSE create mode 100644 tinycrypt/Makefile create mode 100644 tinycrypt/README create mode 100644 tinycrypt/VERSION create mode 100644 tinycrypt/config.mk create mode 100644 tinycrypt/documentation/tinycrypt.rst create mode 100644 tinycrypt/lib/Makefile create mode 100644 tinycrypt/lib/include/tinycrypt/aes.h create mode 100644 tinycrypt/lib/include/tinycrypt/cbc_mode.h create mode 100644 tinycrypt/lib/include/tinycrypt/ccm_mode.h create mode 100644 tinycrypt/lib/include/tinycrypt/cmac_mode.h create mode 100644 tinycrypt/lib/include/tinycrypt/constants.h create mode 100644 tinycrypt/lib/include/tinycrypt/ctr_mode.h create mode 100644 tinycrypt/lib/include/tinycrypt/ctr_prng.h create mode 100644 tinycrypt/lib/include/tinycrypt/ecc.h create mode 100644 tinycrypt/lib/include/tinycrypt/ecc_dh.h create mode 100644 tinycrypt/lib/include/tinycrypt/ecc_dsa.h create mode 100644 tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h create mode 100644 tinycrypt/lib/include/tinycrypt/hmac.h create mode 100644 tinycrypt/lib/include/tinycrypt/hmac_prng.h create mode 100644 tinycrypt/lib/include/tinycrypt/sha256.h create mode 100644 tinycrypt/lib/include/tinycrypt/utils.h create mode 100644 tinycrypt/lib/source/aes_decrypt.c create mode 100644 tinycrypt/lib/source/aes_encrypt.c create mode 100644 tinycrypt/lib/source/cbc_mode.c create mode 100644 tinycrypt/lib/source/ccm_mode.c create mode 100644 tinycrypt/lib/source/cmac_mode.c create mode 100644 tinycrypt/lib/source/ctr_mode.c create mode 100644 tinycrypt/lib/source/ctr_prng.c create mode 100644 tinycrypt/lib/source/ecc.c create mode 100644 tinycrypt/lib/source/ecc_dh.c create mode 100644 tinycrypt/lib/source/ecc_dsa.c create mode 100644 tinycrypt/lib/source/ecc_platform_specific.c create mode 100644 tinycrypt/lib/source/hmac.c create mode 100644 tinycrypt/lib/source/hmac_prng.c create mode 100644 tinycrypt/lib/source/sha256.c create mode 100644 tinycrypt/lib/source/utils.c create mode 100644 tinycrypt/tests/Makefile create mode 100644 tinycrypt/tests/include/test_ecc_utils.h create mode 100644 tinycrypt/tests/include/test_utils.h create mode 100644 tinycrypt/tests/pseudo-random-data.bin create mode 100644 tinycrypt/tests/test_aes.c create mode 100644 tinycrypt/tests/test_cbc_mode.c create mode 100644 tinycrypt/tests/test_ccm_mode.c create mode 100755 tinycrypt/tests/test_client_server create mode 100644 tinycrypt/tests/test_client_server.c create mode 100644 tinycrypt/tests/test_cmac_mode.c create mode 100644 tinycrypt/tests/test_ctr_mode.c create mode 100644 tinycrypt/tests/test_ctr_prng.c create mode 100644 tinycrypt/tests/test_ecc_dh.c create mode 100644 tinycrypt/tests/test_ecc_dsa.c create mode 100644 tinycrypt/tests/test_ecc_utils.c create mode 100644 tinycrypt/tests/test_hmac.c create mode 100644 tinycrypt/tests/test_hmac_prng.c create mode 100644 tinycrypt/tests/test_sha256.c create mode 100644 u_async.c create mode 100644 u_async.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..63742722 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Object files +*.o +*.obj + +# Executables +/test_* +/tests/test_* + +# TinyCrypt build artifacts +tinycrypt/lib/source/*.o +tinycrypt/tests/*.o + +# IDE and editor files +*.swp +*~ +*.bak + +# OS files +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..b2458fdd --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +CC := gcc +CFLAGS := -Os -std=c99 -Wall -Wextra -D_ISOC99_SOURCE -DENABLE_TESTS +INCLUDES := -Itinycrypt/lib/include/ -Itinycrypt/lib/source/ -Itinycrypt/tests/include/ -I. +TEST_DIR := tests + +TINYCRYPT_SRCS := \ + tinycrypt/lib/source/ecc.c \ + tinycrypt/lib/source/ecc_dh.c \ + tinycrypt/lib/source/ecc_platform_specific.c \ + tinycrypt/lib/source/aes_encrypt.c \ + tinycrypt/lib/source/aes_decrypt.c \ + tinycrypt/lib/source/utils.c \ + tinycrypt/lib/source/ctr_mode.c \ + tinycrypt/lib/source/ccm_mode.c + +TINYCRYPT_OBJS := $(TINYCRYPT_SRCS:.c=.o) + +SC_LIB_OBJS := sc_lib.o +UASYNC_OBJS := u_async.o +PN_OBJS := pkt_normalizer.o settings.o +LL_QUEUE_OBJS := ll_queue.o + +all: $(TEST_DIR)/test_ecc_encrypt $(TEST_DIR)/test_sc_lib $(TEST_DIR)/test_udp_secure $(TEST_DIR)/test_pkt_normalizer + +$(TEST_DIR)/test_ecc_encrypt: $(TEST_DIR)/test_ecc_encrypt.o $(TINYCRYPT_OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ + +$(TEST_DIR)/test_sc_lib: $(TEST_DIR)/test_sc_lib.o $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ + +$(TEST_DIR)/test_udp_secure: $(TEST_DIR)/test_udp_secure.o $(SC_LIB_OBJS) $(UASYNC_OBJS) $(TINYCRYPT_OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ + +$(TEST_DIR)/test_pkt_normalizer: $(TEST_DIR)/test_pkt_normalizer.o $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +clean: + rm -f $(TEST_DIR)/test_ecc_encrypt $(TEST_DIR)/test_sc_lib $(TEST_DIR)/test_udp_secure $(TEST_DIR)/test_pkt_normalizer \ + *.o tinycrypt/lib/source/*.o $(TEST_DIR)/*.o + +.PHONY: all clean \ No newline at end of file diff --git a/ll_queue.c b/ll_queue.c new file mode 100644 index 00000000..0b9c824d --- /dev/null +++ b/ll_queue.c @@ -0,0 +1,183 @@ +#include "ll_queue.h" +#include +#include +#include "u_async.h" + +// Предварительное объявление для отложенного возобновления +static void queue_resume_timeout_cb(void* arg); + +// ==================== Управление очередью ==================== + +ll_queue_t* queue_new(void) { + ll_queue_t* q = calloc(1, sizeof(ll_queue_t)); + if (!q) return NULL; + + q->head = NULL; + q->tail = NULL; + q->count = 0; + q->size_limit = -1; // По умолчанию без ограничения + q->callback = NULL; + q->callback_arg = NULL; + q->callback_suspended = 0; // Коллбэки разрешены изначально + q->resume_timeout_id = NULL; + + return q; +} + +void queue_free(ll_queue_t* q) { + if (!q) return; + + // Освободить все элементы + ll_entry_t* entry = q->head; + while (entry) { + ll_entry_t* next = entry->next; + free(entry); + entry = next; + } + + // Отменить отложенное возобновление если запланировано + if (q->resume_timeout_id) { + uasync_cancel_timeout(q->resume_timeout_id); + } + + free(q); +} + +// ==================== Конфигурация очереди ==================== + +void queue_set_callback(ll_queue_t* q, queue_callback_t cbk_fn, void* arg) { + if (!q) return; + q->callback = cbk_fn; + q->callback_arg = arg; +} + +static void queue_resume_timeout_cb(void* arg) { + ll_queue_t* q = (ll_queue_t*)arg; + if (!q || !q->callback) return; + + // Очистить ID таймаута (таймаут сработал) + q->resume_timeout_id = NULL; + + // Разрешить коллбэки + q->callback_suspended = 0; + + // Если в очереди есть элементы, вызвать коллбэк с первым элементом + // Обработчик должен извлечь этот элемент вызовом queue_entry_get() + if (q->head) { + q->callback(q, q->head, q->callback_arg); + } +} + +void queue_resume_callback(ll_queue_t* q) { + if (!q || !q->callback) return; + + // Если уже есть отложенное возобновление, ничего не делать + if (q->resume_timeout_id) { + return; + } + + // Запланировать отложенное возобновление через uasync + q->resume_timeout_id = uasync_set_timeout(0, q, queue_resume_timeout_cb); +} + +void queue_set_size_limit(ll_queue_t* q, int lim) { + if (!q) return; + q->size_limit = lim; +} + +// ==================== Управление элементами ==================== + +ll_entry_t* queue_entry_new(size_t data_size) { + // Выделить память под структуру + область данных + ll_entry_t* entry = malloc(sizeof(ll_entry_t) + data_size); + if (!entry) return NULL; + + entry->next = NULL; + entry->size = data_size; + // Область данных оставить неинициализированной для производительности + + return entry; +} + +void queue_entry_free(ll_entry_t* entry) { + free(entry); +} + +// ==================== Операции с очередью ==================== + +int queue_entry_put(ll_queue_t* q, ll_entry_t* entry) { + if (!q || !entry) return -1; + + // Проверить лимит размера + if (q->size_limit >= 0 && q->count >= q->size_limit) { + queue_entry_free(entry); + return -1; + } + + // Добавить в хвост (FIFO) + entry->next = NULL; + if (q->tail) { + q->tail->next = entry; + } else { + q->head = entry; + } + q->tail = entry; + q->count++; + + // Если очередь была пустой до добавления (count был 0) и коллбэки разрешены - вызвать коллбэк + // Это запускает автоматическую обработку очереди + if (q->count == 1 && !q->callback_suspended && q->callback) { + q->callback(q, entry, q->callback_arg); + } + + return 0; +} + +int queue_entry_put_first(ll_queue_t* q, ll_entry_t* entry) { + if (!q || !entry) return -1; + + // Проверить лимит размера + if (q->size_limit >= 0 && q->count >= q->size_limit) { + queue_entry_free(entry); + return -1; + } + + // Добавить в голову (LIFO, высокий приоритет) + entry->next = q->head; + q->head = entry; + if (!q->tail) { + q->tail = entry; + } + q->count++; + + // Если очередь была пустой до добавления (count был 0) и коллбэки разрешены - вызвать коллбэк + if (q->count == 1 && !q->callback_suspended && q->callback) { + q->callback(q, entry, q->callback_arg); + } + + return 0; +} + +ll_entry_t* queue_entry_get(ll_queue_t* q) { + if (!q || !q->head) return NULL; + + ll_entry_t* entry = q->head; + q->head = entry->next; + if (!q->head) { + q->tail = NULL; + } + q->count--; + + entry->next = NULL; // Отсоединить от очереди + + // При извлечении элемента приостанавливаем коллбэки + // Это предотвращает рекурсию если во время обработки добавляются новые элементы + q->callback_suspended = 1; + + return entry; +} + +int queue_entry_count(ll_queue_t* q) { + if (!q) return 0; + return q->count; +} diff --git a/ll_queue.h b/ll_queue.h new file mode 100644 index 00000000..4bbded49 --- /dev/null +++ b/ll_queue.h @@ -0,0 +1,102 @@ +#ifndef LL_QUEUE_H +#define LL_QUEUE_H + +#include // для size_t + +// Предварительные объявления +typedef struct ll_queue ll_queue_t; +typedef struct ll_entry ll_entry_t; + +// Тип коллбэка: вызывается при добавлении элемента в пустую очередь или для продолжения обработки +// Параметры: указатель на очередь, указатель на элемент (первый в очереди), пользовательский аргумент +typedef void (*queue_callback_t)(ll_queue_t* q, ll_entry_t* entry, void* arg); + +// Структура элемента - переменный размер, данные расположены сразу после структуры +struct ll_entry { + struct ll_entry* next; // Указатель на следующий элемент в очереди + size_t size; // Размер данных элемента (байт) +}; + +// Структура очереди +struct ll_queue { + ll_entry_t* head; // Первый элемент (извлекается отсюда) + ll_entry_t* tail; // Последний элемент (добавляется сюда) + int count; // Текущее количество элементов + int size_limit; // Максимальное количество (-1 = без ограничения) + + queue_callback_t callback; // Функция коллбэка + void* callback_arg; // Пользовательский аргумент для коллбэка + int callback_suspended; // 1 если коллбэки приостановлены (во время обработки) + + void* resume_timeout_id; // ID таймаута uasync для отложенного возобновления +}; + +// ==================== Управление очередью ==================== + +// Создать новую пустую очередь +// Возвращает: указатель на очередь или NULL при ошибке выделения памяти +ll_queue_t* queue_new(void); + +// Освободить очередь и все её элементы +// Также отменяет отложенное возобновление если оно запланировано +void queue_free(ll_queue_t* q); + +// ==================== Конфигурация очереди ==================== + +// Установить функцию и аргумент коллбэка для очереди +// Коллбэк вызывается при добавлении элемента в пустую очередь (разрешенные коллбэки) +void queue_set_callback(ll_queue_t* q, queue_callback_t cbk_fn, void* arg); + +// Возобновить коллбэки после обработки элемента +// Если в очереди остались элементы, запланирует вызов коллбэка через uasync_set_timeout(0) +// Это предотвращает накопление рекурсии в стеке вызовов +void queue_resume_callback(ll_queue_t* q); + +// Установить максимальное количество элементов в очереди +// При превышении лимита новый элемент автоматически освобождается +void queue_set_size_limit(ll_queue_t* q, int lim); + +// ==================== Управление элементами ==================== + +// Создать новый элемент с областью данных указанного размера +// Память выделяется одним блоком: [ll_entry_t][область данных data_size байт] +// Возвращает: указатель на элемент или NULL при ошибке выделения памяти +ll_entry_t* queue_entry_new(size_t data_size); + +// Освободить элемент (не влияет на связи в очереди) +void queue_entry_free(ll_entry_t* entry); + +// ==================== Операции с очередью ==================== + +// Добавить элемент в конец очереди (FIFO) +// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк +// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) +int queue_entry_put(ll_queue_t* q, ll_entry_t* entry); + +// Добавить элемент в начало очереди (LIFO, высокий приоритет) +// Если очередь была пустой и коллбэки разрешены - вызывает коллбэк +// Возвращает: 0 при успехе, -1 если превышен лимит размера (элемент освобожден) +int queue_entry_put_first(ll_queue_t* q, ll_entry_t* entry); + +// Извлечь элемент из начала очереди +// При извлечении приостанавливает коллбэки (callback_suspended = 1) чтобы предотвратить рекурсию +// Возвращает: указатель на элемент или NULL если очередь пуста +ll_entry_t* queue_entry_get(ll_queue_t* q); + +// Получить текущее количество элементов в очереди +int queue_entry_count(ll_queue_t* q); + +// ==================== Вспомогательные функции ==================== + +// Получить указатель на область данных элемента +// Данные расположены сразу после структуры ll_entry_t +static inline void* ll_entry_data(ll_entry_t* entry) { + return (void*)(entry + 1); +} + +// Получить размер данных элемента +static inline size_t ll_entry_size(ll_entry_t* entry) { + return entry->size; +} + +#endif // LL_QUEUE_H diff --git a/pkt_normalizer.c b/pkt_normalizer.c new file mode 100644 index 00000000..21f207bd --- /dev/null +++ b/pkt_normalizer.c @@ -0,0 +1,421 @@ +#include "pkt_normalizer.h" +#include "u_async.h" +#include "settings.h" +#include +#include +#include + +static void packer_handler(ll_queue_t* q, ll_entry_t* unused, void* arg); +static void unpacker_handler(ll_queue_t* q, ll_entry_t* unused, void* arg); +static void send_buf(pn_struct* pn); +static int get_header(uint8_t* header, size_t L); +static void fragment_timeout_cb(void* arg); +static void set_fragment_timeout(pn_struct* pn); +static void cancel_fragment_timeout(pn_struct* pn); + +pn_struct* pkt_normalizer_init(int is_packer) { + pn_struct* pn = malloc(sizeof(pn_struct)); + if (!pn) return NULL; + + pn->input = queue_new(); + if (!pn->input) { + free(pn); + return NULL; + } + pn->output = queue_new(); + if (!pn->output) { + queue_free(pn->input); + free(pn); + return NULL; + } + pn->is_packer = is_packer; + + if (is_packer) { + pn->u.packer.cap = settings.max_fragment_size; + pn->u.packer.buf = malloc(pn->u.packer.cap); + if (!pn->u.packer.buf) { + queue_free(pn->input); + queue_free(pn->output); + free(pn); + return NULL; + } + pn->u.packer.len = 0; + queue_set_callback(pn->input, packer_handler, pn); + } else { + pn->u.unpacker.buf = NULL; + pn->u.unpacker.len = 0; + pn->u.unpacker.total_len = 0; + pn->u.unpacker.cap = 0; + pn->u.unpacker.error_count = 0; + pn->u.unpacker.in_fragment = 0; + pn->u.unpacker.fragment_timeout_id = NULL; + queue_set_callback(pn->input, unpacker_handler, pn); + } + return pn; +} + +void pkt_normalizer_deinit(pn_struct* pn) { + if (!pn) return; + queue_free(pn->input); + queue_free(pn->output); + if (pn->is_packer) { + free(pn->u.packer.buf); + } else { + cancel_fragment_timeout(pn); + free(pn->u.unpacker.buf); + } + free(pn); +} + +pkt_normalizer_pair* pkt_normalizer_pair_init(void) { + pkt_normalizer_pair* pair = malloc(sizeof(pkt_normalizer_pair)); + if (!pair) return NULL; + + pair->packer = pkt_normalizer_init(1); + if (!pair->packer) { + free(pair); + return NULL; + } + pair->unpacker = pkt_normalizer_init(0); + if (!pair->unpacker) { + pkt_normalizer_deinit(pair->packer); + free(pair); + return NULL; + } + return pair; +} + +void pkt_normalizer_pair_deinit(pkt_normalizer_pair* pair) { + if (!pair) return; + pkt_normalizer_deinit(pair->packer); + pkt_normalizer_deinit(pair->unpacker); + free(pair); +} + +static int get_header(uint8_t* header, size_t L) { + if (L > 3839) return -1; + if (L <= 239) { + header[0] = (uint8_t)L; + return 1; + } else { + uint8_t high = (uint8_t)(L >> 8); + if (high > 14) return -1; + header[0] = 0xF0 + high; + header[1] = (uint8_t)(L & 0xFF); + return 2; + } +} + +/* Сбросить состояние сборки фрагментов */ +static void reset_fragment_state(pn_struct* pn) { + if (!pn->is_packer) { + cancel_fragment_timeout(pn); + pn->u.unpacker.len = 0; + pn->u.unpacker.total_len = 0; + pn->u.unpacker.in_fragment = 0; + } +} + +/* Таймаут для сборки фрагментов */ +static void fragment_timeout_cb(void* arg) { + pn_struct* pn = (pn_struct*)arg; + if (!pn || pn->is_packer) return; + + pn->u.unpacker.fragment_timeout_id = NULL; + pn->u.unpacker.error_count++; + reset_fragment_state(pn); +} + +/* Установить таймаут для текущей сборки фрагментов */ +static void set_fragment_timeout(pn_struct* pn) { + if (!pn || pn->is_packer) return; + + cancel_fragment_timeout(pn); + pn->u.unpacker.fragment_timeout_id = uasync_set_timeout( + PKT_NORMALIZER_FRAGMENT_TIMEOUT, pn, fragment_timeout_cb); +} + +/* Отменить таймаут сборки фрагментов */ +static void cancel_fragment_timeout(pn_struct* pn) { + if (!pn || pn->is_packer) return; + + if (pn->u.unpacker.fragment_timeout_id) { + uasync_cancel_timeout(pn->u.unpacker.fragment_timeout_id); + pn->u.unpacker.fragment_timeout_id = NULL; + } +} + +static void send_buf(pn_struct* pn) { + if (pn->u.packer.len == 0) return; + size_t payload_len = pn->u.packer.len; + ll_entry_t* out = queue_entry_new(2 + payload_len); + if (!out) return; + uint8_t* d = ll_entry_data(out); + *(uint16_t*)d = (uint16_t)payload_len; + memcpy(d + 2, pn->u.packer.buf, payload_len); + queue_entry_put(pn->output, out); + pn->u.packer.len = 0; +} + +static void packer_handler(ll_queue_t* q, ll_entry_t* unused, void* arg) { + (void)unused; + pn_struct* pn = arg; + size_t max = (size_t)settings.max_fragment_size; + while (queue_entry_count(q) > 0) { + ll_entry_t* entry = queue_entry_get(q); + size_t L = ll_entry_size(entry); + uint8_t* data = ll_entry_data(entry); + uint8_t header[2]; + int hsize = get_header(header, L); + size_t needed = (size_t)hsize + L; + if (hsize < 0 || needed > max) { + // Fragment + if (pn->u.packer.len > 0) { + send_buf(pn); + } + size_t remaining = L; + size_t pos = 0; + int fragment_count = 0; + while (remaining > 0) { + size_t chunk; + size_t payload_len; + ll_entry_t* fout; + uint8_t* fd; + uint8_t frag_header[2]; + int frag_hsize; + + if (fragment_count == 0) { + // Первый фрагмент: FF + общая длина (2 байта) + chunk = remaining > (max - 5) ? (max - 5) : remaining; // 2+1+2+chunk <= max + payload_len = 1 + 2 + chunk; // FF + total_len + data + fout = queue_entry_new(2 + payload_len); + if (!fout) break; + fd = ll_entry_data(fout); + *(uint16_t*)fd = (uint16_t)payload_len; + fd += 2; + *fd++ = 0xFF; + *fd++ = (uint8_t)(L >> 8); // старший байт общей длины + *fd++ = (uint8_t)(L & 0xFF); // младший байт общей длины + } else { + // Проверим, можно ли отправить последний фрагмент как обычный блок + frag_hsize = get_header(frag_header, remaining); + if (frag_hsize > 0 && (size_t)frag_hsize + remaining + 2 <= max) { + // Отправляем как обычный блок + payload_len = frag_hsize + remaining; + chunk = remaining; + fout = queue_entry_new(2 + payload_len); + if (!fout) break; + fd = ll_entry_data(fout); + *(uint16_t*)fd = (uint16_t)payload_len; + fd += 2; + memcpy(fd, frag_header, frag_hsize); + fd += frag_hsize; + } else { + // Промежуточный или последний фрагмент как FE + chunk = remaining > (max - 3) ? (max - 3) : remaining; // 2+1+chunk <= max + payload_len = 1 + chunk; // FE + data + fout = queue_entry_new(2 + payload_len); + if (!fout) break; + fd = ll_entry_data(fout); + *(uint16_t*)fd = (uint16_t)payload_len; + fd += 2; + *fd++ = 0xFE; + } + } + memcpy(fd, data + pos, chunk); + queue_entry_put(pn->output, fout); + pos += chunk; + remaining -= chunk; + fragment_count++; + } + } else { + if (pn->u.packer.len + needed > max) { + send_buf(pn); + } + // Add to buffer + uint8_t* p = pn->u.packer.buf + pn->u.packer.len; + memcpy(p, header, (size_t)hsize); + memcpy(p + hsize, data, L); + pn->u.packer.len += needed; + } + queue_entry_free(entry); + } + if (pn->u.packer.len > 0) { + send_buf(pn); + } + queue_resume_callback(q); +} + +int pkt_normalizer_get_error_count(const pn_struct* pn) { + if (!pn || pn->is_packer) { + return 0; + } + return pn->u.unpacker.error_count; +} + +void pkt_normalizer_reset_error_count(pn_struct* pn) { + if (!pn || pn->is_packer) { + return; + } + pn->u.unpacker.error_count = 0; +} + +static void unpacker_handler(ll_queue_t* q, ll_entry_t* unused, void* arg) { + (void)unused; + pn_struct* pn = arg; + while (queue_entry_count(q) > 0) { + ll_entry_t* entry = queue_entry_get(q); + uint8_t* data = ll_entry_data(entry); + size_t total = ll_entry_size(entry); + uint16_t payload_len = *(uint16_t*)data; + if (total != 2 + (size_t)payload_len) { + queue_entry_free(entry); + continue; + } + uint8_t* cg = data + 2; + size_t cg_pos = 0; + size_t cg_len = (size_t)payload_len; + while (cg_pos < cg_len) { + uint8_t byte = cg[cg_pos++]; + + if (byte == 0xFF) { + /* Начало нового фрагментированного пакета */ + if (pn->u.unpacker.in_fragment) { + /* Не завершен предыдущий фрагмент - ошибка */ + pn->u.unpacker.error_count++; + reset_fragment_state(pn); + } + /* Проверить, что есть 2 байта для общей длины */ + if (cg_pos + 2 > cg_len) { + pn->u.unpacker.error_count++; + goto err; + } + /* Прочитать общую длину */ + uint16_t total_len = ((uint16_t)cg[cg_pos] << 8) | cg[cg_pos + 1]; + cg_pos += 2; + size_t chunk_len = cg_len - cg_pos; + /* Выделить буфер при необходимости */ + size_t new_len = chunk_len; + if (new_len > pn->u.unpacker.cap) { + size_t new_cap = pn->u.unpacker.cap ? pn->u.unpacker.cap * 2 : 4096; + if (new_cap < new_len) new_cap = new_len; + pn->u.unpacker.buf = realloc(pn->u.unpacker.buf, new_cap); + pn->u.unpacker.cap = new_cap; + } + memcpy(pn->u.unpacker.buf, cg + cg_pos, chunk_len); + pn->u.unpacker.len = chunk_len; + pn->u.unpacker.total_len = total_len; + pn->u.unpacker.in_fragment = 1; + set_fragment_timeout(pn); + cg_pos += chunk_len; + /* Проверить, не собрали ли уже весь пакет */ + if (pn->u.unpacker.len >= pn->u.unpacker.total_len) { + if (pn->u.unpacker.len == pn->u.unpacker.total_len) { + ll_entry_t* out = queue_entry_new(pn->u.unpacker.total_len); + if (out) { + memcpy(ll_entry_data(out), pn->u.unpacker.buf, pn->u.unpacker.total_len); + queue_entry_put(pn->output, out); + } + } else { + /* Слишком много данных - ошибка */ + pn->u.unpacker.error_count++; + } + reset_fragment_state(pn); + } + continue; + } + + if (byte == 0xFE) { + /* Продолжение фрагментированного пакета */ + if (!pn->u.unpacker.in_fragment) { + /* Не было начала фрагмента - ошибка */ + pn->u.unpacker.error_count++; + goto err; + } + size_t chunk_len = cg_len - cg_pos; + size_t new_len = pn->u.unpacker.len + chunk_len; + if (new_len > pn->u.unpacker.cap) { + size_t new_cap = pn->u.unpacker.cap ? pn->u.unpacker.cap * 2 : 4096; + if (new_cap < new_len) new_cap = new_len; + pn->u.unpacker.buf = realloc(pn->u.unpacker.buf, new_cap); + pn->u.unpacker.cap = new_cap; + } + memcpy(pn->u.unpacker.buf + pn->u.unpacker.len, cg + cg_pos, chunk_len); + pn->u.unpacker.len = new_len; + cg_pos += chunk_len; + set_fragment_timeout(pn); + /* Проверить, не собрали ли уже весь пакет */ + if (pn->u.unpacker.len >= pn->u.unpacker.total_len) { + if (pn->u.unpacker.len == pn->u.unpacker.total_len) { + ll_entry_t* out = queue_entry_new(pn->u.unpacker.total_len); + if (out) { + memcpy(ll_entry_data(out), pn->u.unpacker.buf, pn->u.unpacker.total_len); + queue_entry_put(pn->output, out); + } + } else { + /* Слишком много данных - ошибка */ + pn->u.unpacker.error_count++; + } + reset_fragment_state(pn); + } + continue; + } + + /* Обычная запись (не фрагмент) */ + size_t L; + if (byte <= 0xEF) { + L = byte; + } else if (byte >= 0xF0 && byte <= 0xFE) { + if (cg_pos >= cg_len) goto err; + uint8_t ext = cg[cg_pos++]; + L = ((size_t)(byte - 0xF0) << 8) | ext; + } else { + /* Недопустимый байт */ + goto err; + } + + if (cg_pos + L > cg_len) goto err; + + if (pn->u.unpacker.in_fragment) { + /* Это последний фрагмент в виде обычной записи */ + size_t new_len = pn->u.unpacker.len + L; + if (new_len > pn->u.unpacker.cap) { + size_t new_cap = pn->u.unpacker.cap ? pn->u.unpacker.cap * 2 : 4096; + if (new_cap < new_len) new_cap = new_len; + pn->u.unpacker.buf = realloc(pn->u.unpacker.buf, new_cap); + pn->u.unpacker.cap = new_cap; + } + memcpy(pn->u.unpacker.buf + pn->u.unpacker.len, cg + cg_pos, L); + pn->u.unpacker.len = new_len; + cg_pos += L; + set_fragment_timeout(pn); + + /* Проверить, собрали ли весь пакет */ + if (pn->u.unpacker.len >= pn->u.unpacker.total_len) { + if (pn->u.unpacker.len == pn->u.unpacker.total_len) { + ll_entry_t* out = queue_entry_new(pn->u.unpacker.total_len); + if (out) { + memcpy(ll_entry_data(out), pn->u.unpacker.buf, pn->u.unpacker.total_len); + queue_entry_put(pn->output, out); + } + } else { + /* Слишком много данных - ошибка */ + pn->u.unpacker.error_count++; + } + reset_fragment_state(pn); + } + } else { + /* Обычная запись (не часть фрагмента) */ + ll_entry_t* out = queue_entry_new(L); + if (out) { + memcpy(ll_entry_data(out), cg + cg_pos, L); + queue_entry_put(pn->output, out); + } + cg_pos += L; + } + } + err: + queue_entry_free(entry); + } + queue_resume_callback(q); +} diff --git a/pkt_normalizer.h b/pkt_normalizer.h new file mode 100644 index 00000000..5421231a --- /dev/null +++ b/pkt_normalizer.h @@ -0,0 +1,53 @@ +// pkt_normalizer.h +#ifndef PKT_NORMALIZER_H +#define PKT_NORMALIZER_H + +#include "ll_queue.h" +#include + +/* Default fragment reassembly timeout in uasync timebase units (0.1 ms) */ +#ifndef PKT_NORMALIZER_FRAGMENT_TIMEOUT +#define PKT_NORMALIZER_FRAGMENT_TIMEOUT 5000 /* 500 ms */ +#endif + +typedef struct pn_struct pn_struct; +typedef struct pkt_normalizer_pair pkt_normalizer_pair; + +struct pn_struct { + ll_queue_t* input; + ll_queue_t* output; + int is_packer; + union { + struct { + uint8_t* buf; + size_t len; + size_t cap; + } packer; + struct { + uint8_t* buf; /* буфер для сборки фрагментов */ + size_t len; /* текущая накопленная длина */ + size_t total_len; /* ожидаемая общая длина из первого фрагмента */ + size_t cap; /* ёмкость буфера */ + int error_count; /* счетчик ошибок сборки */ + int in_fragment; /* флаг: идет сборка фрагментов (1) или нет (0) */ + void* fragment_timeout_id; /* ID таймаута для сборки фрагментов */ + } unpacker; + } u; +}; + +pn_struct* pkt_normalizer_init(int is_packer); // 1 for packer, 0 for unpacker +void pkt_normalizer_deinit(pn_struct* pn); + +pkt_normalizer_pair* pkt_normalizer_pair_init(void); +void pkt_normalizer_pair_deinit(pkt_normalizer_pair* pair); + +/* Error handling */ +int pkt_normalizer_get_error_count(const pn_struct* pn); +void pkt_normalizer_reset_error_count(pn_struct* pn); + +struct pkt_normalizer_pair { + pn_struct* packer; + pn_struct* unpacker; +}; + +#endif // PKT_NORMALIZER_H diff --git a/sc_lib.c b/sc_lib.c new file mode 100644 index 00000000..6b3ecc68 --- /dev/null +++ b/sc_lib.c @@ -0,0 +1,265 @@ +/* sc_lib.c - Secure Channel library implementation using TinyCrypt */ + +#include "sc_lib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct uECC_Curve_t *curve = NULL; + +static int sc_rng(uint8_t *dest, unsigned size) +{ + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + return 0; + } + + ssize_t ret = read(fd, dest, size); + close(fd); + if (ret != size) { + return 0; + } + + /* Mix in PID and microtime for additional entropy */ + pid_t pid = getpid(); + struct timeval tv; + gettimeofday(&tv, NULL); + + for (unsigned i = 0; i < size; i++) { + dest[i] ^= ((pid >> (i % (sizeof(pid) * 8))) & 0xFF); + dest[i] ^= ((tv.tv_sec >> (i % (sizeof(tv.tv_sec) * 8))) & 0xFF); + dest[i] ^= ((tv.tv_usec >> (i % (sizeof(tv.tv_usec) * 8))) & 0xFF); + } + + return 1; +} + +static int sc_validate_key(const uint8_t *public_key) +{ + if (!curve) { + curve = uECC_secp256r1(); + } + return uECC_valid_public_key(public_key, curve); +} + +sc_status_t sc_generate_keypair(sc_context_t *ctx) +{ + if (!ctx) { + return SC_ERR_INVALID_ARG; + } + + if (!curve) { + curve = uECC_secp256r1(); + } + + /* Set custom RNG function */ + uECC_set_rng(sc_rng); + + if (!uECC_make_key(ctx->public_key, ctx->private_key, curve)) { + return SC_ERR_CRYPTO; + } + + ctx->initialized = 1; + ctx->peer_key_set = 0; + ctx->session_ready = 0; + ctx->tx_counter = 0; + ctx->rx_counter = 0; + + return SC_OK; +} + +sc_status_t sc_init_local_keys(sc_context_t *ctx, + const uint8_t *public_key, + const uint8_t *private_key) +{ + if (!ctx || !public_key || !private_key) { + return SC_ERR_INVALID_ARG; + } + + if (!curve) { + curve = uECC_secp256r1(); + } + + /* Validate public key */ + if (sc_validate_key(public_key) != 0) { + return SC_ERR_INVALID_ARG; + } + + memcpy(ctx->public_key, public_key, SC_PUBKEY_SIZE); + memcpy(ctx->private_key, private_key, SC_PRIVKEY_SIZE); + + ctx->initialized = 1; + ctx->peer_key_set = 0; + ctx->session_ready = 0; + ctx->tx_counter = 0; + ctx->rx_counter = 0; + + return SC_OK; +} + +sc_status_t sc_set_peer_public_key(sc_context_t *ctx, + const uint8_t *peer_public_key) +{ + uint8_t shared_secret[SC_SHARED_SECRET_SIZE]; + + if (!ctx || !peer_public_key) { + return SC_ERR_INVALID_ARG; + } + + if (!ctx->initialized) { + return SC_ERR_NOT_INITIALIZED; + } + + if (!curve) { + curve = uECC_secp256r1(); + } + + /* Validate peer public key */ + if (sc_validate_key(peer_public_key) != 0) { + return SC_ERR_INVALID_ARG; + } + + /* Compute shared secret using ECDH */ + if (!uECC_shared_secret(peer_public_key, ctx->private_key, + shared_secret, curve)) { + return SC_ERR_CRYPTO; + } + + /* Derive session key from shared secret (simple copy for demo) */ + memcpy(ctx->session_key, shared_secret, SC_SESSION_KEY_SIZE); + + /* Store peer public key */ + memcpy(ctx->peer_public_key, peer_public_key, SC_PUBKEY_SIZE); + ctx->peer_key_set = 1; + + ctx->session_ready = 1; + + return SC_OK; +} + +static void sc_build_nonce(uint32_t counter, uint8_t *nonce_out) +{ + /* Simple nonce construction: counter in little-endian + zeros */ + memset(nonce_out, 0, SC_NONCE_SIZE); + nonce_out[0] = (counter >> 0) & 0xFF; + nonce_out[1] = (counter >> 8) & 0xFF; + nonce_out[2] = (counter >> 16) & 0xFF; + nonce_out[3] = (counter >> 24) & 0xFF; +} + +sc_status_t sc_encrypt(sc_context_t *ctx, + const uint8_t *plaintext, + size_t plaintext_len, + uint8_t *ciphertext, + uint8_t *tag) +{ + uint8_t nonce[SC_NONCE_SIZE]; + struct tc_aes_key_sched_struct sched; + struct tc_ccm_mode_struct ccm_state; + TCCcmMode_t c = &ccm_state; + uint8_t combined_output[plaintext_len + SC_TAG_SIZE]; + + if (!ctx || !plaintext || !ciphertext || !tag) { + return SC_ERR_INVALID_ARG; + } + + if (!ctx->session_ready) { + return SC_ERR_NOT_INITIALIZED; + } + + if (plaintext_len == 0) { + return SC_ERR_INVALID_ARG; + } + + /* Initialize AES key schedule */ + if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { + return SC_ERR_CRYPTO; + } + + /* Build nonce from counter */ + sc_build_nonce(ctx->tx_counter, nonce); + + /* Configure CCM mode */ + if (tc_ccm_config(c, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { + return SC_ERR_CRYPTO; + } + + /* Encrypt and generate tag */ + if (tc_ccm_generation_encryption(combined_output, sizeof(combined_output), + NULL, 0, /* no associated data */ + plaintext, plaintext_len, + c) != TC_CRYPTO_SUCCESS) { + return SC_ERR_CRYPTO; + } + + /* Split combined output into ciphertext and tag */ + memcpy(ciphertext, combined_output, plaintext_len); + memcpy(tag, combined_output + plaintext_len, SC_TAG_SIZE); + + ctx->tx_counter++; + + return SC_OK; +} + +sc_status_t sc_decrypt(sc_context_t *ctx, + const uint8_t *ciphertext, + size_t ciphertext_len, + const uint8_t *tag, + uint8_t *plaintext) +{ + uint8_t nonce[SC_NONCE_SIZE]; + struct tc_aes_key_sched_struct sched; + struct tc_ccm_mode_struct ccm_state; + TCCcmMode_t c = &ccm_state; + uint8_t combined_input[ciphertext_len + SC_TAG_SIZE]; + + if (!ctx || !ciphertext || !tag || !plaintext) { + return SC_ERR_INVALID_ARG; + } + + if (!ctx->session_ready) { + return SC_ERR_NOT_INITIALIZED; + } + + if (ciphertext_len == 0) { + return SC_ERR_INVALID_ARG; + } + + /* Combine ciphertext and tag for CCM input */ + memcpy(combined_input, ciphertext, ciphertext_len); + memcpy(combined_input + ciphertext_len, tag, SC_TAG_SIZE); + + /* Initialize AES key schedule */ + if (tc_aes128_set_encrypt_key(&sched, ctx->session_key) != TC_CRYPTO_SUCCESS) { + return SC_ERR_CRYPTO; + } + + /* Build nonce from counter */ + sc_build_nonce(ctx->rx_counter, nonce); + + /* Configure CCM mode */ + if (tc_ccm_config(c, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE) != TC_CRYPTO_SUCCESS) { + return SC_ERR_CRYPTO; + } + + /* Decrypt and verify tag */ + if (tc_ccm_decryption_verification(plaintext, ciphertext_len, + NULL, 0, /* no associated data */ + combined_input, ciphertext_len + SC_TAG_SIZE, + c) != TC_CRYPTO_SUCCESS) { + return SC_ERR_AUTH_FAILED; + } + + ctx->rx_counter++; + + return SC_OK; +} diff --git a/sc_lib.h b/sc_lib.h new file mode 100644 index 00000000..d3a384db --- /dev/null +++ b/sc_lib.h @@ -0,0 +1,119 @@ +#ifndef SECURE_CHANNEL_H +#define SECURE_CHANNEL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ===== Константы ===== */ + +#define SC_PUBKEY_SIZE 64 /* secp256r1: X || Y */ +#define SC_PRIVKEY_SIZE 32 +#define SC_SHARED_SECRET_SIZE 32 +#define SC_SESSION_KEY_SIZE 16 /* AES-128 key size */ +#define SC_NONCE_SIZE 13 +#define SC_TAG_SIZE 16 + +/* ===== Коды ошибок ===== */ + +typedef enum { + SC_OK = 0, + SC_ERR_INVALID_ARG, + SC_ERR_CRYPTO, + SC_ERR_NOT_INITIALIZED, + SC_ERR_AUTH_FAILED +} sc_status_t; + +/* ===== Контекст защищённого канала ===== */ + +typedef struct +{ + /* Локальные ключи */ + uint8_t private_key[SC_PRIVKEY_SIZE]; + uint8_t public_key[SC_PUBKEY_SIZE]; + + /* Ключ пира */ + uint8_t peer_public_key[SC_PUBKEY_SIZE]; + uint8_t peer_key_set; + + /* Производные ключи */ + uint8_t session_key[SC_SESSION_KEY_SIZE]; + + /* Nonce / counters */ + uint32_t tx_counter; + uint32_t rx_counter; + + /* Флаги состояния */ + uint8_t initialized; + uint8_t session_ready; + +} sc_context_t; + +/* ===== API ===== */ + +/** + * @brief Сгенерировать пару ECDH ключей + * + * @param ctx Контекст + * @return SC_OK или ошибка + */ +sc_status_t sc_generate_keypair(sc_context_t *ctx); + +/** + * @brief Инициализация контекста с уже существующими ключами + * + * @param ctx Контекст + * @param public_key Указатель на публичный ключ (64 байта) + * @param private_key Указатель на приватный ключ (32 байта) + */ +sc_status_t sc_init_local_keys(sc_context_t *ctx, + const uint8_t *public_key, + const uint8_t *private_key); + +/** + * @brief Установить публичный ключ пира и вычислить session key + * + * @param ctx Контекст + * @param peer_public_key Публичный ключ пира (64 байта) + */ +sc_status_t sc_set_peer_public_key(sc_context_t *ctx, + const uint8_t *peer_public_key); + +/** + * @brief Зашифровать сообщение + * + * @param ctx Контекст + * @param plaintext Входные данные + * @param plaintext_len Длина + * @param ciphertext Выход (может совпадать с plaintext) + * @param tag MAC-тег (16 байт) + */ +sc_status_t sc_encrypt(sc_context_t *ctx, + const uint8_t *plaintext, + size_t plaintext_len, + uint8_t *ciphertext, + uint8_t *tag); + +/** + * @brief Расшифровать и проверить сообщение + * + * @param ctx Контекст + * @param ciphertext Зашифрованные данные + * @param ciphertext_len Длина + * @param tag MAC-тег + * @param plaintext Выход + */ +sc_status_t sc_decrypt(sc_context_t *ctx, + const uint8_t *ciphertext, + size_t ciphertext_len, + const uint8_t *tag, + uint8_t *plaintext); + +#ifdef __cplusplus +} +#endif + +#endif /* SECURE_CHANNEL_H */ diff --git a/settings.c b/settings.c new file mode 100644 index 00000000..a633438e --- /dev/null +++ b/settings.c @@ -0,0 +1,6 @@ +// settings.c +#include "settings.h" + +settings_t settings = { + .max_fragment_size = 1400 +}; diff --git a/settings.h b/settings.h new file mode 100644 index 00000000..395b9120 --- /dev/null +++ b/settings.h @@ -0,0 +1,11 @@ +// settings.h +#ifndef SETTINGS_H +#define SETTINGS_H + +typedef struct { + int max_fragment_size; +} settings_t; + +extern settings_t settings; + +#endif // SETTINGS_H diff --git a/tests/test_ecc_encrypt.c b/tests/test_ecc_encrypt.c new file mode 100644 index 00000000..1b098705 --- /dev/null +++ b/tests/test_ecc_encrypt.c @@ -0,0 +1,179 @@ +/* test_ecc_encrypt.c - TinyCrypt test for client-server key exchange and encryption */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TC_PASS 0 +#define TC_FAIL 1 + +#define TC_PRINT printf +#define TC_ERROR(...) do { printf("ERROR: " __VA_ARGS__); } while(0) +#define TC_START(name) printf("Starting test: %s\n", name) +#define TC_END_RESULT(result) printf("Result: %s\n", (result) == TC_PASS ? "PASS" : "FAIL") +#define TC_END_REPORT(result) printf("Test %s\n", (result) == TC_PASS ? "SUCCESSFUL" : "FAILED") + +static void show_str(const char *label, const uint8_t *s, size_t len) +{ + unsigned int i; + printf("%s = ", label); + for (i = 0; i < (unsigned int) len; ++i) { + printf("%02x", s[i]); + } + printf("\n"); +} + +static int test_key_exchange_and_encrypt(void) +{ + const struct uECC_Curve_t *curve = uECC_secp256r1(); + + /* Client key pair */ + uint8_t client_private[NUM_ECC_BYTES]; + uint8_t client_public[2 * NUM_ECC_BYTES]; + + /* Server key pair */ + uint8_t server_private[NUM_ECC_BYTES]; + uint8_t server_public[2 * NUM_ECC_BYTES]; + + /* Shared secrets */ + uint8_t client_secret[NUM_ECC_BYTES]; + uint8_t server_secret[NUM_ECC_BYTES]; + + TC_PRINT("Generating client key pair...\n"); + if (!uECC_make_key(client_public, client_private, curve)) { + TC_ERROR("Failed to generate client key pair\n"); + return TC_FAIL; + } + + TC_PRINT("Generating server key pair...\n"); + if (!uECC_make_key(server_public, server_private, curve)) { + TC_ERROR("Failed to generate server key pair\n"); + return TC_FAIL; + } + + /* Compute shared secret on client side */ + TC_PRINT("Computing shared secret on client side...\n"); + if (!uECC_shared_secret(server_public, client_private, client_secret, curve)) { + TC_ERROR("Failed to compute client shared secret\n"); + return TC_FAIL; + } + + /* Compute shared secret on server side */ + TC_PRINT("Computing shared secret on server side...\n"); + if (!uECC_shared_secret(client_public, server_private, server_secret, curve)) { + TC_ERROR("Failed to compute server shared secret\n"); + return TC_FAIL; + } + + /* Verify that both shared secrets match */ + if (memcmp(client_secret, server_secret, NUM_ECC_BYTES) != 0) { + TC_ERROR("Shared secrets do not match\n"); + show_str("Client secret", client_secret, NUM_ECC_BYTES); + show_str("Server secret", server_secret, NUM_ECC_BYTES); + return TC_FAIL; + } + TC_PRINT("Shared secrets match.\n"); + + /* Derive AES key from shared secret (first 16 bytes) */ + uint8_t aes_key[TC_AES_KEY_SIZE]; + memcpy(aes_key, client_secret, TC_AES_KEY_SIZE); + + /* Prepare test data */ + const char *plaintext = "Hello, secure world!"; + size_t plaintext_len = strlen(plaintext) + 1; /* include null terminator */ + uint8_t ciphertext[plaintext_len]; + uint8_t decrypted[plaintext_len]; + + /* Initialize AES key schedule */ + struct tc_aes_key_sched_struct sched; + if (tc_aes128_set_encrypt_key(&sched, aes_key) != TC_CRYPTO_SUCCESS) { + TC_ERROR("Failed to set AES encryption key\n"); + return TC_FAIL; + } + + /* Initialize counter (little-endian 32-bit) */ + uint8_t ctr[TC_AES_BLOCK_SIZE] = {0}; /* zero-initialized counter */ + + TC_PRINT("Encrypting plaintext...\n"); + if (tc_ctr_mode(ciphertext, plaintext_len, (const uint8_t *)plaintext, + plaintext_len, ctr, &sched) != TC_CRYPTO_SUCCESS) { + TC_ERROR("Encryption failed\n"); + return TC_FAIL; + } + + /* Reset counter for decryption (CTR mode uses same counter sequence) */ + memset(ctr, 0, TC_AES_BLOCK_SIZE); + + TC_PRINT("Decrypting ciphertext...\n"); + if (tc_ctr_mode(decrypted, plaintext_len, ciphertext, + plaintext_len, ctr, &sched) != TC_CRYPTO_SUCCESS) { + TC_ERROR("Decryption failed\n"); + return TC_FAIL; + } + + /* Verify decrypted matches original */ + if (memcmp(plaintext, decrypted, plaintext_len) != 0) { + TC_ERROR("Decrypted text does not match original\n"); + show_str("Original", (const uint8_t *)plaintext, plaintext_len); + show_str("Decrypted", decrypted, plaintext_len); + return TC_FAIL; + } + TC_PRINT("Decryption successful. Test passed.\n"); + + return TC_PASS; +} + +int main(void) +{ + unsigned int result = TC_PASS; + + TC_START("Performing client-server key exchange and encryption test:"); + + /* Setup cryptographically secure PRNG */ + uECC_set_rng(&default_CSPRNG); + + result = test_key_exchange_and_encrypt(); + + TC_END_RESULT(result); + TC_END_REPORT(result); + + return result; +} \ No newline at end of file diff --git a/tests/test_pkt_normalizer.c b/tests/test_pkt_normalizer.c new file mode 100644 index 00000000..ca9b1b47 --- /dev/null +++ b/tests/test_pkt_normalizer.c @@ -0,0 +1,533 @@ +#include "u_async.h" +#include "ll_queue.h" +#include "pkt_normalizer.h" +#include "settings.h" +#include +#include +#include +#include +#include +#include + +#define TEST_ASSERT(cond, msg) \ + do { \ + if (!(cond)) { \ + printf("FAIL: %s (line %d)\n", msg, __LINE__); \ + return 1; \ + } else { \ + printf("PASS: %s\n", msg); \ + } \ + } while(0) + +/* Структура для хранения тестового пакета */ +typedef struct { + uint8_t* data; + size_t len; +} test_packet_t; + +#define MAX_TEST_PACKETS 20 +static test_packet_t sent_packets[MAX_TEST_PACKETS]; +static test_packet_t received_packets[MAX_TEST_PACKETS]; +static int sent_count = 0; +static int received_count = 0; + +static void reset_test_data(void) { + for (int i = 0; i < sent_count; i++) { + free(sent_packets[i].data); + sent_packets[i].data = NULL; + } + for (int i = 0; i < received_count; i++) { + free(received_packets[i].data); + received_packets[i].data = NULL; + } + sent_count = 0; + received_count = 0; +} + +static void add_sent_packet(const uint8_t* data, size_t len) { + assert(sent_count < MAX_TEST_PACKETS); + sent_packets[sent_count].data = malloc(len); + assert(sent_packets[sent_count].data); + memcpy(sent_packets[sent_count].data, data, len); + sent_packets[sent_count].len = len; + sent_count++; +} + +static void add_received_packet(const uint8_t* data, size_t len) { + assert(received_count < MAX_TEST_PACKETS); + received_packets[received_count].data = malloc(len); + assert(received_packets[received_count].data); + memcpy(received_packets[received_count].data, data, len); + received_packets[received_count].len = len; + received_count++; +} + +static int compare_packets(void) { + if (sent_count != received_count) { + printf("Packet count mismatch: sent=%d, received=%d\n", sent_count, received_count); + return -1; + } + for (int i = 0; i < sent_count; i++) { + if (sent_packets[i].len != received_packets[i].len) { + printf("Packet %d length mismatch: sent=%zu, received=%zu\n", + i, sent_packets[i].len, received_packets[i].len); + return -1; + } + if (memcmp(sent_packets[i].data, received_packets[i].data, sent_packets[i].len) != 0) { + printf("Packet %d data mismatch\n", i); + return -1; + } + } + return 0; +} + +/* Создать тестовый пакет со случайным содержимым */ +static ll_entry_t* create_test_packet(size_t data_size) { + ll_entry_t* entry = queue_entry_new(data_size); + if (!entry) { + return NULL; + } + uint8_t* data = ll_entry_data(entry); + for (size_t i = 0; i < data_size; i++) { + data[i] = rand() & 0xFF; + } + return entry; +} + +/* Коллбэк для пересылки пакетов от упаковщика к распаковщику */ +static void forward_cb(ll_queue_t* q, ll_entry_t* unused, void* arg) { + (void)unused; + ll_queue_t* target = (ll_queue_t*)arg; + while (queue_entry_count(q) > 0) { + ll_entry_t* e = queue_entry_get(q); + queue_entry_put(target, e); // Transfer ownership + } + queue_resume_callback(q); +} + +/* Коллбэк для сбора полученных пакетов */ +static void receive_cb(ll_queue_t* q, ll_entry_t* unused, void* arg) { + (void)unused; + (void)arg; + while (queue_entry_count(q) > 0) { + ll_entry_t* e = queue_entry_get(q); + uint8_t* data = ll_entry_data(e); + size_t len = ll_entry_size(e); + add_received_packet(data, len); + queue_entry_free(e); + } + queue_resume_callback(q); +} + +/* Принудительно обработать все очереди, вызывая коллбэки для непустых очередей + * Это нужно потому что в тестовой среде нет uasync_mainloop + */ +static void process_queues(pkt_normalizer_pair* pair) { + int iterations = 0; + int processed; + + /* Сначала принудительно сбросим все флаги callback_suspended, потому что + * uasync таймауты не работают в тестовой среде */ + pair->packer->input->callback_suspended = 0; + pair->packer->output->callback_suspended = 0; + pair->unpacker->input->callback_suspended = 0; + pair->unpacker->output->callback_suspended = 0; + + do { + processed = 0; + iterations++; + + /* Обработать входную очередь упаковщика */ + if (pair->packer->input->callback && + queue_entry_count(pair->packer->input) > 0) { + pair->packer->input->callback(pair->packer->input, + pair->packer->input->head, + pair->packer->input->callback_arg); + processed = 1; + } + + /* Обработать выходную очередь упаковщика (forward_cb) */ + if (pair->packer->output->callback && + queue_entry_count(pair->packer->output) > 0) { + pair->packer->output->callback(pair->packer->output, + pair->packer->output->head, + pair->packer->output->callback_arg); + processed = 1; + } + + /* Обработать входную очередь распаковщика */ + if (pair->unpacker->input->callback && + queue_entry_count(pair->unpacker->input) > 0) { + pair->unpacker->input->callback(pair->unpacker->input, + pair->unpacker->input->head, + pair->unpacker->input->callback_arg); + processed = 1; + } + + /* Обработать выходную очередь распаковщика (receive_cb) */ + if (pair->unpacker->output->callback && + queue_entry_count(pair->unpacker->output) > 0) { + pair->unpacker->output->callback(pair->unpacker->output, + pair->unpacker->output->head, + pair->unpacker->output->callback_arg); + processed = 1; + } + + if (iterations > 50) { + printf("ERROR: process_queues infinite loop detected\n"); + break; + } + } while (processed); +} + +/* Тест 1: мелкие пакеты */ +static int test_small_packets(pkt_normalizer_pair* pair) { + printf("\n--- Test 1: small packets ---\n"); + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + const char* packets[] = {"hello", "world", "test"}; + for (size_t i = 0; i < sizeof(packets)/sizeof(packets[0]); i++) { + size_t len = strlen(packets[i]); + ll_entry_t* entry = queue_entry_new(len); + TEST_ASSERT(entry != NULL, "create packet"); + memcpy(ll_entry_data(entry), packets[i], len); + add_sent_packet((const uint8_t*)packets[i], len); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put into packer input"); + } + + process_queues(pair); + + TEST_ASSERT(compare_packets() == 0, "small packets comparison"); + return 0; +} + +/* Тест 2: средний пакет (не фрагментируется) */ +static int test_medium_packet(pkt_normalizer_pair* pair) { + printf("\n--- Test 2: medium packet ---\n"); + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + size_t data_size = 500; + ll_entry_t* entry = create_test_packet(data_size); + TEST_ASSERT(entry != NULL, "create medium packet"); + + uint8_t* data = ll_entry_data(entry); + add_sent_packet(data, data_size); + + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put medium packet"); + + process_queues(pair); + + TEST_ASSERT(compare_packets() == 0, "medium packet comparison"); + return 0; +} + +/* Тест 3: большой пакет с фрагментацией */ +static int test_fragmentation(pkt_normalizer_pair* pair) { + printf("\n--- Test 3: fragmentation ---\n"); + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + /* Сохранить оригинальный размер фрагмента */ + int original_fragment_size = settings.max_fragment_size; + + /* Установить маленький размер фрагмента для тестирования */ + settings.max_fragment_size = 300; + + size_t data_size = 1000; /* Должен быть фрагментирован */ + ll_entry_t* entry = create_test_packet(data_size); + TEST_ASSERT(entry != NULL, "create big packet"); + + uint8_t* data = ll_entry_data(entry); + add_sent_packet(data, data_size); + + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put big packet"); + + process_queues(pair); + + /* Проверить, что не было ошибок сборки */ + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no fragmentation errors"); + + /* Восстановить оригинальный размер */ + settings.max_fragment_size = original_fragment_size; + + TEST_ASSERT(compare_packets() == 0, "fragmented packet comparison"); + return 0; +} + +/* Тест 4: несколько пакетов разного размера */ +static int test_mixed_packets(pkt_normalizer_pair* pair) { + printf("\n--- Test 4: mixed size packets ---\n"); + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + /* Отправить пакеты разных размеров */ + size_t sizes[] = {10, 100, 50, 300, 5}; + for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) { + ll_entry_t* entry = create_test_packet(sizes[i]); + TEST_ASSERT(entry != NULL, "create mixed packet"); + + uint8_t* data = ll_entry_data(entry); + add_sent_packet(data, sizes[i]); + + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put mixed packet"); + } + + process_queues(pair); + + TEST_ASSERT(compare_packets() == 0, "mixed packets comparison"); + return 0; +} + +/* Тест 6: стресс-тест со случайными размерами пакетов */ +static int test_stress_random(pkt_normalizer_pair* pair) { + printf("\n--- Test 6: stress test with random packets ---\n"); + const int NUM_PACKETS = 100; + const int MAX_PACKET_SIZE = 4000; + int original_fragment_size = settings.max_fragment_size; + + /* Часть 1: случайные пакеты без изменения размера фрагмента */ + for (int i = 0; i < NUM_PACKETS; i++) { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + /* Случайный размер пакета от 1 до MAX_PACKET_SIZE */ + size_t size = (rand() % MAX_PACKET_SIZE) + 1; + + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create random packet"); + + uint8_t* data = ll_entry_data(entry); + add_sent_packet(data, size); + + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put random packet"); + + process_queues(pair); + + /* Проверить, что пакет корректно обработан */ + TEST_ASSERT(compare_packets() == 0, "random packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors during random packet"); + } + + /* Часть 2: фрагментация со случайным размером фрагмента */ + const int FRAGMENT_TESTS = 50; + for (int i = 0; i < FRAGMENT_TESTS; i++) { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + /* Случайный размер фрагмента от 50 до 500 */ + int frag_size = (rand() % 451) + 50; + settings.max_fragment_size = frag_size; + + /* Случайный размер пакета от frag_size+1 до 3000 (чтобы гарантировать фрагментацию) */ + size_t packet_size = (rand() % (3000 - frag_size)) + frag_size + 1; + + ll_entry_t* entry = create_test_packet(packet_size); + TEST_ASSERT(entry != NULL, "create fragmentable packet"); + + uint8_t* data = ll_entry_data(entry); + add_sent_packet(data, packet_size); + + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put fragmentable packet"); + + process_queues(pair); + + /* Проверить, что пакет корректно обработан */ + TEST_ASSERT(compare_packets() == 0, "fragmentable packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors during fragmentation"); + } + + settings.max_fragment_size = original_fragment_size; + return 0; +} + +/* Тест 7: граничные случаи и максимальные размеры */ +static int test_edge_cases(pkt_normalizer_pair* pair) { + printf("\n--- Test 7: edge cases and maximum sizes ---\n"); + int original_fragment_size = settings.max_fragment_size; + + /* Сбросить данные теста */ + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + + /* Тест 1: минимальный размер пакета (1 байт) */ + { + size_t size = 1; + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 1-byte packet"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 1-byte packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "1-byte packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 1-byte packet"); + } + + /* Тест 2: граница одно- и двухбайтного заголовка (239/240) */ + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + size_t size = 239; + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 239-byte packet"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 239-byte packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "239-byte packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 239-byte packet"); + } + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + size_t size = 240; + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 240-byte packet"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 240-byte packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "240-byte packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 240-byte packet"); + } + + /* Тест 3: максимальный размер без фрагментации (3839) */ + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + size_t size = 3839; + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 3839-byte packet"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 3839-byte packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "3839-byte packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 3839-byte packet"); + } + + /* Тест 4: размер, требующий фрагментации (3840) с обычным max_fragment_size */ + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + size_t size = 3840; + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 3840-byte packet"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put 3840-byte packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "3840-byte packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for 3840-byte packet"); + } + + /* Тест 5: размер чуть меньше max_fragment_size, чтобы не фрагментироваться */ + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + settings.max_fragment_size = 500; + size_t size = 480; /* достаточно мало, чтобы поместиться с заголовком */ + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 480-byte packet with fragment size 500"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "packet comparison with fragment size 500"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors"); + } + + /* Тест 6: размер чуть больше max_fragment_size, чтобы вызвать фрагментацию */ + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + settings.max_fragment_size = 500; + size_t size = 520; /* потребует фрагментации */ + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 520-byte packet with fragment size 500"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "packet comparison with fragmentation"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors"); + } + + /* Тест 7: максимальный размер пакета с фрагментацией (65535) - ограничим 10000 для скорости */ + { + reset_test_data(); + pkt_normalizer_reset_error_count(pair->unpacker); + settings.max_fragment_size = 1000; + size_t size = 10000; + ll_entry_t* entry = create_test_packet(size); + TEST_ASSERT(entry != NULL, "create 10000-byte fragmented packet"); + add_sent_packet(ll_entry_data(entry), size); + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put large fragmented packet"); + process_queues(pair); + TEST_ASSERT(compare_packets() == 0, "large fragmented packet comparison"); + TEST_ASSERT(pkt_normalizer_get_error_count(pair->unpacker) == 0, "no errors for large fragmented packet"); + } + + settings.max_fragment_size = original_fragment_size; + return 0; +} + +/* Тест 5: проверка жизненного цикла */ +static int test_lifecycle(void) { + printf("\n--- Test 5: lifecycle ---\n"); + + pkt_normalizer_pair* pair = pkt_normalizer_pair_init(); + TEST_ASSERT(pair != NULL, "pair initialization"); + TEST_ASSERT(pair->packer != NULL, "packer initialization"); + TEST_ASSERT(pair->unpacker != NULL, "unpacker initialization"); + + /* Создать тестовые очереди */ + ll_queue_t* test_queue = queue_new(); + TEST_ASSERT(test_queue != NULL, "test queue creation"); + + /* Отправить один пакет */ + const char* test_data = "test"; + ll_entry_t* entry = queue_entry_new(strlen(test_data)); + TEST_ASSERT(entry != NULL, "create test packet"); + memcpy(ll_entry_data(entry), test_data, strlen(test_data)); + + TEST_ASSERT(queue_entry_put(pair->packer->input, entry) == 0, "put test packet"); + + /* Освободить всё */ + pkt_normalizer_pair_deinit(pair); + queue_free(test_queue); + + return 0; +} + +int main(void) { + int result = 0; + + printf("=== Packet Normalizer Unit Test ===\n"); + + srand((unsigned int)time(NULL)); + uasync_init(); + + pkt_normalizer_pair* pair = pkt_normalizer_pair_init(); + if (!pair) { + fprintf(stderr, "Failed to initialize packet normalizer pair\n"); + return 1; + } + + /* Настроить цепочку обработки: packer->output -> unpacker->input -> unpacker->output */ + queue_set_callback(pair->packer->output, forward_cb, pair->unpacker->input); + queue_set_callback(pair->unpacker->output, receive_cb, NULL); + + result |= test_lifecycle(); + result |= test_small_packets(pair); + result |= test_medium_packet(pair); + result |= test_fragmentation(pair); + result |= test_mixed_packets(pair); + result |= test_stress_random(pair); + result |= test_edge_cases(pair); + + pkt_normalizer_pair_deinit(pair); + reset_test_data(); + + if (result == 0) { + printf("\n=== All tests PASSED ===\n"); + } else { + printf("\n=== Some tests FAILED ===\n"); + } + + return result; +} \ No newline at end of file diff --git a/tests/test_sc_lib.c b/tests/test_sc_lib.c new file mode 100644 index 00000000..da531ab3 --- /dev/null +++ b/tests/test_sc_lib.c @@ -0,0 +1,172 @@ +/* test_sc_lib.c - Test for Secure Channel library */ + +#include "sc_lib.h" +#include +#include +#include +#include +#include + +#define TEST_ASSERT(cond, msg) \ + do { \ + if (!(cond)) { \ + printf("FAIL: %s (line %d)\n", msg, __LINE__); \ + return 1; \ + } else { \ + printf("PASS: %s\n", msg); \ + } \ + } while(0) + +static int test_key_generation(void) +{ + sc_context_t ctx; + sc_status_t status; + + memset(&ctx, 0, sizeof(ctx)); + + status = sc_generate_keypair(&ctx); + TEST_ASSERT(status == SC_OK, "sc_generate_keypair"); + TEST_ASSERT(ctx.initialized == 1, "ctx.initialized set"); + TEST_ASSERT(ctx.peer_key_set == 0, "peer_key_set initially 0"); + TEST_ASSERT(ctx.session_ready == 0, "session_ready initially 0"); + + return 0; +} + +static int test_key_exchange(void) +{ + sc_context_t client_ctx, server_ctx; + sc_status_t status; + + memset(&client_ctx, 0, sizeof(client_ctx)); + memset(&server_ctx, 0, sizeof(server_ctx)); + + /* Generate key pairs */ + status = sc_generate_keypair(&client_ctx); + TEST_ASSERT(status == SC_OK, "client key generation"); + + status = sc_generate_keypair(&server_ctx); + TEST_ASSERT(status == SC_OK, "server key generation"); + + /* Exchange public keys */ + status = sc_set_peer_public_key(&client_ctx, server_ctx.public_key); + TEST_ASSERT(status == SC_OK, "client set peer key"); + TEST_ASSERT(client_ctx.peer_key_set == 1, "client peer_key_set"); + TEST_ASSERT(client_ctx.session_ready == 1, "client session_ready"); + + status = sc_set_peer_public_key(&server_ctx, client_ctx.public_key); + TEST_ASSERT(status == SC_OK, "server set peer key"); + TEST_ASSERT(server_ctx.peer_key_set == 1, "server peer_key_set"); + TEST_ASSERT(server_ctx.session_ready == 1, "server session_ready"); + + /* Session keys should be identical */ + TEST_ASSERT(memcmp(client_ctx.session_key, server_ctx.session_key, + SC_SESSION_KEY_SIZE) == 0, + "session keys match"); + + return 0; +} + +static int test_encrypt_decrypt(void) +{ + sc_context_t client_ctx, server_ctx; + sc_status_t status; + const char *plaintext = "Hello, secure channel!"; + size_t plaintext_len = strlen(plaintext) + 1; + uint8_t ciphertext[256]; + uint8_t tag[SC_TAG_SIZE]; + uint8_t decrypted[256]; + + memset(&client_ctx, 0, sizeof(client_ctx)); + memset(&server_ctx, 0, sizeof(server_ctx)); + + /* Setup secure channel */ + status = sc_generate_keypair(&client_ctx); + TEST_ASSERT(status == SC_OK, "client key generation"); + + status = sc_generate_keypair(&server_ctx); + TEST_ASSERT(status == SC_OK, "server key generation"); + + status = sc_set_peer_public_key(&client_ctx, server_ctx.public_key); + TEST_ASSERT(status == SC_OK, "client set peer key"); + + status = sc_set_peer_public_key(&server_ctx, client_ctx.public_key); + TEST_ASSERT(status == SC_OK, "server set peer key"); + + /* Client encrypts */ + status = sc_encrypt(&client_ctx, (const uint8_t *)plaintext, plaintext_len, + ciphertext, tag); + TEST_ASSERT(status == SC_OK, "encryption"); + + /* Server decrypts */ + status = sc_decrypt(&server_ctx, ciphertext, plaintext_len, tag, decrypted); + TEST_ASSERT(status == SC_OK, "decryption"); + + /* Verify decrypted matches original */ + TEST_ASSERT(memcmp(plaintext, decrypted, plaintext_len) == 0, + "decrypted matches original"); + + /* Verify tag verification fails with wrong tag */ + uint8_t wrong_tag[SC_TAG_SIZE]; + memset(wrong_tag, 0xAA, sizeof(wrong_tag)); + status = sc_decrypt(&server_ctx, ciphertext, plaintext_len, wrong_tag, decrypted); + TEST_ASSERT(status == SC_ERR_AUTH_FAILED, "wrong tag detection"); + + /* Verify counter increment */ + TEST_ASSERT(client_ctx.tx_counter == 1, "client tx_counter incremented"); + TEST_ASSERT(server_ctx.rx_counter == 1, "server rx_counter incremented"); + + return 0; +} + +static int test_error_handling(void) +{ + sc_context_t ctx; + uint8_t buffer[32]; + uint8_t tag[SC_TAG_SIZE]; + sc_status_t status; + + memset(&ctx, 0, sizeof(ctx)); + + /* Test NULL context */ + status = sc_generate_keypair(NULL); + TEST_ASSERT(status == SC_ERR_INVALID_ARG, "NULL context detection"); + + /* Test uninitialized context */ + memset(&ctx, 0, sizeof(ctx)); + status = sc_set_peer_public_key(&ctx, buffer); + TEST_ASSERT(status == SC_ERR_NOT_INITIALIZED, "uninitialized context"); + + /* Test encryption without session */ + memset(&ctx, 0, sizeof(ctx)); + status = sc_generate_keypair(&ctx); + TEST_ASSERT(status == SC_OK, "key generation for error test"); + + status = sc_encrypt(&ctx, buffer, sizeof(buffer), buffer, tag); + TEST_ASSERT(status == SC_ERR_NOT_INITIALIZED, "encrypt without session"); + + return 0; +} + +int main(void) +{ + int result = 0; + + printf("=== Secure Channel Library Test ===\n"); + + /* Initialize TinyCrypt RNG */ + uECC_set_rng(&default_CSPRNG); + + result |= test_key_generation(); + result |= test_key_exchange(); + result |= test_encrypt_decrypt(); + result |= test_error_handling(); + + if (result == 0) { + printf("\n=== All tests PASSED ===\n"); + } else { + printf("\n=== Some tests FAILED ===\n"); + } + + return result; +} \ No newline at end of file diff --git a/tests/test_udp_secure.c b/tests/test_udp_secure.c new file mode 100644 index 00000000..ac2336f3 --- /dev/null +++ b/tests/test_udp_secure.c @@ -0,0 +1,202 @@ +/* test_udp_secure.c - Unit test for UDP secure channel with async library */ + +#include "sc_lib.h" +#include "u_async.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_ASSERT(cond, msg) \ + do { \ + if (!(cond)) { \ + printf("FAIL: %s (line %d)\n", msg, __LINE__); \ + exit(1); \ + } else { \ + printf("PASS: %s\n", msg); \ + } \ + } while(0) + +#define PORT_A 12345 +#define PORT_B 12346 +#define LOCALHOST "127.0.0.1" + +typedef struct { + sc_context_t ctx; + int sockfd; + struct sockaddr_in addr; + struct sockaddr_in peer_addr; + uint8_t rx_buffer[1024]; + size_t rx_len; + uint8_t tx_buffer[1024]; + size_t tx_len; + int received; + int sent; +} client_state_t; + +static client_state_t client_a, client_b; +static volatile int test_complete = 0; +static volatile int test_failed = 0; + +static void timeout_callback(void* arg) { + (void)arg; + printf("ERROR: Test timeout\n"); + test_failed = 1; + exit(1); +} + +static void client_a_read_callback(int fd, void* arg) { + client_state_t* state = (client_state_t*)arg; + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + ssize_t n = recvfrom(fd, state->rx_buffer, sizeof(state->rx_buffer), 0, + (struct sockaddr*)&from, &fromlen); + if (n < 0) { + perror("recvfrom"); + return; + } + printf("Client A received %zd bytes\n", n); + // In this test, client A is not expecting data + // but we can handle it if needed +} + +static void client_b_read_callback(int fd, void* arg) { + client_state_t* state = (client_state_t*)arg; + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + ssize_t n = recvfrom(fd, state->rx_buffer, sizeof(state->rx_buffer), 0, + (struct sockaddr*)&from, &fromlen); + if (n < 0) { + perror("recvfrom"); + return; + } + printf("Client B received %zd bytes\n", n); + + // Expect encrypted message + tag + size_t ciphertext_len = n - SC_TAG_SIZE; + if (ciphertext_len <= 0 || ciphertext_len > sizeof(state->rx_buffer) - SC_TAG_SIZE) { + printf("ERROR: Invalid received length\n"); + test_failed = 1; + return; + } + + uint8_t* ciphertext = state->rx_buffer; + uint8_t* tag = state->rx_buffer + ciphertext_len; + uint8_t decrypted[1024]; + + sc_status_t status = sc_decrypt(&state->ctx, ciphertext, ciphertext_len, tag, decrypted); + TEST_ASSERT(status == SC_OK, "decryption of received message"); + + const char* expected = "Hello from client A over UDP!"; + TEST_ASSERT(memcmp(decrypted, expected, strlen(expected) + 1) == 0, + "decrypted matches expected plaintext"); + + printf("Client B successfully decrypted message: %s\n", (char*)decrypted); + test_complete = 1; + exit(0); +} + +static int create_udp_socket(int port, struct sockaddr_in* addr) { + int sock = socket(AF_INET, SOCK_DGRAM, 0); + TEST_ASSERT(sock >= 0, "socket creation"); + + int flags = fcntl(sock, F_GETFL, 0); + TEST_ASSERT(flags >= 0, "get socket flags"); + TEST_ASSERT(fcntl(sock, F_SETFL, flags | O_NONBLOCK) == 0, "set non-blocking"); + + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + addr->sin_addr.s_addr = inet_addr(LOCALHOST); + + TEST_ASSERT(bind(sock, (struct sockaddr*)addr, sizeof(*addr)) == 0, "bind socket"); + return sock; +} + +static void generate_keys(client_state_t* client) { + memset(&client->ctx, 0, sizeof(client->ctx)); + sc_status_t status = sc_generate_keypair(&client->ctx); + TEST_ASSERT(status == SC_OK, "key generation"); +} + +static void send_encrypted_message(client_state_t* src, client_state_t* dst) { + const char* plaintext = "Hello from client A over UDP!"; + size_t plaintext_len = strlen(plaintext) + 1; + + uint8_t ciphertext[plaintext_len]; + uint8_t tag[SC_TAG_SIZE]; + + sc_status_t status = sc_encrypt(&src->ctx, (const uint8_t*)plaintext, plaintext_len, + ciphertext, tag); + TEST_ASSERT(status == SC_OK, "encryption for sending"); + + // Combine ciphertext and tag into single packet + memcpy(src->tx_buffer, ciphertext, plaintext_len); + memcpy(src->tx_buffer + plaintext_len, tag, SC_TAG_SIZE); + size_t packet_len = plaintext_len + SC_TAG_SIZE; + + ssize_t sent = sendto(src->sockfd, src->tx_buffer, packet_len, 0, + (struct sockaddr*)&dst->addr, sizeof(dst->addr)); + TEST_ASSERT(sent == (ssize_t)packet_len, "sendto"); + printf("Client A sent encrypted message (%zd bytes)\n", sent); +} + +int main(void) { + printf("=== UDP Secure Channel Test with Async Library ===\n"); + + // Initialize TinyCrypt RNG + uECC_set_rng(&default_CSPRNG); + + // Initialize async library + uasync_init(); + + // Create UDP sockets + client_a.sockfd = create_udp_socket(PORT_A, &client_a.addr); + client_b.sockfd = create_udp_socket(PORT_B, &client_b.addr); + + // Set peer addresses for sending + client_a.peer_addr = client_b.addr; + client_b.peer_addr = client_a.addr; + + // Generate key pairs for both clients + generate_keys(&client_a); + generate_keys(&client_b); + + // Exchange public keys + sc_status_t status = sc_set_peer_public_key(&client_a.ctx, client_b.ctx.public_key); + TEST_ASSERT(status == SC_OK, "client A set peer key"); + status = sc_set_peer_public_key(&client_b.ctx, client_a.ctx.public_key); + TEST_ASSERT(status == SC_OK, "client B set peer key"); + + // Verify session keys match + TEST_ASSERT(memcmp(client_a.ctx.session_key, client_b.ctx.session_key, + SC_SESSION_KEY_SIZE) == 0, + "session keys match"); + + // Register sockets with async library + uasync_add_socket(client_a.sockfd, client_a_read_callback, NULL, NULL, &client_a); + uasync_add_socket(client_b.sockfd, client_b_read_callback, NULL, NULL, &client_b); + + // Set timeout for test completion (2 seconds) + uasync_set_timeout(20000, NULL, timeout_callback); // timebase 0.1 ms, 20000 = 2 sec + + // Send encrypted message from A to B + send_encrypted_message(&client_a, &client_b); + + // Run async mainloop (will exit via callback or timeout) + printf("Starting async mainloop...\n"); + uasync_mainloop(); // This will not return + + // Should not reach here + return 1; +} \ No newline at end of file diff --git a/tinycrypt/.gitignore b/tinycrypt/.gitignore new file mode 100644 index 00000000..c960ccc7 --- /dev/null +++ b/tinycrypt/.gitignore @@ -0,0 +1,5 @@ +*.o +*~ +*.d +*.exe +*.a diff --git a/tinycrypt/AUTHORS b/tinycrypt/AUTHORS new file mode 100644 index 00000000..e6fe14d5 --- /dev/null +++ b/tinycrypt/AUTHORS @@ -0,0 +1,14 @@ +Architect: +Rafael Misoczki + +Open Source Maintainer: +Rafael Misoczki + +Contributors: +Rafael Misoczki +Constanza Heath +Flavio Santes +Jarkko Sakkinen +Chris Morrison +Marti Bolivar +Colin Ian King diff --git a/tinycrypt/LICENSE b/tinycrypt/LICENSE new file mode 100644 index 00000000..2e1db516 --- /dev/null +++ b/tinycrypt/LICENSE @@ -0,0 +1,61 @@ + +================================================================================ + + TinyCrypt Cryptographic Library + +================================================================================ + + Copyright (c) 2017, Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + - 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. + + - Neither the name of the Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +================================================================================ +Copyright (c) 2014, Kenneth MacKay +All rights reserved. + +https://github.com/kmackay/micro-ecc + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +================================================================================ diff --git a/tinycrypt/Makefile b/tinycrypt/Makefile new file mode 100644 index 00000000..3c0e42b9 --- /dev/null +++ b/tinycrypt/Makefile @@ -0,0 +1,21 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Global Makefile. +# See lib/Makefile and tests/Makefile for further configuration. +# +################################################################################ +include config.mk + +all: + $(MAKE) -C lib +ifeq ($(ENABLE_TESTS),true) + $(MAKE) -C tests +endif + +clean: + $(MAKE) -C lib clean + $(MAKE) -C tests clean + $(RM) *~ + diff --git a/tinycrypt/README b/tinycrypt/README new file mode 100644 index 00000000..d697178c --- /dev/null +++ b/tinycrypt/README @@ -0,0 +1,76 @@ +# This project will no longer be maintained by Intel. # +Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project. +Intel no longer accepts patches to this project. +If you have an ongoing need to use this project, are interested in independently developing it, or would like to maintain patches for the open source software community, please create your own fork of this project. + + +================================================================================ + + TinyCrypt Cryptographic Library + +================================================================================ + + Copyright (c) 2017, Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + - 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. + + - Neither the name of the Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +================================================================================ + +Overview: + +The TinyCrypt Library provides an implementation for constrained devices of a +minimal set of standard cryptography primitives. + +Please, ***SEE THE DOCUMENTATION*** folder for more information on the supported +cryptographic primitives and the limitations of TinyCrypt library. For usage, +security and technicalities, please see the corresponding header file of each +cryptographic primitive. + +================================================================================ + +Organization: + +/lib: C source code of the cryptographic primitives. +/lib/include/tinycrypt: C header files of the cryptographic primitives. +/tests: Test vectors of the cryptographic primitives. +/doc: Documentation of TinyCrypt. + +================================================================================ + +Building: + +1) In Makefile.conf set: + - CFLAGS for compiler flags. + - CC for compiler. + - ENABLE_TESTS for enabling (true) or disabling (false) tests compilation. +2) In lib/Makefile select the primitives required by your project. +3) In tests/Makefile select the corresponding tests of the selected primitives. +4) make +5) run tests in tests/ + +================================================================================ + diff --git a/tinycrypt/VERSION b/tinycrypt/VERSION new file mode 100644 index 00000000..a45be462 --- /dev/null +++ b/tinycrypt/VERSION @@ -0,0 +1 @@ +0.2.8 diff --git a/tinycrypt/config.mk b/tinycrypt/config.mk new file mode 100644 index 00000000..a5b9fb77 --- /dev/null +++ b/tinycrypt/config.mk @@ -0,0 +1,35 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Global configuration Makefile. Included everywhere. +# +################################################################################ + +# EDIT HERE: +CC:=gcc +CFLAGS:=-Os -std=c99 -Wall -Wextra -D_ISOC99_SOURCE -MMD -I../lib/include/ -I../lib/source/ -I../tests/include/ +vpath %.c ../lib/source/ +ENABLE_TESTS=true + +# override MinGW built-in recipe +%.o: %.c + $(COMPILE.c) $(OUTPUT_OPTION) $< + +ifeq ($(OS),Windows_NT) +DOTEXE:=.exe +endif + +# DO NOT EDIT AFTER THIS POINT: +ifeq ($(ENABLE_TESTS), true) +CFLAGS += -DENABLE_TESTS +else +CFLAGS += -DDISABLE_TESTS +endif + +export CC +export CFLAGS +export VPATH +export ENABLE_TESTS + +################################################################################ diff --git a/tinycrypt/documentation/tinycrypt.rst b/tinycrypt/documentation/tinycrypt.rst new file mode 100644 index 00000000..356c099a --- /dev/null +++ b/tinycrypt/documentation/tinycrypt.rst @@ -0,0 +1,352 @@ + +TinyCrypt Cryptographic Library +############################### +Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + +Overview +******** +The TinyCrypt Library provides an implementation for targeting constrained devices +with a minimal set of standard cryptography primitives, as listed below. To better +serve applications targeting constrained devices, TinyCrypt implementations differ +from the standard specifications (see the Important Remarks section for some +important differences). Certain cryptographic primitives depend on other +primitives, as mentioned in the list below. + +Aside from the Important Remarks section below, valuable information on the usage, +security and technicalities of each cryptographic primitive are found in the +corresponding header file. + +* SHA-256: + + * Type of primitive: Hash function. + * Standard Specification: NIST FIPS PUB 180-4. + * Requires: -- + +* HMAC-SHA256: + + * Type of primitive: Message authentication code. + * Standard Specification: RFC 2104. + * Requires: SHA-256 + +* HMAC-PRNG: + + * Type of primitive: Pseudo-random number generator (256-bit strength). + * Standard Specification: NIST SP 800-90A. + * Requires: SHA-256 and HMAC-SHA256. + +* AES-128: + + * Type of primitive: Block cipher. + * Standard Specification: NIST FIPS PUB 197. + * Requires: -- + +* AES-CBC mode: + + * Type of primitive: Encryption mode of operation. + * Standard Specification: NIST SP 800-38A. + * Requires: AES-128. + +* AES-CTR mode: + + * Type of primitive: Encryption mode of operation. + * Standard Specification: NIST SP 800-38A. + * Requires: AES-128. + +* AES-CMAC mode: + + * Type of primitive: Message authentication code. + * Standard Specification: NIST SP 800-38B. + * Requires: AES-128. + +* AES-CCM mode: + + * Type of primitive: Authenticated encryption. + * Standard Specification: NIST SP 800-38C. + * Requires: AES-128. + +* CTR-PRNG: + + * Type of primitive: Pseudo-random number generator (128-bit strength). + * Standard Specification: NIST SP 800-90A. + * Requires: AES-128. + +* ECC-DH: + + * Type of primitive: Key exchange based on curve NIST p-256. + * Standard Specification: RFC 6090. + * Requires: ECC auxiliary functions (ecc.h/c). + +* ECC-DSA: + + * Type of primitive: Digital signature based on curve NIST p-256. + * Standard Specification: RFC 6090. + * Requires: ECC auxiliary functions (ecc.h/c). + +Design Goals +************ + +* Minimize the code size of each cryptographic primitive. This means minimize + the size of a platform-independent implementation, as presented in TinyCrypt. + Note that various applications may require further features, optimizations with + respect to other metrics and countermeasures for particular threats. These + peculiarities would increase the code size and thus are not considered here. + +* Minimize the dependencies among the cryptographic primitives. This means + that it is unnecessary to build and allocate object code for more primitives + than the ones strictly required by the intended application. In other words, + one can select and compile only the primitives required by the application. + + +Important Remarks +***************** + +The cryptographic implementations in TinyCrypt library have some limitations. +Some of these limitations are inherent to the cryptographic primitives +themselves, while others are specific to TinyCrypt. These limitations were accepted +in order to meet its design goals (in special, minimal code size) and to better +serve applications targeting constrained devices in general. Some of these +limitations are discussed in-depth below. + +General Remarks +*************** + +* TinyCrypt does **not** intend to be fully side-channel resistant. Due to the + variety of side-channel attacks, many of them only relevant to certain + platforms. In this sense, instead of penalizing all library users with + side-channel countermeasures such as increasing the overall code size, + TinyCrypt only implements certain generic timing-attack countermeasures. + +Specific Remarks +**************** + +* SHA-256: + + * The number of bits_hashed in the state is not checked for overflow. Note + however that this will only be a problem if you intend to hash more than + 2^64 bits, which is an extremely large window. + +* HMAC: + + * The HMAC verification process is assumed to be performed by the application. + This compares the computed tag with some given tag. + Note that conventional memory-comparison methods (such as memcmp function) + might be vulnerable to timing attacks; thus be sure to use a constant-time + memory comparison function (such as compare_constant_time + function provided in lib/utils.c). + + * The tc_hmac_final function, responsible for computing the message tag, + cleans the state context before exiting. Thus, applications do not need to + clean the TCHmacState_t ctx after calling tc_hmac_final. This should not + be changed in future versions of the library as there are applications + currently relying on this good-practice/feature of TinyCrypt. + +* HMAC-PRNG: + + * Before using HMAC-PRNG, you *must* find an entropy source to produce a seed. + PRNGs only stretch the seed into a seemingly random output of arbitrary + length. The security of the output is exactly equal to the + unpredictability of the seed. + + * NIST SP 800-90A requires three items as seed material in the initialization + step: entropy seed, personalization and a nonce (which is not implemented). + TinyCrypt requires the personalization byte array and automatically creates + the entropy seed using a mandatory call to the re-seed function. + +* AES-128: + + * The current implementation does not support other key-lengths (such as 256 + bits). Note that if you need AES-256, it doesn't sound as though your + application is running in a constrained environment. AES-256 requires keys + twice the size as for AES-128, and the key schedule is 40% larger. + +* CTR mode: + + * The AES-CTR mode limits the size of a data message they encrypt to 2^32 + blocks. If you need to encrypt larger data sets, your application would + need to replace the key after 2^32 block encryptions. + +* CTR-PRNG: + + * Before using CTR-PRNG, you *must* find an entropy source to produce a seed. + PRNGs only stretch the seed into a seemingly random output of arbitrary + length. The security of the output is exactly equal to the + unpredictability of the seed. + +* CBC mode: + + * TinyCrypt CBC decryption assumes that the iv and the ciphertext are + contiguous (as produced by TinyCrypt CBC encryption). This allows for a + very efficient decryption algorithm that would not otherwise be possible. + +* CMAC mode: + + * AES128-CMAC mode of operation offers 64 bits of security against collision + attacks. Note however that an external attacker cannot generate the tags + him/herself without knowing the MAC key. In this sense, to attack the + collision property of AES128-CMAC, an external attacker would need the + cooperation of the legal user to produce an exponentially high number of + tags (e.g. 2^64) to finally be able to look for collisions and benefit + from them. As an extra precaution, the current implementation allows to at + most 2^48 calls to tc_cmac_update function before re-calling tc_cmac_setup + (allowing a new key to be set), as suggested in Appendix B of SP 800-38B. + +* CCM mode: + + * There are a few tradeoffs for the selection of the parameters of CCM mode. + In special, there is a tradeoff between the maximum number of invocations + of CCM under a given key and the maximum payload length for those + invocations. Both things are related to the parameter 'q' of CCM mode. The + maximum number of invocations of CCM under a given key is determined by + the nonce size, which is: 15-q bytes. The maximum payload length for those + invocations is defined as 2^(8q) bytes. + + To achieve minimal code size, TinyCrypt CCM implementation fixes q = 2, + which is a quite reasonable choice for constrained applications. The + implications of this choice are: + + The nonce size is: 13 bytes. + + The maximum payload length is: 2^16 bytes = 65 KB. + + The mac size parameter is an important parameter to estimate the security + against collision attacks (that aim at finding different messages that + produce the same authentication tag). TinyCrypt CCM implementation + accepts any even integer between 4 and 16, as suggested in SP 800-38C. + + * TinyCrypt CCM implementation accepts associated data of any length between + 0 and (2^16 - 2^8) = 65280 bytes. + + * TinyCrypt CCM implementation accepts: + + * Both non-empty payload and associated data (it encrypts and + authenticates the payload and only authenticates the associated data); + + * Non-empty payload and empty associated data (it encrypts and + authenticates the payload); + + * Non-empty associated data and empty payload (it degenerates to an + authentication-only mode on the associated data). + + * RFC-3610, which also specifies CCM, presents a few relevant security + suggestions, such as: it is recommended for most applications to use a + mac size greater than 8. Besides, it is emphasized that the usage of the + same nonce for two different messages which are encrypted with the same + key obviously destroys the security properties of CCM mode. + +* ECC-DH and ECC-DSA: + + * TinyCrypt ECC implementation is based on micro-ecc (see + https://github.com/kmackay/micro-ecc). In the original micro-ecc + documentation, there is an important remark about the way integers are + represented: + + "Integer representation: To reduce code size, all large integers are + represented using little-endian words - so the least significant word is + first. You can use the 'ecc_bytes2native()' and 'ecc_native2bytes()' + functions to convert between the native integer representation and the + standardized octet representation." + + Note that the assumed bit layout is: {31, 30, ..., 0}, {63, 62, ..., 32}, + {95, 94, ..., 64}, {127, 126, ..., 96} for a very-long-integer (vli) + consisting of 4 unsigned integers (as an example). + + * A cryptographically-secure PRNG function must be set (using uECC_set_rng()) + before calling uECC_make_key() or uECC_sign(). + +Examples of Applications +************************ +It is possible to do useful cryptography with only the given small set of +primitives. With this list of primitives it becomes feasible to support a range +of cryptography usages: + + * Measurement of code, data structures, and other digital artifacts (SHA256); + + * Generate commitments (SHA256); + + * Construct keys (HMAC-SHA256); + + * Extract entropy from strings containing some randomness (HMAC-SHA256); + + * Construct random mappings (HMAC-SHA256); + + * Construct nonces and challenges (HMAC-PRNG, CTR-PRNG); + + * Authenticate using a shared secret (HMAC-SHA256); + + * Create an authenticated, replay-protected session (HMAC-SHA256 + HMAC-PRNG); + + * Authenticated encryption (AES-128 + AES-CCM); + + * Key-exchange (EC-DH); + + * Digital signature (EC-DSA); + +Test Vectors +************ + +The library provides a test program for each cryptographic primitive (see 'test' +folder). Besides illustrating how to use the primitives, these tests evaluate +the correctness of the implementations by checking the results against +well-known publicly validated test vectors. + +For the case of the HMAC-PRNG, due to the necessity of performing an extensive +battery test to produce meaningful conclusions, we suggest the user to evaluate +the unpredictability of the implementation by using the NIST Statistical Test +Suite (see References). + +For the case of the EC-DH and EC-DSA implementations, most of the test vectors +were obtained from the site of the NIST Cryptographic Algorithm Validation +Program (CAVP), see References. + +References +********** + +* `NIST FIPS PUB 180-4 (SHA-256)`_ + +.. _NIST FIPS PUB 180-4 (SHA-256): + http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf + +* `NIST FIPS PUB 197 (AES-128)`_ + +.. _NIST FIPS PUB 197 (AES-128): + http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + +* `NIST SP800-90A (HMAC-PRNG)`_ + +.. _NIST SP800-90A (HMAC-PRNG): + http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf + +* `NIST SP 800-38A (AES-CBC and AES-CTR)`_ + +.. _NIST SP 800-38A (AES-CBC and AES-CTR): + http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + +* `NIST SP 800-38B (AES-CMAC)`_ + +.. _NIST SP 800-38B (AES-CMAC): + http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf + +* `NIST SP 800-38C (AES-CCM)`_ + +.. _NIST SP 800-38C (AES-CCM): + http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + +* `NIST Statistical Test Suite (useful for testing HMAC-PRNG)`_ + +.. _NIST Statistical Test Suite (useful for testing HMAC-PRNG): + http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html + +* `NIST Cryptographic Algorithm Validation Program (CAVP) site`_ + +.. _NIST Cryptographic Algorithm Validation Program (CAVP) site: + http://csrc.nist.gov/groups/STM/cavp/ + +* `RFC 2104 (HMAC-SHA256)`_ + +.. _RFC 2104 (HMAC-SHA256): + https://www.ietf.org/rfc/rfc2104.txt + +* `RFC 6090 (ECC-DH and ECC-DSA)`_ + +.. _RFC 6090 (ECC-DH and ECC-DSA): + https://www.ietf.org/rfc/rfc6090.txt diff --git a/tinycrypt/lib/Makefile b/tinycrypt/lib/Makefile new file mode 100644 index 00000000..9c4d8e27 --- /dev/null +++ b/tinycrypt/lib/Makefile @@ -0,0 +1,39 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Cryptographic Primitives Makefile. +# +################################################################################ + +include ../config.mk + +# Edit the OBJS content to add/remove primitives needed from TinyCrypt library: +OBJS:=aes_decrypt.o \ + aes_encrypt.o \ + cbc_mode.o \ + ctr_mode.o \ + ctr_prng.o \ + hmac.o \ + hmac_prng.o \ + sha256.o \ + ecc.o \ + ecc_dh.o \ + ecc_dsa.o \ + ccm_mode.o \ + cmac_mode.o \ + utils.o + +DEPS:=$(OBJS:.o=.d) + +all: libtinycrypt.a + +libtinycrypt.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $^ + +.PHONY: clean + +clean: + -$(RM) *.exe $(OBJS) $(DEPS) *~ libtinycrypt.a + +-include $(DEPS) diff --git a/tinycrypt/lib/include/tinycrypt/aes.h b/tinycrypt/lib/include/tinycrypt/aes.h new file mode 100644 index 00000000..b612213a --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/aes.h @@ -0,0 +1,130 @@ +/* aes.h - TinyCrypt interface to an AES-128 implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief -- Interface to an AES-128 implementation. + * + * Overview: AES-128 is a NIST approved block cipher specified in + * FIPS 197. Block ciphers are deterministic algorithms that + * perform a transformation specified by a symmetric key in fixed- + * length data sets, also called blocks. + * + * Security: AES-128 provides approximately 128 bits of security. + * + * Usage: 1) call tc_aes128_set_encrypt/decrypt_key to set the key. + * + * 2) call tc_aes_encrypt/decrypt to process the data. + */ + +#ifndef __TC_AES_H__ +#define __TC_AES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define Nb (4) /* number of columns (32-bit words) comprising the state */ +#define Nk (4) /* number of 32-bit words comprising the key */ +#define Nr (10) /* number of rounds */ +#define TC_AES_BLOCK_SIZE (Nb*Nk) +#define TC_AES_KEY_SIZE (Nb*Nk) + +typedef struct tc_aes_key_sched_struct { + unsigned int words[Nb*(Nr+1)]; +} *TCAesKeySched_t; + +/** + * @brief Set AES-128 encryption key + * Uses key k to initialize s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL + * @note This implementation skips the additional steps required for keys + * larger than 128 bits, and must not be used for AES-192 or + * AES-256 key schedule -- see FIPS 197 for details + * @param s IN/OUT -- initialized struct tc_aes_key_sched_struct + * @param k IN -- points to the AES key + */ +int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k); + +/** + * @brief AES-128 Encryption procedure + * Encrypts contents of in buffer into out buffer under key; + * schedule s + * @note Assumes s was initialized by aes_set_encrypt_key; + * out and in point to 16 byte buffers + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL + * @param out IN/OUT -- buffer to receive ciphertext block + * @param in IN -- a plaintext block to encrypt + * @param s IN -- initialized AES key schedule + */ +int tc_aes_encrypt(uint8_t *out, const uint8_t *in, + const TCAesKeySched_t s); + +/** + * @brief Set the AES-128 decryption key + * Uses key k to initialize s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL + * @note This is the implementation of the straightforward inverse cipher + * using the cipher documented in FIPS-197 figure 12, not the + * equivalent inverse cipher presented in Figure 15 + * @warning This routine skips the additional steps required for keys larger + * than 128, and must not be used for AES-192 or AES-256 key + * schedule -- see FIPS 197 for details + * @param s IN/OUT -- initialized struct tc_aes_key_sched_struct + * @param k IN -- points to the AES key + */ +int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k); + +/** + * @brief AES-128 Encryption procedure + * Decrypts in buffer into out buffer under key schedule s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL + * @note Assumes s was initialized by aes_set_encrypt_key + * out and in point to 16 byte buffers + * @param out IN/OUT -- buffer to receive ciphertext block + * @param in IN -- a plaintext block to encrypt + * @param s IN -- initialized AES key schedule + */ +int tc_aes_decrypt(uint8_t *out, const uint8_t *in, + const TCAesKeySched_t s); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_AES_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/cbc_mode.h b/tinycrypt/lib/include/tinycrypt/cbc_mode.h new file mode 100644 index 00000000..4a837fd0 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/cbc_mode.h @@ -0,0 +1,151 @@ +/* cbc_mode.h - TinyCrypt interface to a CBC mode implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to a CBC mode implementation. + * + * Overview: CBC (for "cipher block chaining") mode is a NIST approved mode of + * operation defined in SP 800-38a. It can be used with any block + * cipher to provide confidentiality of strings whose lengths are + * multiples of the block_size of the underlying block cipher. + * TinyCrypt hard codes AES as the block cipher. + * + * Security: CBC mode provides data confidentiality given that the maximum + * number q of blocks encrypted under a single key satisfies + * q < 2^63, which is not a practical constraint (it is considered a + * good practice to replace the encryption when q == 2^56). CBC mode + * provides NO data integrity. + * + * CBC mode assumes that the IV value input into the + * tc_cbc_mode_encrypt is randomly generated. The TinyCrypt library + * provides HMAC-PRNG module, which generates suitable IVs. Other + * methods for generating IVs are acceptable, provided that the + * values of the IVs generated appear random to any adversary, + * including someone with complete knowledge of the system design. + * + * The randomness property on which CBC mode's security depends is + * the unpredictability of the IV. Since it is unpredictable, this + * means in practice that CBC mode requires that the IV is stored + * somehow with the ciphertext in order to recover the plaintext. + * + * TinyCrypt CBC encryption prepends the IV to the ciphertext, + * because this affords a more efficient (few buffers) decryption. + * Hence tc_cbc_mode_encrypt assumes the ciphertext buffer is always + * 16 bytes larger than the plaintext buffer. + * + * Requires: AES-128 + * + * Usage: 1) call tc_cbc_mode_encrypt to encrypt data. + * + * 2) call tc_cbc_mode_decrypt to decrypt data. + * + */ + +#ifndef __TC_CBC_MODE_H__ +#define __TC_CBC_MODE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CBC encryption procedure + * CBC encrypts inlen bytes of the in buffer into the out buffer + * using the encryption key schedule provided, prepends iv to out + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * out == NULL or + * in == NULL or + * ctr == NULL or + * sched == NULL or + * inlen == 0 or + * (inlen % TC_AES_BLOCK_SIZE) != 0 or + * (outlen % TC_AES_BLOCK_SIZE) != 0 or + * outlen != inlen + TC_AES_BLOCK_SIZE + * @note Assumes: - sched has been configured by aes_set_encrypt_key + * - iv contains a 16 byte random string + * - out buffer is large enough to hold the ciphertext + iv + * - out buffer is a contiguous buffer + * - in holds the plaintext and is a contiguous buffer + * - inlen gives the number of bytes in the in buffer + * @param out IN/OUT -- buffer to receive the ciphertext + * @param outlen IN -- length of ciphertext buffer in bytes + * @param in IN -- plaintext to encrypt + * @param inlen IN -- length of plaintext buffer in bytes + * @param iv IN -- the IV for the this encrypt/decrypt + * @param sched IN -- AES key schedule for this encrypt + */ +int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, const uint8_t *iv, + const TCAesKeySched_t sched); + +/** + * @brief CBC decryption procedure + * CBC decrypts inlen bytes of the in buffer into the out buffer + * using the provided encryption key schedule + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * out == NULL or + * in == NULL or + * sched == NULL or + * inlen == 0 or + * outlen == 0 or + * (inlen % TC_AES_BLOCK_SIZE) != 0 or + * (outlen % TC_AES_BLOCK_SIZE) != 0 or + * outlen != inlen + TC_AES_BLOCK_SIZE + * @note Assumes:- in == iv + ciphertext, i.e. the iv and the ciphertext are + * contiguous. This allows for a very efficient decryption + * algorithm that would not otherwise be possible + * - sched was configured by aes_set_decrypt_key + * - out buffer is large enough to hold the decrypted plaintext + * and is a contiguous buffer + * - inlen gives the number of bytes in the in buffer + * @param out IN/OUT -- buffer to receive decrypted data + * @param outlen IN -- length of plaintext buffer in bytes + * @param in IN -- ciphertext to decrypt, including IV + * @param inlen IN -- length of ciphertext buffer in bytes + * @param iv IN -- the IV for the this encrypt/decrypt + * @param sched IN -- AES key schedule for this decrypt + * + */ +int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, const uint8_t *iv, + const TCAesKeySched_t sched); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_CBC_MODE_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ccm_mode.h b/tinycrypt/lib/include/tinycrypt/ccm_mode.h new file mode 100644 index 00000000..69c798e2 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ccm_mode.h @@ -0,0 +1,211 @@ +/* ccm_mode.h - TinyCrypt interface to a CCM mode implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to a CCM mode implementation. + * + * Overview: CCM (for "Counter with CBC-MAC") mode is a NIST approved mode of + * operation defined in SP 800-38C. + * + * TinyCrypt CCM implementation accepts: + * + * 1) Both non-empty payload and associated data (it encrypts and + * authenticates the payload and also authenticates the associated + * data); + * 2) Non-empty payload and empty associated data (it encrypts and + * authenticates the payload); + * 3) Non-empty associated data and empty payload (it degenerates to + * an authentication mode on the associated data). + * + * TinyCrypt CCM implementation accepts associated data of any length + * between 0 and (2^16 - 2^8) bytes. + * + * Security: The mac length parameter is an important parameter to estimate the + * security against collision attacks (that aim at finding different + * messages that produce the same authentication tag). TinyCrypt CCM + * implementation accepts any even integer between 4 and 16, as + * suggested in SP 800-38C. + * + * RFC-3610, which also specifies CCM, presents a few relevant + * security suggestions, such as: it is recommended for most + * applications to use a mac length greater than 8. Besides, the + * usage of the same nonce for two different messages which are + * encrypted with the same key destroys the security of CCM mode. + * + * Requires: AES-128 + * + * Usage: 1) call tc_ccm_config to configure. + * + * 2) call tc_ccm_mode_encrypt to encrypt data and generate tag. + * + * 3) call tc_ccm_mode_decrypt to decrypt data and verify tag. + */ + +#ifndef __TC_CCM_MODE_H__ +#define __TC_CCM_MODE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* max additional authenticated size in bytes: 2^16 - 2^8 = 65280 */ +#define TC_CCM_AAD_MAX_BYTES 0xff00 + +/* max message size in bytes: 2^(8L) = 2^16 = 65536 */ +#define TC_CCM_PAYLOAD_MAX_BYTES 0x10000 + +/* struct tc_ccm_mode_struct represents the state of a CCM computation */ +typedef struct tc_ccm_mode_struct { + TCAesKeySched_t sched; /* AES key schedule */ + uint8_t *nonce; /* nonce required by CCM */ + unsigned int mlen; /* mac length in bytes (parameter t in SP-800 38C) */ +} *TCCcmMode_t; + +/** + * @brief CCM configuration procedure + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * c == NULL or + * sched == NULL or + * nonce == NULL or + * mlen != {4, 6, 8, 10, 12, 16} + * @param c -- CCM state + * @param sched IN -- AES key schedule + * @param nonce IN - nonce + * @param nlen -- nonce length in bytes + * @param mlen -- mac length in bytes (parameter t in SP-800 38C) + */ +int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce, + unsigned int nlen, unsigned int mlen); + +/** + * @brief CCM tag generation and encryption procedure + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * out == NULL or + * c == NULL or + * ((plen > 0) and (payload == NULL)) or + * ((alen > 0) and (associated_data == NULL)) or + * (alen >= TC_CCM_AAD_MAX_BYTES) or + * (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or + * (olen < plen + maclength) + * + * @param out OUT -- encrypted data + * @param olen IN -- output length in bytes + * @param associated_data IN -- associated data + * @param alen IN -- associated data length in bytes + * @param payload IN -- payload + * @param plen IN -- payload length in bytes + * @param c IN -- CCM state + * + * @note: out buffer should be at least (plen + c->mlen) bytes long. + * + * @note: The sequence b for encryption is formatted as follows: + * b = [FLAGS | nonce | counter ], where: + * FLAGS is 1 byte long + * nonce is 13 bytes long + * counter is 2 bytes long + * The byte FLAGS is composed by the following 8 bits: + * 0-2 bits: used to represent the value of q-1 + * 3-7 btis: always 0's + * + * @note: The sequence b for authentication is formatted as follows: + * b = [FLAGS | nonce | length(mac length)], where: + * FLAGS is 1 byte long + * nonce is 13 bytes long + * length(mac length) is 2 bytes long + * The byte FLAGS is composed by the following 8 bits: + * 0-2 bits: used to represent the value of q-1 + * 3-5 bits: mac length (encoded as: (mlen-2)/2) + * 6: Adata (0 if alen == 0, and 1 otherwise) + * 7: always 0 + */ +int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen, + const uint8_t *associated_data, + unsigned int alen, const uint8_t *payload, + unsigned int plen, TCCcmMode_t c); + +/** + * @brief CCM decryption and tag verification procedure + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * out == NULL or + * c == NULL or + * ((plen > 0) and (payload == NULL)) or + * ((alen > 0) and (associated_data == NULL)) or + * (alen >= TC_CCM_AAD_MAX_BYTES) or + * (plen >= TC_CCM_PAYLOAD_MAX_BYTES) or + * (olen < plen - c->mlen) + * + * @param out OUT -- decrypted data + * @param associated_data IN -- associated data + * @param alen IN -- associated data length in bytes + * @param payload IN -- payload + * @param plen IN -- payload length in bytes + * @param c IN -- CCM state + * + * @note: out buffer should be at least (plen - c->mlen) bytes long. + * + * @note: The sequence b for encryption is formatted as follows: + * b = [FLAGS | nonce | counter ], where: + * FLAGS is 1 byte long + * nonce is 13 bytes long + * counter is 2 bytes long + * The byte FLAGS is composed by the following 8 bits: + * 0-2 bits: used to represent the value of q-1 + * 3-7 btis: always 0's + * + * @note: The sequence b for authentication is formatted as follows: + * b = [FLAGS | nonce | length(mac length)], where: + * FLAGS is 1 byte long + * nonce is 13 bytes long + * length(mac length) is 2 bytes long + * The byte FLAGS is composed by the following 8 bits: + * 0-2 bits: used to represent the value of q-1 + * 3-5 bits: mac length (encoded as: (mlen-2)/2) + * 6: Adata (0 if alen == 0, and 1 otherwise) + * 7: always 0 + */ +int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen, + const uint8_t *associated_data, + unsigned int alen, const uint8_t *payload, unsigned int plen, + TCCcmMode_t c); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_CCM_MODE_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/cmac_mode.h b/tinycrypt/lib/include/tinycrypt/cmac_mode.h new file mode 100644 index 00000000..f44b0a53 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/cmac_mode.h @@ -0,0 +1,194 @@ +/* cmac_mode.h -- interface to a CMAC implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to a CMAC implementation. + * + * Overview: CMAC is defined NIST in SP 800-38B, and is the standard algorithm + * for computing a MAC using a block cipher. It can compute the MAC + * for a byte string of any length. It is distinguished from CBC-MAC + * in the processing of the final message block; CMAC uses a + * different technique to compute the final message block is full + * size or only partial, while CBC-MAC uses the same technique for + * both. This difference permits CMAC to be applied to variable + * length messages, while all messages authenticated by CBC-MAC must + * be the same length. + * + * Security: AES128-CMAC mode of operation offers 64 bits of security against + * collision attacks. Note however that an external attacker cannot + * generate the tags him/herself without knowing the MAC key. In this + * sense, to attack the collision property of AES128-CMAC, an + * external attacker would need the cooperation of the legal user to + * produce an exponentially high number of tags (e.g. 2^64) to + * finally be able to look for collisions and benefit from them. As + * an extra precaution, the current implementation allows to at most + * 2^48 calls to the tc_cmac_update function before re-calling + * tc_cmac_setup (allowing a new key to be set), as suggested in + * Appendix B of SP 800-38B. + * + * Requires: AES-128 + * + * Usage: This implementation provides a "scatter-gather" interface, so that + * the CMAC value can be computed incrementally over a message + * scattered in different segments throughout memory. Experience shows + * this style of interface tends to minimize the burden of programming + * correctly. Like all symmetric key operations, it is session + * oriented. + * + * To begin a CMAC session, use tc_cmac_setup to initialize a struct + * tc_cmac_struct with encryption key and buffer. Our implementation + * always assume that the AES key to be the same size as the block + * cipher block size. Once setup, this data structure can be used for + * many CMAC computations. + * + * Once the state has been setup with a key, computing the CMAC of + * some data requires three steps: + * + * (1) first use tc_cmac_init to initialize a new CMAC computation. + * (2) next mix all of the data into the CMAC computation state using + * tc_cmac_update. If all of the data resides in a single data + * segment then only one tc_cmac_update call is needed; if data + * is scattered throughout memory in n data segments, then n calls + * will be needed. CMAC IS ORDER SENSITIVE, to be able to detect + * attacks that swap bytes, so the order in which data is mixed + * into the state is critical! + * (3) Once all of the data for a message has been mixed, use + * tc_cmac_final to compute the CMAC tag value. + * + * Steps (1)-(3) can be repeated as many times as you want to CMAC + * multiple messages. A practical limit is 2^48 1K messages before you + * have to change the key. + * + * Once you are done computing CMAC with a key, it is a good idea to + * destroy the state so an attacker cannot recover the key; use + * tc_cmac_erase to accomplish this. + */ + +#ifndef __TC_CMAC_MODE_H__ +#define __TC_CMAC_MODE_H__ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* padding for last message block */ +#define TC_CMAC_PADDING 0x80 + +/* struct tc_cmac_struct represents the state of a CMAC computation */ +typedef struct tc_cmac_struct { +/* initialization vector */ + uint8_t iv[TC_AES_BLOCK_SIZE]; +/* used if message length is a multiple of block_size bytes */ + uint8_t K1[TC_AES_BLOCK_SIZE]; +/* used if message length isn't a multiple block_size bytes */ + uint8_t K2[TC_AES_BLOCK_SIZE]; +/* where to put bytes that didn't fill a block */ + uint8_t leftover[TC_AES_BLOCK_SIZE]; +/* identifies the encryption key */ + unsigned int keyid; +/* next available leftover location */ + unsigned int leftover_offset; +/* AES key schedule */ + TCAesKeySched_t sched; +/* calls to tc_cmac_update left before re-key */ + uint64_t countdown; +} *TCCmacState_t; + +/** + * @brief Configures the CMAC state to use the given AES key + * @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state + * returns TC_CRYPTO_FAIL (0) if: + * s == NULL or + * key == NULL + * + * @param s IN/OUT -- the state to set up + * @param key IN -- the key to use + * @param sched IN -- AES key schedule + */ +int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, + TCAesKeySched_t sched); + +/** + * @brief Erases the CMAC state + * @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state + * returns TC_CRYPTO_FAIL (0) if: + * s == NULL + * + * @param s IN/OUT -- the state to erase + */ +int tc_cmac_erase(TCCmacState_t s); + +/** + * @brief Initializes a new CMAC computation + * @return returns TC_CRYPTO_SUCCESS (1) after having initialized the CMAC state + * returns TC_CRYPTO_FAIL (0) if: + * s == NULL + * + * @param s IN/OUT -- the state to initialize + */ +int tc_cmac_init(TCCmacState_t s); + +/** + * @brief Incrementally computes CMAC over the next data segment + * @return returns TC_CRYPTO_SUCCESS (1) after successfully updating the CMAC state + * returns TC_CRYPTO_FAIL (0) if: + * s == NULL or + * if data == NULL when dlen > 0 + * + * @param s IN/OUT -- the CMAC state + * @param data IN -- the next data segment to MAC + * @param dlen IN -- the length of data in bytes + */ +int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t dlen); + +/** + * @brief Generates the tag from the CMAC state + * @return returns TC_CRYPTO_SUCCESS (1) after successfully generating the tag + * returns TC_CRYPTO_FAIL (0) if: + * tag == NULL or + * s == NULL + * + * @param tag OUT -- the CMAC tag + * @param s IN -- CMAC state + */ +int tc_cmac_final(uint8_t *tag, TCCmacState_t s); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_CMAC_MODE_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/constants.h b/tinycrypt/lib/include/tinycrypt/constants.h new file mode 100644 index 00000000..965490e0 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/constants.h @@ -0,0 +1,61 @@ +/* constants.h - TinyCrypt interface to constants */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief -- Interface to constants. + * + */ + +#ifndef __TC_CONSTANTS_H__ +#define __TC_CONSTANTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TC_CRYPTO_SUCCESS 1 +#define TC_CRYPTO_FAIL 0 + +#define TC_ZERO_BYTE 0x00 + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_CONSTANTS_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ctr_mode.h b/tinycrypt/lib/include/tinycrypt/ctr_mode.h new file mode 100644 index 00000000..dc221f9e --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ctr_mode.h @@ -0,0 +1,108 @@ +/* ctr_mode.h - TinyCrypt interface to CTR mode */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to CTR mode. + * + * Overview: CTR (pronounced "counter") mode is a NIST approved mode of + * operation defined in SP 800-38a. It can be used with any + * block cipher to provide confidentiality of strings of any + * length. TinyCrypt hard codes AES128 as the block cipher. + * + * Security: CTR mode achieves confidentiality only if the counter value is + * never reused with a same encryption key. If the counter is + * repeated, than an adversary might be able to defeat the scheme. + * + * A usual method to ensure different counter values refers to + * initialize the counter in a given value (0, for example) and + * increases it every time a new block is enciphered. This naturally + * leaves to a limitation on the number q of blocks that can be + * enciphered using a same key: q < 2^(counter size). + * + * TinyCrypt uses a counter of 32 bits. This means that after 2^32 + * block encryptions, the counter will be reused (thus losing CBC + * security). 2^32 block encryptions should be enough for most of + * applications targeting constrained devices. Applications intended + * to encrypt a larger number of blocks must replace the key after + * 2^32 block encryptions. + * + * CTR mode provides NO data integrity. + * + * Requires: AES-128 + * + * Usage: 1) call tc_ctr_mode to process the data to encrypt/decrypt. + * + */ + +#ifndef __TC_CTR_MODE_H__ +#define __TC_CTR_MODE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CTR mode encryption/decryption procedure. + * CTR mode encrypts (or decrypts) inlen bytes from in buffer into out buffer + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * out == NULL or + * in == NULL or + * ctr == NULL or + * sched == NULL or + * inlen == 0 or + * outlen == 0 or + * inlen != outlen + * @note Assumes:- The current value in ctr has NOT been used with sched + * - out points to inlen bytes + * - in points to inlen bytes + * - ctr is an integer counter in littleEndian format + * - sched was initialized by aes_set_encrypt_key + * @param out OUT -- produced ciphertext (plaintext) + * @param outlen IN -- length of ciphertext buffer in bytes + * @param in IN -- data to encrypt (or decrypt) + * @param inlen IN -- length of input data in bytes + * @param ctr IN/OUT -- the current counter value + * @param sched IN -- an initialized AES key schedule + */ +int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_CTR_MODE_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ctr_prng.h b/tinycrypt/lib/include/tinycrypt/ctr_prng.h new file mode 100644 index 00000000..9be06dbb --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ctr_prng.h @@ -0,0 +1,166 @@ +/* ctr_prng.h - TinyCrypt interface to a CTR-PRNG implementation */ + +/* + * Copyright (c) 2016, Chris Morrison + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/** + * @file + * @brief Interface to a CTR-PRNG implementation. + * + * Overview: A pseudo-random number generator (PRNG) generates a sequence + * of numbers that have a distribution close to the one expected + * for a sequence of truly random numbers. The NIST Special + * Publication 800-90A specifies several mechanisms to generate + * sequences of pseudo random numbers, including the CTR-PRNG one + * which is based on AES. TinyCrypt implements CTR-PRNG with + * AES-128. + * + * Security: A cryptographically secure PRNG depends on the existence of an + * entropy source to provide a truly random seed as well as the + * security of the primitives used as the building blocks (AES-128 + * in this instance). + * + * Requires: - AES-128 + * + * Usage: 1) call tc_ctr_prng_init to seed the prng context + * + * 2) call tc_ctr_prng_reseed to mix in additional entropy into + * the prng context + * + * 3) call tc_ctr_prng_generate to output the pseudo-random data + * + * 4) call tc_ctr_prng_uninstantiate to zero out the prng context + */ + +#ifndef __TC_CTR_PRNG_H__ +#define __TC_CTR_PRNG_H__ + +#include + +#define TC_CTR_PRNG_RESEED_REQ -1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + /* updated each time another BLOCKLEN_BYTES bytes are produced */ + uint8_t V[TC_AES_BLOCK_SIZE]; + + /* updated whenever the PRNG is reseeded */ + struct tc_aes_key_sched_struct key; + + /* number of requests since initialization/reseeding */ + uint64_t reseedCount; +} TCCtrPrng_t; + + +/** + * @brief CTR-PRNG initialization procedure + * Initializes prng context with entropy and personalization string (if any) + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * ctx == NULL, + * entropy == NULL, + * entropyLen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) + * @note Only the first (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes of + * both the entropy and personalization inputs are used - + * supplying additional bytes has no effect. + * @param ctx IN/OUT -- the PRNG context to initialize + * @param entropy IN -- entropy used to seed the PRNG + * @param entropyLen IN -- entropy length in bytes + * @param personalization IN -- personalization string used to seed the PRNG + * (may be null) + * @param plen IN -- personalization length in bytes + * + */ +int tc_ctr_prng_init(TCCtrPrng_t * const ctx, + uint8_t const * const entropy, + unsigned int entropyLen, + uint8_t const * const personalization, + unsigned int pLen); + +/** + * @brief CTR-PRNG reseed procedure + * Mixes entropy and additional_input into the prng context + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * ctx == NULL, + * entropy == NULL, + * entropylen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) + * @note It is better to reseed an existing prng context rather than + * re-initialise, so that any existing entropy in the context is + * presereved. This offers some protection against undetected failures + * of the entropy source. + * @note Assumes tc_ctr_prng_init has been called for ctx + * @param ctx IN/OUT -- the PRNG state + * @param entropy IN -- entropy to mix into the prng + * @param entropylen IN -- length of entropy in bytes + * @param additional_input IN -- additional input to the prng (may be null) + * @param additionallen IN -- additional input length in bytes + */ +int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx, + uint8_t const * const entropy, + unsigned int entropyLen, + uint8_t const * const additional_input, + unsigned int additionallen); + +/** + * @brief CTR-PRNG generate procedure + * Generates outlen pseudo-random bytes into out buffer, updates prng + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CTR_PRNG_RESEED_REQ (-1) if a reseed is needed + * returns TC_CRYPTO_FAIL (0) if: + * ctx == NULL, + * out == NULL, + * outlen >= 2^16 + * @note Assumes tc_ctr_prng_init has been called for ctx + * @param ctx IN/OUT -- the PRNG context + * @param additional_input IN -- additional input to the prng (may be null) + * @param additionallen IN -- additional input length in bytes + * @param out IN/OUT -- buffer to receive output + * @param outlen IN -- size of out buffer in bytes + */ +int tc_ctr_prng_generate(TCCtrPrng_t * const ctx, + uint8_t const * const additional_input, + unsigned int additionallen, + uint8_t * const out, + unsigned int outlen); + +/** + * @brief CTR-PRNG uninstantiate procedure + * Zeroes the internal state of the supplied prng context + * @return none + * @param ctx IN/OUT -- the PRNG context + */ +void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_CTR_PRNG_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ecc.h b/tinycrypt/lib/include/tinycrypt/ecc.h new file mode 100644 index 00000000..8abc949c --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ecc.h @@ -0,0 +1,545 @@ +/* ecc.h - TinyCrypt interface to common ECC functions */ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief -- Interface to common ECC functions. + * + * Overview: This software is an implementation of common functions + * necessary to elliptic curve cryptography. This implementation uses + * curve NIST p-256. + * + * Security: The curve NIST p-256 provides approximately 128 bits of security. + * + */ + +#ifndef __TC_UECC_H__ +#define __TC_UECC_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Word size (4 bytes considering 32-bits architectures) */ +#define uECC_WORD_SIZE 4 + +/* setting max number of calls to prng: */ +#ifndef uECC_RNG_MAX_TRIES +#define uECC_RNG_MAX_TRIES 64 +#endif + +/* defining data types to store word and bit counts: */ +typedef int8_t wordcount_t; +typedef int16_t bitcount_t; +/* defining data type for comparison result: */ +typedef int8_t cmpresult_t; +/* defining data type to store ECC coordinate/point in 32bits words: */ +typedef unsigned int uECC_word_t; +/* defining data type to store an ECC coordinate/point in 64bits words: */ +typedef uint64_t uECC_dword_t; + +/* defining masks useful for ecc computations: */ +#define HIGH_BIT_SET 0x80000000 +#define uECC_WORD_BITS 32 +#define uECC_WORD_BITS_SHIFT 5 +#define uECC_WORD_BITS_MASK 0x01F + +/* Number of words of 32 bits to represent an element of the the curve p-256: */ +#define NUM_ECC_WORDS 8 +/* Number of bytes to represent an element of the the curve p-256: */ +#define NUM_ECC_BYTES (uECC_WORD_SIZE*NUM_ECC_WORDS) + +/* structure that represents an elliptic curve (e.g. p256):*/ +struct uECC_Curve_t; +typedef const struct uECC_Curve_t * uECC_Curve; +struct uECC_Curve_t { + wordcount_t num_words; + wordcount_t num_bytes; + bitcount_t num_n_bits; + uECC_word_t p[NUM_ECC_WORDS]; + uECC_word_t n[NUM_ECC_WORDS]; + uECC_word_t G[NUM_ECC_WORDS * 2]; + uECC_word_t b[NUM_ECC_WORDS]; + void (*double_jacobian)(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1, + uECC_Curve curve); + void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); + void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product); +}; + +/* + * @brief computes doubling of point ion jacobian coordinates, in place. + * @param X1 IN/OUT -- x coordinate + * @param Y1 IN/OUT -- y coordinate + * @param Z1 IN/OUT -- z coordinate + * @param curve IN -- elliptic curve + */ +void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1, + uECC_word_t * Z1, uECC_Curve curve); + +/* + * @brief Computes x^3 + ax + b. result must not overlap x. + * @param result OUT -- x^3 + ax + b + * @param x IN -- value of x + * @param curve IN -- elliptic curve + */ +void x_side_default(uECC_word_t *result, const uECC_word_t *x, + uECC_Curve curve); + +/* + * @brief Computes result = product % curve_p + * from http://www.nsa.gov/ia/_files/nist-routines.pdf + * @param result OUT -- product % curve_p + * @param product IN -- value to be reduced mod curve_p + */ +void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int *product); + +/* Bytes to words ordering: */ +#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e +#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a +#define BITS_TO_WORDS(num_bits) \ + ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8)) +#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8) + +/* definition of curve NIST p-256: */ +static const struct uECC_Curve_t curve_secp256r1 = { + NUM_ECC_WORDS, + NUM_ECC_BYTES, + 256, /* num_n_bits */ { + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00), + BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), + BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) + }, { + BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3), + BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC), + BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), + BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) + }, { + BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4), + BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77), + BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8), + BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B), + + BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB), + BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B), + BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E), + BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) + }, { + BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B), + BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65), + BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3), + BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) + }, + &double_jacobian_default, + &x_side_default, + &vli_mmod_fast_secp256r1 +}; + +uECC_Curve uECC_secp256r1(void); + +/* + * @brief Generates a random integer in the range 0 < random < top. + * Both random and top have num_words words. + * @param random OUT -- random integer in the range 0 < random < top + * @param top IN -- upper limit + * @param num_words IN -- number of words + * @return a random integer in the range 0 < random < top + */ +int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top, + wordcount_t num_words); + + +/* uECC_RNG_Function type + * The RNG function should fill 'size' random bytes into 'dest'. It should + * return 1 if 'dest' was filled with random data, or 0 if the random data could + * not be generated. The filled-in values should be either truly random, or from + * a cryptographically-secure PRNG. + * + * A correctly functioning RNG function must be set (using uECC_set_rng()) + * before calling uECC_make_key() or uECC_sign(). + * + * Setting a correctly functioning RNG function improves the resistance to + * side-channel attacks for uECC_shared_secret(). + * + * A correct RNG function is set by default. If you are building on another + * POSIX-compliant system that supports /dev/random or /dev/urandom, you can + * define uECC_POSIX to use the predefined RNG. + */ +typedef int(*uECC_RNG_Function)(uint8_t *dest, unsigned int size); + +/* + * @brief Set the function that will be used to generate random bytes. The RNG + * function should return 1 if the random data was generated, or 0 if the random + * data could not be generated. + * + * @note On platforms where there is no predefined RNG function, this must be + * called before uECC_make_key() or uECC_sign() are used. + * + * @param rng_function IN -- function that will be used to generate random bytes + */ +void uECC_set_rng(uECC_RNG_Function rng_function); + +/* + * @brief provides current uECC_RNG_Function. + * @return Returns the function that will be used to generate random bytes. + */ +uECC_RNG_Function uECC_get_rng(void); + +/* + * @brief computes the size of a private key for the curve in bytes. + * @param curve IN -- elliptic curve + * @return size of a private key for the curve in bytes. + */ +int uECC_curve_private_key_size(uECC_Curve curve); + +/* + * @brief computes the size of a public key for the curve in bytes. + * @param curve IN -- elliptic curve + * @return the size of a public key for the curve in bytes. + */ +int uECC_curve_public_key_size(uECC_Curve curve); + +/* + * @brief Compute the corresponding public key for a private key. + * @param private_key IN -- The private key to compute the public key for + * @param public_key OUT -- Will be filled in with the corresponding public key + * @param curve + * @return Returns 1 if key was computed successfully, 0 if an error occurred. + */ +int uECC_compute_public_key(const uint8_t *private_key, + uint8_t *public_key, uECC_Curve curve); + +/* + * @brief Compute public-key. + * @return corresponding public-key. + * @param result OUT -- public-key + * @param private_key IN -- private-key + * @param curve IN -- elliptic curve + */ +uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, + uECC_word_t *private_key, uECC_Curve curve); + +/* + * @brief Regularize the bitcount for the private key so that attackers cannot + * use a side channel attack to learn the number of leading zeros. + * @return Regularized k + * @param k IN -- private-key + * @param k0 IN/OUT -- regularized k + * @param k1 IN/OUT -- regularized k + * @param curve IN -- elliptic curve + */ +uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, + uECC_word_t *k1, uECC_Curve curve); + +/* + * @brief Point multiplication algorithm using Montgomery's ladder with co-Z + * coordinates. See http://eprint.iacr.org/2011/338.pdf. + * @note Result may overlap point. + * @param result OUT -- returns scalar*point + * @param point IN -- elliptic curve point + * @param scalar IN -- scalar + * @param initial_Z IN -- initial value for z + * @param num_bits IN -- number of bits in scalar + * @param curve IN -- elliptic curve + */ +void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, + const uECC_word_t * scalar, const uECC_word_t * initial_Z, + bitcount_t num_bits, uECC_Curve curve); + +/* + * @brief Constant-time comparison to zero - secure way to compare long integers + * @param vli IN -- very long integer + * @param num_words IN -- number of words in the vli + * @return 1 if vli == 0, 0 otherwise. + */ +uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words); + +/* + * @brief Check if 'point' is the point at infinity + * @param point IN -- elliptic curve point + * @param curve IN -- elliptic curve + * @return if 'point' is the point at infinity, 0 otherwise. + */ +uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve); + +/* + * @brief computes the sign of left - right, in constant time. + * @param left IN -- left term to be compared + * @param right IN -- right term to be compared + * @param num_words IN -- number of words + * @return the sign of left - right + */ +cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, + wordcount_t num_words); + +/* + * @brief computes sign of left - right, not in constant time. + * @note should not be used if inputs are part of a secret + * @param left IN -- left term to be compared + * @param right IN -- right term to be compared + * @param num_words IN -- number of words + * @return the sign of left - right + */ +cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, const uECC_word_t *right, + wordcount_t num_words); + +/* + * @brief Computes result = (left - right) % mod. + * @note Assumes that (left < mod) and (right < mod), and that result does not + * overlap mod. + * @param result OUT -- (left - right) % mod + * @param left IN -- leftright term in modular subtraction + * @param right IN -- right term in modular subtraction + * @param mod IN -- mod + * @param num_words IN -- number of words + */ +void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, const uECC_word_t *mod, + wordcount_t num_words); + +/* + * @brief Computes P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) or + * P => P', Q => P + Q + * @note assumes Input P = (x1, y1, Z), Q = (x2, y2, Z) + * @param X1 IN -- x coordinate of P + * @param Y1 IN -- y coordinate of P + * @param X2 IN -- x coordinate of Q + * @param Y2 IN -- y coordinate of Q + * @param curve IN -- elliptic curve + */ +void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, + uECC_word_t * Y2, uECC_Curve curve); + +/* + * @brief Computes (x1 * z^2, y1 * z^3) + * @param X1 IN -- previous x1 coordinate + * @param Y1 IN -- previous y1 coordinate + * @param Z IN -- z value + * @param curve IN -- elliptic curve + */ +void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, + uECC_Curve curve); + +/* + * @brief Check if bit is set. + * @return Returns nonzero if bit 'bit' of vli is set. + * @warning It is assumed that the value provided in 'bit' is within the + * boundaries of the word-array 'vli'. + * @note The bit ordering layout assumed for vli is: {31, 30, ..., 0}, + * {63, 62, ..., 32}, {95, 94, ..., 64}, {127, 126,..., 96} for a vli consisting + * of 4 uECC_word_t elements. + */ +uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit); + +/* + * @brief Computes result = product % mod, where product is 2N words long. + * @param result OUT -- product % mod + * @param mod IN -- module + * @param num_words IN -- number of words + * @warning Currently only designed to work for curve_p or curve_n. + */ +void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product, + const uECC_word_t *mod, wordcount_t num_words); + +/* + * @brief Computes modular product (using curve->mmod_fast) + * @param result OUT -- (left * right) mod % curve_p + * @param left IN -- left term in product + * @param right IN -- right term in product + * @param curve IN -- elliptic curve + */ +void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, uECC_Curve curve); + +/* + * @brief Computes result = left - right. + * @note Can modify in place. + * @param result OUT -- left - right + * @param left IN -- left term in subtraction + * @param right IN -- right term in subtraction + * @param num_words IN -- number of words + * @return borrow + */ +uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, wordcount_t num_words); + +/* + * @brief Constant-time comparison function(secure way to compare long ints) + * @param left IN -- left term in comparison + * @param right IN -- right term in comparison + * @param num_words IN -- number of words + * @return Returns 0 if left == right, 1 otherwise. + */ +uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right, + wordcount_t num_words); + +/* + * @brief Computes (left * right) % mod + * @param result OUT -- (left * right) % mod + * @param left IN -- left term in product + * @param right IN -- right term in product + * @param mod IN -- mod + * @param num_words IN -- number of words + */ +void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, const uECC_word_t *mod, + wordcount_t num_words); + +/* + * @brief Computes (1 / input) % mod + * @note All VLIs are the same size. + * @note See "Euclid's GCD to Montgomery Multiplication to the Great Divide" + * @param result OUT -- (1 / input) % mod + * @param input IN -- value to be modular inverted + * @param mod IN -- mod + * @param num_words -- number of words + */ +void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input, + const uECC_word_t *mod, wordcount_t num_words); + +/* + * @brief Sets dest = src. + * @param dest OUT -- destination buffer + * @param src IN -- origin buffer + * @param num_words IN -- number of words + */ +void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, + wordcount_t num_words); + +/* + * @brief Computes (left + right) % mod. + * @note Assumes that (left < mod) and right < mod), and that result does not + * overlap mod. + * @param result OUT -- (left + right) % mod. + * @param left IN -- left term in addition + * @param right IN -- right term in addition + * @param mod IN -- mod + * @param num_words IN -- number of words + */ +void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, const uECC_word_t *mod, + wordcount_t num_words); + +/* + * @brief Counts the number of bits required to represent vli. + * @param vli IN -- very long integer + * @param max_words IN -- number of words + * @return number of bits in given vli + */ +bitcount_t uECC_vli_numBits(const uECC_word_t *vli, + const wordcount_t max_words); + +/* + * @brief Erases (set to 0) vli + * @param vli IN -- very long integer + * @param num_words IN -- number of words + */ +void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words); + +/* + * @brief check if it is a valid point in the curve + * @param point IN -- point to be checked + * @param curve IN -- elliptic curve + * @return 0 if point is valid + * @exception returns -1 if it is a point at infinity + * @exception returns -2 if x or y is smaller than p, + * @exception returns -3 if y^2 != x^3 + ax + b. + */ +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve); + +/* + * @brief Check if a public key is valid. + * @param public_key IN -- The public key to be checked. + * @return returns 0 if the public key is valid + * @exception returns -1 if it is a point at infinity + * @exception returns -2 if x or y is smaller than p, + * @exception returns -3 if y^2 != x^3 + ax + b. + * @exception returns -4 if public key is the group generator. + * + * @note Note that you are not required to check for a valid public key before + * using any other uECC functions. However, you may wish to avoid spending CPU + * time computing a shared secret or verifying a signature using an invalid + * public key. + */ +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); + + /* + * @brief Converts an integer in uECC native format to big-endian bytes. + * @param bytes OUT -- bytes representation + * @param num_bytes IN -- number of bytes + * @param native IN -- uECC native representation + */ +void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, + const unsigned int *native); + +/* + * @brief Converts big-endian bytes to an integer in uECC native format. + * @param native OUT -- uECC native representation + * @param bytes IN -- bytes representation + * @param num_bytes IN -- number of bytes + */ +void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes, + int num_bytes); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_UECC_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ecc_dh.h b/tinycrypt/lib/include/tinycrypt/ecc_dh.h new file mode 100644 index 00000000..b828e195 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ecc_dh.h @@ -0,0 +1,131 @@ +/* ecc_dh.h - TinyCrypt interface to EC-DH implementation */ + +/* + * Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/* Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief -- Interface to EC-DH implementation. + * + * Overview: This software is an implementation of EC-DH. This implementation + * uses curve NIST p-256. + * + * Security: The curve NIST p-256 provides approximately 128 bits of security. + */ + +#ifndef __TC_ECC_DH_H__ +#define __TC_ECC_DH_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create a public/private key pair. + * @return returns TC_CRYPTO_SUCCESS (1) if the key pair was generated successfully + * returns TC_CRYPTO_FAIL (0) if error while generating key pair + * + * @param p_public_key OUT -- Will be filled in with the public key. Must be at + * least 2 * the curve size (in bytes) long. For curve secp256r1, p_public_key + * must be 64 bytes long. + * @param p_private_key OUT -- Will be filled in with the private key. Must be as + * long as the curve order (for secp256r1, p_private_key must be 32 bytes long). + * + * @note side-channel countermeasure: algorithm strengthened against timing + * attack. + * @warning A cryptographically-secure PRNG function must be set (using + * uECC_set_rng()) before calling uECC_make_key(). + */ +int uECC_make_key(uint8_t *p_public_key, uint8_t *p_private_key, uECC_Curve curve); + +#ifdef ENABLE_TESTS + +/** + * @brief Create a public/private key pair given a specific d. + * + * @note THIS FUNCTION SHOULD BE CALLED ONLY FOR TEST PURPOSES. Refer to + * uECC_make_key() function for real applications. + */ +int uECC_make_key_with_d(uint8_t *p_public_key, uint8_t *p_private_key, + unsigned int *d, uECC_Curve curve); +#endif + +/** + * @brief Compute a shared secret given your secret key and someone else's + * public key. + * @return returns TC_CRYPTO_SUCCESS (1) if the shared secret was computed successfully + * returns TC_CRYPTO_FAIL (0) otherwise + * + * @param p_secret OUT -- Will be filled in with the shared secret value. Must be + * the same size as the curve size (for curve secp256r1, secret must be 32 bytes + * long. + * @param p_public_key IN -- The public key of the remote party. + * @param p_private_key IN -- Your private key. + * + * @warning It is recommended to use the output of uECC_shared_secret() as the + * input of a recommended Key Derivation Function (see NIST SP 800-108) in + * order to produce a cryptographically secure symmetric key. + */ +int uECC_shared_secret(const uint8_t *p_public_key, const uint8_t *p_private_key, + uint8_t *p_secret, uECC_Curve curve); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_ECC_DH_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ecc_dsa.h b/tinycrypt/lib/include/tinycrypt/ecc_dsa.h new file mode 100644 index 00000000..aca00bc9 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ecc_dsa.h @@ -0,0 +1,139 @@ +/* ecc_dh.h - TinyCrypt interface to EC-DSA implementation */ + +/* + * Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief -- Interface to EC-DSA implementation. + * + * Overview: This software is an implementation of EC-DSA. This implementation + * uses curve NIST p-256. + * + * Security: The curve NIST p-256 provides approximately 128 bits of security. + * + * Usage: - To sign: Compute a hash of the data you wish to sign (SHA-2 is + * recommended) and pass it in to ecdsa_sign function along with your + * private key and a random number. You must use a new non-predictable + * random number to generate each new signature. + * - To verify a signature: Compute the hash of the signed data using + * the same hash as the signer and pass it to this function along with + * the signer's public key and the signature values (r and s). + */ + +#ifndef __TC_ECC_DSA_H__ +#define __TC_ECC_DSA_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Generate an ECDSA signature for a given hash value. + * @return returns TC_CRYPTO_SUCCESS (1) if the signature generated successfully + * returns TC_CRYPTO_FAIL (0) if an error occurred. + * + * @param p_private_key IN -- Your private key. + * @param p_message_hash IN -- The hash of the message to sign. + * @param p_hash_size IN -- The size of p_message_hash in bytes. + * @param p_signature OUT -- Will be filled in with the signature value. Must be + * at least 2 * curve size long (for secp256r1, signature must be 64 bytes long). + * + * @warning A cryptographically-secure PRNG function must be set (using + * uECC_set_rng()) before calling uECC_sign(). + * @note Usage: Compute a hash of the data you wish to sign (SHA-2 is + * recommended) and pass it in to this function along with your private key. + * @note side-channel countermeasure: algorithm strengthened against timing + * attack. + */ +int uECC_sign(const uint8_t *p_private_key, const uint8_t *p_message_hash, + unsigned p_hash_size, uint8_t *p_signature, uECC_Curve curve); + +#ifdef ENABLE_TESTS +/* + * THIS FUNCTION SHOULD BE CALLED FOR TEST PURPOSES ONLY. + * Refer to uECC_sign() function for real applications. + */ +int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, + unsigned int hash_size, uECC_word_t *k, uint8_t *signature, + uECC_Curve curve); +#endif + +/** + * @brief Verify an ECDSA signature. + * @return returns TC_SUCCESS (1) if the signature is valid + * returns TC_FAIL (0) if the signature is invalid. + * + * @param p_public_key IN -- The signer's public key. + * @param p_message_hash IN -- The hash of the signed data. + * @param p_hash_size IN -- The size of p_message_hash in bytes. + * @param p_signature IN -- The signature values. + * + * @note Usage: Compute the hash of the signed data using the same hash as the + * signer and pass it to this function along with the signer's public key and + * the signature values (hash_size and signature). + */ +int uECC_verify(const uint8_t *p_public_key, const uint8_t *p_message_hash, + unsigned int p_hash_size, const uint8_t *p_signature, uECC_Curve curve); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_ECC_DSA_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h b/tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h new file mode 100644 index 00000000..e2c88235 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/ecc_platform_specific.h @@ -0,0 +1,81 @@ +/* uECC_platform_specific.h - Interface to platform specific functions*/ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.*/ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * uECC_platform_specific.h -- Interface to platform specific functions + */ + +#ifndef __UECC_PLATFORM_SPECIFIC_H_ +#define __UECC_PLATFORM_SPECIFIC_H_ + +/* + * The RNG function should fill 'size' random bytes into 'dest'. It should + * return 1 if 'dest' was filled with random data, or 0 if the random data could + * not be generated. The filled-in values should be either truly random, or from + * a cryptographically-secure PRNG. + * + * A cryptographically-secure PRNG function must be set (using uECC_set_rng()) + * before calling uECC_make_key() or uECC_sign(). + * + * Setting a cryptographically-secure PRNG function improves the resistance to + * side-channel attacks for uECC_shared_secret(). + * + * A correct PRNG function is set by default (default_RNG_defined = 1) and works + * for some platforms, such as Unix and Linux. For other platforms, you may need + * to provide another PRNG function. +*/ +#define default_RNG_defined 1 + +int default_CSPRNG(uint8_t *dest, unsigned int size); + +#endif /* __UECC_PLATFORM_SPECIFIC_H_ */ diff --git a/tinycrypt/lib/include/tinycrypt/hmac.h b/tinycrypt/lib/include/tinycrypt/hmac.h new file mode 100644 index 00000000..3a081494 --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/hmac.h @@ -0,0 +1,139 @@ +/* hmac.h - TinyCrypt interface to an HMAC implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to an HMAC implementation. + * + * Overview: HMAC is a message authentication code based on hash functions. + * TinyCrypt hard codes SHA-256 as the hash function. A message + * authentication code based on hash functions is also called a + * keyed cryptographic hash function since it performs a + * transformation specified by a key in an arbitrary length data + * set into a fixed length data set (also called tag). + * + * Security: The security of the HMAC depends on the length of the key and + * on the security of the hash function. Note that HMAC primitives + * are much less affected by collision attacks than their + * corresponding hash functions. + * + * Requires: SHA-256 + * + * Usage: 1) call tc_hmac_set_key to set the HMAC key. + * + * 2) call tc_hmac_init to initialize a struct hash_state before + * processing the data. + * + * 3) call tc_hmac_update to process the next input segment; + * tc_hmac_update can be called as many times as needed to process + * all of the segments of the input; the order is important. + * + * 4) call tc_hmac_final to out put the tag. + */ + +#ifndef __TC_HMAC_H__ +#define __TC_HMAC_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct tc_hmac_state_struct { + /* the internal state required by h */ + struct tc_sha256_state_struct hash_state; + /* HMAC key schedule */ + uint8_t key[2*TC_SHA256_BLOCK_SIZE]; +}; +typedef struct tc_hmac_state_struct *TCHmacState_t; + +/** + * @brief HMAC set key procedure + * Configures ctx to use key + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if + * ctx == NULL or + * key == NULL or + * key_size == 0 + * @param ctx IN/OUT -- the struct tc_hmac_state_struct to initial + * @param key IN -- the HMAC key to configure + * @param key_size IN -- the HMAC key size + */ +int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key, + unsigned int key_size); + +/** + * @brief HMAC init procedure + * Initializes ctx to begin the next HMAC operation + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL + * @param ctx IN/OUT -- struct tc_hmac_state_struct buffer to init + */ +int tc_hmac_init(TCHmacState_t ctx); + +/** + * @brief HMAC update procedure + * Mixes data_length bytes addressed by data into state + * @return returns TC_CRYPTO_SUCCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: ctx == NULL or key == NULL + * @note Assumes state has been initialized by tc_hmac_init + * @param ctx IN/OUT -- state of HMAC computation so far + * @param data IN -- data to incorporate into state + * @param data_length IN -- size of data in bytes + */ +int tc_hmac_update(TCHmacState_t ctx, const void *data, + unsigned int data_length); + +/** + * @brief HMAC final procedure + * Writes the HMAC tag into the tag buffer + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * tag == NULL or + * ctx == NULL or + * key == NULL or + * taglen != TC_SHA256_DIGEST_SIZE + * @note ctx is erased before exiting. This should never be changed/removed. + * @note Assumes the tag bufer is at least sizeof(hmac_tag_size(state)) bytes + * state has been initialized by tc_hmac_init + * @param tag IN/OUT -- buffer to receive computed HMAC tag + * @param taglen IN -- size of tag in bytes + * @param ctx IN/OUT -- the HMAC state for computing tag + */ +int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx); + +#ifdef __cplusplus +} +#endif + +#endif /*__TC_HMAC_H__*/ diff --git a/tinycrypt/lib/include/tinycrypt/hmac_prng.h b/tinycrypt/lib/include/tinycrypt/hmac_prng.h new file mode 100644 index 00000000..ad12cbbf --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/hmac_prng.h @@ -0,0 +1,164 @@ +/* hmac_prng.h - TinyCrypt interface to an HMAC-PRNG implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to an HMAC-PRNG implementation. + * + * Overview: A pseudo-random number generator (PRNG) generates a sequence + * of numbers that have a distribution close to the one expected + * for a sequence of truly random numbers. The NIST Special + * Publication 800-90A specifies several mechanisms to generate + * sequences of pseudo random numbers, including the HMAC-PRNG one + * which is based on HMAC. TinyCrypt implements HMAC-PRNG with + * certain modifications from the NIST SP 800-90A spec. + * + * Security: A cryptographically secure PRNG depends on the existence of an + * entropy source to provide a truly random seed as well as the + * security of the primitives used as the building blocks (HMAC and + * SHA256, for TinyCrypt). + * + * The NIST SP 800-90A standard tolerates a null personalization, + * while TinyCrypt requires a non-null personalization. This is + * because a personalization string (the host name concatenated + * with a time stamp, for example) is easily computed and might be + * the last line of defense against failure of the entropy source. + * + * Requires: - SHA-256 + * - HMAC + * + * Usage: 1) call tc_hmac_prng_init to set the HMAC key and process the + * personalization data. + * + * 2) call tc_hmac_prng_reseed to process the seed and additional + * input. + * + * 3) call tc_hmac_prng_generate to out put the pseudo-random data. + */ + +#ifndef __TC_HMAC_PRNG_H__ +#define __TC_HMAC_PRNG_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TC_HMAC_PRNG_RESEED_REQ -1 + +struct tc_hmac_prng_struct { + /* the HMAC instance for this PRNG */ + struct tc_hmac_state_struct h; + /* the PRNG key */ + uint8_t key[TC_SHA256_DIGEST_SIZE]; + /* PRNG state */ + uint8_t v[TC_SHA256_DIGEST_SIZE]; + /* calls to tc_hmac_prng_generate left before re-seed */ + unsigned int countdown; +}; + +typedef struct tc_hmac_prng_struct *TCHmacPrng_t; + +/** + * @brief HMAC-PRNG initialization procedure + * Initializes prng with personalization, disables tc_hmac_prng_generate + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * prng == NULL, + * personalization == NULL, + * plen > MAX_PLEN + * @note Assumes: - personalization != NULL. + * The personalization is a platform unique string (e.g., the host + * name) and is the last line of defense against failure of the + * entropy source + * @warning NIST SP 800-90A specifies 3 items as seed material during + * initialization: entropy seed, personalization, and an optional + * nonce. TinyCrypts requires instead a non-null personalization + * (which is easily computed) and indirectly requires an entropy + * seed (since the reseed function is mandatorily called after + * init) + * @param prng IN/OUT -- the PRNG state to initialize + * @param personalization IN -- personalization string + * @param plen IN -- personalization length in bytes + */ +int tc_hmac_prng_init(TCHmacPrng_t prng, + const uint8_t *personalization, + unsigned int plen); + +/** + * @brief HMAC-PRNG reseed procedure + * Mixes seed into prng, enables tc_hmac_prng_generate + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * prng == NULL, + * seed == NULL, + * seedlen < MIN_SLEN, + * seendlen > MAX_SLEN, + * additional_input != (const uint8_t *) 0 && additionallen == 0, + * additional_input != (const uint8_t *) 0 && additionallen > MAX_ALEN + * @note Assumes:- tc_hmac_prng_init has been called for prng + * - seed has sufficient entropy. + * + * @param prng IN/OUT -- the PRNG state + * @param seed IN -- entropy to mix into the prng + * @param seedlen IN -- length of seed in bytes + * @param additional_input IN -- additional input to the prng + * @param additionallen IN -- additional input length in bytes + */ +int tc_hmac_prng_reseed(TCHmacPrng_t prng, const uint8_t *seed, + unsigned int seedlen, const uint8_t *additional_input, + unsigned int additionallen); + +/** + * @brief HMAC-PRNG generate procedure + * Generates outlen pseudo-random bytes into out buffer, updates prng + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_HMAC_PRNG_RESEED_REQ (-1) if a reseed is needed + * returns TC_CRYPTO_FAIL (0) if: + * out == NULL, + * prng == NULL, + * outlen == 0, + * outlen >= MAX_OUT + * @note Assumes tc_hmac_prng_init has been called for prng + * @param out IN/OUT -- buffer to receive output + * @param outlen IN -- size of out buffer in bytes + * @param prng IN/OUT -- the PRNG state + */ +int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_HMAC_PRNG_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/sha256.h b/tinycrypt/lib/include/tinycrypt/sha256.h new file mode 100644 index 00000000..af5e8baf --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/sha256.h @@ -0,0 +1,129 @@ +/* sha256.h - TinyCrypt interface to a SHA-256 implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to a SHA-256 implementation. + * + * Overview: SHA-256 is a NIST approved cryptographic hashing algorithm + * specified in FIPS 180. A hash algorithm maps data of arbitrary + * size to data of fixed length. + * + * Security: SHA-256 provides 128 bits of security against collision attacks + * and 256 bits of security against pre-image attacks. SHA-256 does + * NOT behave like a random oracle, but it can be used as one if + * the string being hashed is prefix-free encoded before hashing. + * + * Usage: 1) call tc_sha256_init to initialize a struct + * tc_sha256_state_struct before hashing a new string. + * + * 2) call tc_sha256_update to hash the next string segment; + * tc_sha256_update can be called as many times as needed to hash + * all of the segments of a string; the order is important. + * + * 3) call tc_sha256_final to out put the digest from a hashing + * operation. + */ + +#ifndef __TC_SHA256_H__ +#define __TC_SHA256_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TC_SHA256_BLOCK_SIZE (64) +#define TC_SHA256_DIGEST_SIZE (32) +#define TC_SHA256_STATE_BLOCKS (TC_SHA256_DIGEST_SIZE/4) + +struct tc_sha256_state_struct { + unsigned int iv[TC_SHA256_STATE_BLOCKS]; + uint64_t bits_hashed; + uint8_t leftover[TC_SHA256_BLOCK_SIZE]; + size_t leftover_offset; +}; + +typedef struct tc_sha256_state_struct *TCSha256State_t; + +/** + * @brief SHA256 initialization procedure + * Initializes s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if s == NULL + * @param s Sha256 state struct + */ +int tc_sha256_init(TCSha256State_t s); + +/** + * @brief SHA256 update procedure + * Hashes data_length bytes addressed by data into state s + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * s == NULL, + * s->iv == NULL, + * data == NULL + * @note Assumes s has been initialized by tc_sha256_init + * @warning The state buffer 'leftover' is left in memory after processing + * If your application intends to have sensitive data in this + * buffer, remind to erase it after the data has been processed + * @param s Sha256 state struct + * @param data message to hash + * @param datalen length of message to hash + */ +int tc_sha256_update (TCSha256State_t s, const uint8_t *data, size_t datalen); + +/** + * @brief SHA256 final procedure + * Inserts the completed hash computation into digest + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * s == NULL, + * s->iv == NULL, + * digest == NULL + * @note Assumes: s has been initialized by tc_sha256_init + * digest points to at least TC_SHA256_DIGEST_SIZE bytes + * @warning The state buffer 'leftover' is left in memory after processing + * If your application intends to have sensitive data in this + * buffer, remind to erase it after the data has been processed + * @param digest unsigned eight bit integer + * @param Sha256 state struct + */ +int tc_sha256_final(uint8_t *digest, TCSha256State_t s); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_SHA256_H__ */ diff --git a/tinycrypt/lib/include/tinycrypt/utils.h b/tinycrypt/lib/include/tinycrypt/utils.h new file mode 100644 index 00000000..6b7b0abf --- /dev/null +++ b/tinycrypt/lib/include/tinycrypt/utils.h @@ -0,0 +1,121 @@ +/* utils.h - TinyCrypt interface to platform-dependent run-time operations */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/** + * @file + * @brief Interface to platform-dependent run-time operations. + * + */ + +#ifndef __TC_UTILS_H__ +#define __TC_UTILS_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Copy the the buffer 'from' to the buffer 'to'. + * @return returns TC_CRYPTO_SUCCESS (1) + * returns TC_CRYPTO_FAIL (0) if: + * from_len > to_len. + * + * @param to OUT -- destination buffer + * @param to_len IN -- length of destination buffer + * @param from IN -- origin buffer + * @param from_len IN -- length of origin buffer + */ +unsigned int _copy(uint8_t *to, unsigned int to_len, + const uint8_t *from, unsigned int from_len); + +/** + * @brief Set the value 'val' into the buffer 'to', 'len' times. + * + * @param to OUT -- destination buffer + * @param val IN -- value to be set in 'to' + * @param len IN -- number of times the value will be copied + */ +void _set(void *to, uint8_t val, unsigned int len); + +/** + * @brief Set the value 'val' into the buffer 'to', 'len' times, in a way + * which does not risk getting optimized out by the compiler + * In cases where the compiler does not set __GNUC__ and where the + * optimization level removes the memset, it may be necessary to + * implement a _set_secure function and define the + * TINYCRYPT_ARCH_HAS_SET_SECURE, which then can ensure that the + * memset does not get optimized out. + * + * @param to OUT -- destination buffer + * @param val IN -- value to be set in 'to' + * @param len IN -- number of times the value will be copied + */ +#ifdef TINYCRYPT_ARCH_HAS_SET_SECURE +extern void _set_secure(void *to, uint8_t val, unsigned int len); +#else /* ! TINYCRYPT_ARCH_HAS_SET_SECURE */ +static inline void _set_secure(void *to, uint8_t val, unsigned int len) +{ + (void) memset(to, val, len); +#ifdef __GNUC__ + __asm__ __volatile__("" :: "g"(to) : "memory"); +#endif /* __GNUC__ */ +} +#endif /* TINYCRYPT_ARCH_HAS_SET_SECURE */ + +/* + * @brief AES specific doubling function, which utilizes + * the finite field used by AES. + * @return Returns a^2 + * + * @param a IN/OUT -- value to be doubled + */ +uint8_t _double_byte(uint8_t a); + +/* + * @brief Constant-time algorithm to compare if two sequences of bytes are equal + * @return Returns 0 if equal, and non-zero otherwise + * + * @param a IN -- sequence of bytes a + * @param b IN -- sequence of bytes b + * @param size IN -- size of sequences a and b + */ +int _compare(const uint8_t *a, const uint8_t *b, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* __TC_UTILS_H__ */ diff --git a/tinycrypt/lib/source/aes_decrypt.c b/tinycrypt/lib/source/aes_decrypt.c new file mode 100644 index 00000000..993a6180 --- /dev/null +++ b/tinycrypt/lib/source/aes_decrypt.c @@ -0,0 +1,164 @@ +/* aes_decrypt.c - TinyCrypt implementation of AES decryption procedure */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +static const uint8_t inv_sbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, + 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, + 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, + 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, + 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, + 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, + 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, + 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, + 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, + 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0c, 0x7d +}; + +int tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k) +{ + return tc_aes128_set_encrypt_key(s, k); +} + +#define mult8(a)(_double_byte(_double_byte(_double_byte(a)))) +#define mult9(a)(mult8(a)^(a)) +#define multb(a)(mult8(a)^_double_byte(a)^(a)) +#define multd(a)(mult8(a)^_double_byte(_double_byte(a))^(a)) +#define multe(a)(mult8(a)^_double_byte(_double_byte(a))^_double_byte(a)) + +static inline void mult_row_column(uint8_t *out, const uint8_t *in) +{ + out[0] = multe(in[0]) ^ multb(in[1]) ^ multd(in[2]) ^ mult9(in[3]); + out[1] = mult9(in[0]) ^ multe(in[1]) ^ multb(in[2]) ^ multd(in[3]); + out[2] = multd(in[0]) ^ mult9(in[1]) ^ multe(in[2]) ^ multb(in[3]); + out[3] = multb(in[0]) ^ multd(in[1]) ^ mult9(in[2]) ^ multe(in[3]); +} + +static inline void inv_mix_columns(uint8_t *s) +{ + uint8_t t[Nb*Nk]; + + mult_row_column(t, s); + mult_row_column(&t[Nb], s+Nb); + mult_row_column(&t[2*Nb], s+(2*Nb)); + mult_row_column(&t[3*Nb], s+(3*Nb)); + (void)_copy(s, sizeof(t), t, sizeof(t)); +} + +static inline void add_round_key(uint8_t *s, const unsigned int *k) +{ + s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16); + s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]); + s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16); + s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]); + s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16); + s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]); + s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16); + s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]); +} + +static inline void inv_sub_bytes(uint8_t *s) +{ + unsigned int i; + + for (i = 0; i < (Nb*Nk); ++i) { + s[i] = inv_sbox[s[i]]; + } +} + +/* + * This inv_shift_rows also implements the matrix flip required for + * inv_mix_columns, but performs it here to reduce the number of memory + * operations. + */ +static inline void inv_shift_rows(uint8_t *s) +{ + uint8_t t[Nb*Nk]; + + t[0] = s[0]; t[1] = s[13]; t[2] = s[10]; t[3] = s[7]; + t[4] = s[4]; t[5] = s[1]; t[6] = s[14]; t[7] = s[11]; + t[8] = s[8]; t[9] = s[5]; t[10] = s[2]; t[11] = s[15]; + t[12] = s[12]; t[13] = s[9]; t[14] = s[6]; t[15] = s[3]; + (void)_copy(s, sizeof(t), t, sizeof(t)); +} + +int tc_aes_decrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) +{ + uint8_t state[Nk*Nb]; + unsigned int i; + + if (out == (uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (in == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (s == (TCAesKeySched_t) 0) { + return TC_CRYPTO_FAIL; + } + + (void)_copy(state, sizeof(state), in, sizeof(state)); + + add_round_key(state, s->words + Nb*Nr); + + for (i = Nr - 1; i > 0; --i) { + inv_shift_rows(state); + inv_sub_bytes(state); + add_round_key(state, s->words + Nb*i); + inv_mix_columns(state); + } + + inv_shift_rows(state); + inv_sub_bytes(state); + add_round_key(state, s->words); + + (void)_copy(out, sizeof(state), state, sizeof(state)); + + /*zeroing out the state buffer */ + _set(state, TC_ZERO_BYTE, sizeof(state)); + + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/aes_encrypt.c b/tinycrypt/lib/source/aes_encrypt.c new file mode 100644 index 00000000..8991aee5 --- /dev/null +++ b/tinycrypt/lib/source/aes_encrypt.c @@ -0,0 +1,191 @@ +/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +static const uint8_t sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, + 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, + 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, + 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, + 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, + 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16 +}; + +static inline unsigned int rotword(unsigned int a) +{ + return (((a) >> 24)|((a) << 8)); +} + +#define subbyte(a, o)(sbox[((a) >> (o))&0xff] << (o)) +#define subword(a)(subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0)) + +int tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k) +{ + const unsigned int rconst[11] = { + 0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 + }; + unsigned int i; + unsigned int t; + + if (s == (TCAesKeySched_t) 0) { + return TC_CRYPTO_FAIL; + } else if (k == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } + + for (i = 0; i < Nk; ++i) { + s->words[i] = (k[Nb*i]<<24) | (k[Nb*i+1]<<16) | + (k[Nb*i+2]<<8) | (k[Nb*i+3]); + } + + for (; i < (Nb * (Nr + 1)); ++i) { + t = s->words[i-1]; + if ((i % Nk) == 0) { + t = subword(rotword(t)) ^ rconst[i/Nk]; + } + s->words[i] = s->words[i-Nk] ^ t; + } + + return TC_CRYPTO_SUCCESS; +} + +static inline void add_round_key(uint8_t *s, const unsigned int *k) +{ + s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16); + s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]); + s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16); + s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]); + s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16); + s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]); + s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16); + s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]); +} + +static inline void sub_bytes(uint8_t *s) +{ + unsigned int i; + + for (i = 0; i < (Nb * Nk); ++i) { + s[i] = sbox[s[i]]; + } +} + +#define triple(a)(_double_byte(a)^(a)) + +static inline void mult_row_column(uint8_t *out, const uint8_t *in) +{ + out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3]; + out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3]; + out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]); + out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]); +} + +static inline void mix_columns(uint8_t *s) +{ + uint8_t t[Nb*Nk]; + + mult_row_column(t, s); + mult_row_column(&t[Nb], s+Nb); + mult_row_column(&t[2 * Nb], s + (2 * Nb)); + mult_row_column(&t[3 * Nb], s + (3 * Nb)); + (void) _copy(s, sizeof(t), t, sizeof(t)); +} + +/* + * This shift_rows also implements the matrix flip required for mix_columns, but + * performs it here to reduce the number of memory operations. + */ +static inline void shift_rows(uint8_t *s) +{ + uint8_t t[Nb * Nk]; + + t[0] = s[0]; t[1] = s[5]; t[2] = s[10]; t[3] = s[15]; + t[4] = s[4]; t[5] = s[9]; t[6] = s[14]; t[7] = s[3]; + t[8] = s[8]; t[9] = s[13]; t[10] = s[2]; t[11] = s[7]; + t[12] = s[12]; t[13] = s[1]; t[14] = s[6]; t[15] = s[11]; + (void) _copy(s, sizeof(t), t, sizeof(t)); +} + +int tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s) +{ + uint8_t state[Nk*Nb]; + unsigned int i; + + if (out == (uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (in == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (s == (TCAesKeySched_t) 0) { + return TC_CRYPTO_FAIL; + } + + (void)_copy(state, sizeof(state), in, sizeof(state)); + add_round_key(state, s->words); + + for (i = 0; i < (Nr - 1); ++i) { + sub_bytes(state); + shift_rows(state); + mix_columns(state); + add_round_key(state, s->words + Nb*(i+1)); + } + + sub_bytes(state); + shift_rows(state); + add_round_key(state, s->words + Nb*(i+1)); + + (void)_copy(out, sizeof(state), state, sizeof(state)); + + /* zeroing out the state buffer */ + _set(state, TC_ZERO_BYTE, sizeof(state)); + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/cbc_mode.c b/tinycrypt/lib/source/cbc_mode.c new file mode 100644 index 00000000..ae20af1a --- /dev/null +++ b/tinycrypt/lib/source/cbc_mode.c @@ -0,0 +1,114 @@ +/* cbc_mode.c - TinyCrypt implementation of CBC mode encryption & decryption */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +int tc_cbc_mode_encrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, const uint8_t *iv, + const TCAesKeySched_t sched) +{ + + uint8_t buffer[TC_AES_BLOCK_SIZE]; + unsigned int n, m; + + /* input sanity check: */ + if (out == (uint8_t *) 0 || + in == (const uint8_t *) 0 || + sched == (TCAesKeySched_t) 0 || + inlen == 0 || + outlen == 0 || + (inlen % TC_AES_BLOCK_SIZE) != 0 || + (outlen % TC_AES_BLOCK_SIZE) != 0 || + outlen != inlen + TC_AES_BLOCK_SIZE) { + return TC_CRYPTO_FAIL; + } + + /* copy iv to the buffer */ + (void)_copy(buffer, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE); + /* copy iv to the output buffer */ + (void)_copy(out, TC_AES_BLOCK_SIZE, iv, TC_AES_BLOCK_SIZE); + out += TC_AES_BLOCK_SIZE; + + for (n = m = 0; n < inlen; ++n) { + buffer[m++] ^= *in++; + if (m == TC_AES_BLOCK_SIZE) { + (void)tc_aes_encrypt(buffer, buffer, sched); + (void)_copy(out, TC_AES_BLOCK_SIZE, + buffer, TC_AES_BLOCK_SIZE); + out += TC_AES_BLOCK_SIZE; + m = 0; + } + } + + return TC_CRYPTO_SUCCESS; +} + +int tc_cbc_mode_decrypt(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, const uint8_t *iv, + const TCAesKeySched_t sched) +{ + + uint8_t buffer[TC_AES_BLOCK_SIZE]; + const uint8_t *p; + unsigned int n, m; + + /* sanity check the inputs */ + if (out == (uint8_t *) 0 || + in == (const uint8_t *) 0 || + sched == (TCAesKeySched_t) 0 || + inlen == 0 || + outlen == 0 || + (inlen % TC_AES_BLOCK_SIZE) != 0 || + (outlen % TC_AES_BLOCK_SIZE) != 0 || + outlen != inlen) { + return TC_CRYPTO_FAIL; + } + + /* + * Note that in == iv + ciphertext, i.e. the iv and the ciphertext are + * contiguous. This allows for a very efficient decryption algorithm + * that would not otherwise be possible. + */ + p = iv; + for (n = m = 0; n < outlen; ++n) { + if ((n % TC_AES_BLOCK_SIZE) == 0) { + (void)tc_aes_decrypt(buffer, in, sched); + in += TC_AES_BLOCK_SIZE; + m = 0; + } + *out++ = buffer[m++] ^ *p++; + } + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/ccm_mode.c b/tinycrypt/lib/source/ccm_mode.c new file mode 100644 index 00000000..929adac6 --- /dev/null +++ b/tinycrypt/lib/source/ccm_mode.c @@ -0,0 +1,266 @@ +/* ccm_mode.c - TinyCrypt implementation of CCM mode */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +#include + +int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce, + unsigned int nlen, unsigned int mlen) +{ + + /* input sanity check: */ + if (c == (TCCcmMode_t) 0 || + sched == (TCAesKeySched_t) 0 || + nonce == (uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } else if (nlen != 13) { + return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/ + } else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) { + return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16.*/ + } + + c->mlen = mlen; + c->sched = sched; + c->nonce = nonce; + + return TC_CRYPTO_SUCCESS; +} + +/** + * Variation of CBC-MAC mode used in CCM. + */ +static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen, + unsigned int flag, TCAesKeySched_t sched) +{ + + unsigned int i; + + if (flag > 0) { + T[0] ^= (uint8_t)(dlen >> 8); + T[1] ^= (uint8_t)(dlen); + dlen += 2; i = 2; + } else { + i = 0; + } + + while (i < dlen) { + T[i++ % (Nb * Nk)] ^= *data++; + if (((i % (Nb * Nk)) == 0) || dlen == i) { + (void) tc_aes_encrypt(T, T, sched); + } + } +} + +/** + * Variation of CTR mode used in CCM. + * The CTR mode used by CCM is slightly different than the conventional CTR + * mode (the counter is increased before encryption, instead of after + * encryption). Besides, it is assumed that the counter is stored in the last + * 2 bytes of the nonce. + */ +static int ccm_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched) +{ + + uint8_t buffer[TC_AES_BLOCK_SIZE]; + uint8_t nonce[TC_AES_BLOCK_SIZE]; + uint16_t block_num; + unsigned int i; + + /* input sanity check: */ + if (out == (uint8_t *) 0 || + in == (uint8_t *) 0 || + ctr == (uint8_t *) 0 || + sched == (TCAesKeySched_t) 0 || + inlen == 0 || + outlen == 0 || + outlen != inlen) { + return TC_CRYPTO_FAIL; + } + + /* copy the counter to the nonce */ + (void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce)); + + /* select the last 2 bytes of the nonce to be incremented */ + block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15])); + for (i = 0; i < inlen; ++i) { + if ((i % (TC_AES_BLOCK_SIZE)) == 0) { + block_num++; + nonce[14] = (uint8_t)(block_num >> 8); + nonce[15] = (uint8_t)(block_num); + if (!tc_aes_encrypt(buffer, nonce, sched)) { + return TC_CRYPTO_FAIL; + } + } + /* update the output */ + *out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++; + } + + /* update the counter */ + ctr[14] = nonce[14]; ctr[15] = nonce[15]; + + return TC_CRYPTO_SUCCESS; +} + +int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen, + const uint8_t *associated_data, + unsigned int alen, const uint8_t *payload, + unsigned int plen, TCCcmMode_t c) +{ + + /* input sanity check: */ + if ((out == (uint8_t *) 0) || + (c == (TCCcmMode_t) 0) || + ((plen > 0) && (payload == (uint8_t *) 0)) || + ((alen > 0) && (associated_data == (uint8_t *) 0)) || + (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */ + (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */ + (olen < (plen + c->mlen))) { /* invalid output buffer size */ + return TC_CRYPTO_FAIL; + } + + uint8_t b[Nb * Nk]; + uint8_t tag[Nb * Nk]; + unsigned int i; + + /* GENERATING THE AUTHENTICATION TAG: */ + + /* formatting the sequence b for authentication: */ + b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1); + for (i = 1; i <= 13; ++i) { + b[i] = c->nonce[i - 1]; + } + b[14] = (uint8_t)(plen >> 8); + b[15] = (uint8_t)(plen); + + /* computing the authentication tag using cbc-mac: */ + (void) tc_aes_encrypt(tag, b, c->sched); + if (alen > 0) { + ccm_cbc_mac(tag, associated_data, alen, 1, c->sched); + } + if (plen > 0) { + ccm_cbc_mac(tag, payload, plen, 0, c->sched); + } + + /* ENCRYPTION: */ + + /* formatting the sequence b for encryption: */ + b[0] = 1; /* q - 1 = 2 - 1 = 1 */ + b[14] = b[15] = TC_ZERO_BYTE; + + /* encrypting payload using ctr mode: */ + ccm_ctr_mode(out, plen, payload, plen, b, c->sched); + + b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/ + + /* encrypting b and adding the tag to the output: */ + (void) tc_aes_encrypt(b, b, c->sched); + out += plen; + for (i = 0; i < c->mlen; ++i) { + *out++ = tag[i] ^ b[i]; + } + + return TC_CRYPTO_SUCCESS; +} + +int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen, + const uint8_t *associated_data, + unsigned int alen, const uint8_t *payload, + unsigned int plen, TCCcmMode_t c) +{ + + /* input sanity check: */ + if ((out == (uint8_t *) 0) || + (c == (TCCcmMode_t) 0) || + ((plen > 0) && (payload == (uint8_t *) 0)) || + ((alen > 0) && (associated_data == (uint8_t *) 0)) || + (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */ + (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */ + (olen < plen - c->mlen)) { /* invalid output buffer size */ + return TC_CRYPTO_FAIL; + } + + uint8_t b[Nb * Nk]; + uint8_t tag[Nb * Nk]; + unsigned int i; + + /* DECRYPTION: */ + + /* formatting the sequence b for decryption: */ + b[0] = 1; /* q - 1 = 2 - 1 = 1 */ + for (i = 1; i < 14; ++i) { + b[i] = c->nonce[i - 1]; + } + b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */ + + /* decrypting payload using ctr mode: */ + ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched); + + b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */ + + /* encrypting b and restoring the tag from input: */ + (void) tc_aes_encrypt(b, b, c->sched); + for (i = 0; i < c->mlen; ++i) { + tag[i] = *(payload + plen - c->mlen + i) ^ b[i]; + } + + /* VERIFYING THE AUTHENTICATION TAG: */ + + /* formatting the sequence b for authentication: */ + b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1); + for (i = 1; i < 14; ++i) { + b[i] = c->nonce[i - 1]; + } + b[14] = (uint8_t)((plen - c->mlen) >> 8); + b[15] = (uint8_t)(plen - c->mlen); + + /* computing the authentication tag using cbc-mac: */ + (void) tc_aes_encrypt(b, b, c->sched); + if (alen > 0) { + ccm_cbc_mac(b, associated_data, alen, 1, c->sched); + } + if (plen > 0) { + ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched); + } + + /* comparing the received tag and the computed one: */ + if (_compare(b, tag, c->mlen) == 0) { + return TC_CRYPTO_SUCCESS; + } else { + /* erase the decrypted buffer in case of mac validation failure: */ + _set(out, 0, plen - c->mlen); + return TC_CRYPTO_FAIL; + } +} diff --git a/tinycrypt/lib/source/cmac_mode.c b/tinycrypt/lib/source/cmac_mode.c new file mode 100644 index 00000000..22adf208 --- /dev/null +++ b/tinycrypt/lib/source/cmac_mode.c @@ -0,0 +1,254 @@ +/* cmac_mode.c - TinyCrypt CMAC mode implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include +#include + +/* max number of calls until change the key (2^48).*/ +static const uint64_t MAX_CALLS = ((uint64_t)1 << 48); + +/* + * gf_wrap -- In our implementation, GF(2^128) is represented as a 16 byte + * array with byte 0 the most significant and byte 15 the least significant. + * High bit carry reduction is based on the primitive polynomial + * + * X^128 + X^7 + X^2 + X + 1, + * + * which leads to the reduction formula X^128 = X^7 + X^2 + X + 1. Indeed, + * since 0 = (X^128 + X^7 + X^2 + 1) mod (X^128 + X^7 + X^2 + X + 1) and since + * addition of polynomials with coefficients in Z/Z(2) is just XOR, we can + * add X^128 to both sides to get + * + * X^128 = (X^7 + X^2 + X + 1) mod (X^128 + X^7 + X^2 + X + 1) + * + * and the coefficients of the polynomial on the right hand side form the + * string 1000 0111 = 0x87, which is the value of gf_wrap. + * + * This gets used in the following way. Doubling in GF(2^128) is just a left + * shift by 1 bit, except when the most significant bit is 1. In the latter + * case, the relation X^128 = X^7 + X^2 + X + 1 says that the high order bit + * that overflows beyond 128 bits can be replaced by addition of + * X^7 + X^2 + X + 1 <--> 0x87 to the low order 128 bits. Since addition + * in GF(2^128) is represented by XOR, we therefore only have to XOR 0x87 + * into the low order byte after a left shift when the starting high order + * bit is 1. + */ +const unsigned char gf_wrap = 0x87; + +/* + * assumes: out != NULL and points to a GF(2^n) value to receive the + * doubled value; + * in != NULL and points to a 16 byte GF(2^n) value + * to double; + * the in and out buffers do not overlap. + * effects: doubles the GF(2^n) value pointed to by "in" and places + * the result in the GF(2^n) value pointed to by "out." + */ +void gf_double(uint8_t *out, uint8_t *in) +{ + + /* start with low order byte */ + uint8_t *x = in + (TC_AES_BLOCK_SIZE - 1); + + /* if msb == 1, we need to add the gf_wrap value, otherwise add 0 */ + uint8_t carry = (in[0] >> 7) ? gf_wrap : 0; + + out += (TC_AES_BLOCK_SIZE - 1); + for (;;) { + *out-- = (*x << 1) ^ carry; + if (x == in) { + break; + } + carry = *x-- >> 7; + } +} + +int tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched) +{ + + /* input sanity check: */ + if (s == (TCCmacState_t) 0 || + key == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } + + /* put s into a known state */ + _set(s, 0, sizeof(*s)); + s->sched = sched; + + /* configure the encryption key used by the underlying block cipher */ + tc_aes128_set_encrypt_key(s->sched, key); + + /* compute s->K1 and s->K2 from s->iv using s->keyid */ + _set(s->iv, 0, TC_AES_BLOCK_SIZE); + tc_aes_encrypt(s->iv, s->iv, s->sched); + gf_double (s->K1, s->iv); + gf_double (s->K2, s->K1); + + /* reset s->iv to 0 in case someone wants to compute now */ + tc_cmac_init(s); + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_erase(TCCmacState_t s) +{ + if (s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + /* destroy the current state */ + _set(s, 0, sizeof(*s)); + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_init(TCCmacState_t s) +{ + /* input sanity check: */ + if (s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + /* CMAC starts with an all zero initialization vector */ + _set(s->iv, 0, TC_AES_BLOCK_SIZE); + + /* and the leftover buffer is empty */ + _set(s->leftover, 0, TC_AES_BLOCK_SIZE); + s->leftover_offset = 0; + + /* Set countdown to max number of calls allowed before re-keying: */ + s->countdown = MAX_CALLS; + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length) +{ + unsigned int i; + + /* input sanity check: */ + if (s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + if (data_length == 0) { + return TC_CRYPTO_SUCCESS; + } + if (data == (const uint8_t *) 0) { + return TC_CRYPTO_FAIL; + } + + if (s->countdown == 0) { + return TC_CRYPTO_FAIL; + } + + s->countdown--; + + if (s->leftover_offset > 0) { + /* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */ + size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset; + + if (data_length < remaining_space) { + /* still not enough data to encrypt this time either */ + _copy(&s->leftover[s->leftover_offset], data_length, data, data_length); + s->leftover_offset += data_length; + return TC_CRYPTO_SUCCESS; + } + /* leftover block is now full; encrypt it first */ + _copy(&s->leftover[s->leftover_offset], + remaining_space, + data, + remaining_space); + data_length -= remaining_space; + data += remaining_space; + s->leftover_offset = 0; + + for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { + s->iv[i] ^= s->leftover[i]; + } + tc_aes_encrypt(s->iv, s->iv, s->sched); + } + + /* CBC encrypt each (except the last) of the data blocks */ + while (data_length > TC_AES_BLOCK_SIZE) { + for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { + s->iv[i] ^= data[i]; + } + tc_aes_encrypt(s->iv, s->iv, s->sched); + data += TC_AES_BLOCK_SIZE; + data_length -= TC_AES_BLOCK_SIZE; + } + + if (data_length > 0) { + /* save leftover data for next time */ + _copy(s->leftover, data_length, data, data_length); + s->leftover_offset = data_length; + } + + return TC_CRYPTO_SUCCESS; +} + +int tc_cmac_final(uint8_t *tag, TCCmacState_t s) +{ + uint8_t *k; + unsigned int i; + + /* input sanity check: */ + if (tag == (uint8_t *) 0 || + s == (TCCmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + if (s->leftover_offset == TC_AES_BLOCK_SIZE) { + /* the last message block is a full-sized block */ + k = (uint8_t *) s->K1; + } else { + /* the final message block is not a full-sized block */ + size_t remaining = TC_AES_BLOCK_SIZE - s->leftover_offset; + + _set(&s->leftover[s->leftover_offset], 0, remaining); + s->leftover[s->leftover_offset] = TC_CMAC_PADDING; + k = (uint8_t *) s->K2; + } + for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) { + s->iv[i] ^= s->leftover[i] ^ k[i]; + } + + tc_aes_encrypt(tag, s->iv, s->sched); + + /* erasing state: */ + tc_cmac_erase(s); + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/ctr_mode.c b/tinycrypt/lib/source/ctr_mode.c new file mode 100644 index 00000000..1dfb92df --- /dev/null +++ b/tinycrypt/lib/source/ctr_mode.c @@ -0,0 +1,85 @@ +/* ctr_mode.c - TinyCrypt CTR mode implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +int tc_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in, + unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched) +{ + + uint8_t buffer[TC_AES_BLOCK_SIZE]; + uint8_t nonce[TC_AES_BLOCK_SIZE]; + unsigned int block_num; + unsigned int i; + + /* input sanity check: */ + if (out == (uint8_t *) 0 || + in == (uint8_t *) 0 || + ctr == (uint8_t *) 0 || + sched == (TCAesKeySched_t) 0 || + inlen == 0 || + outlen == 0 || + outlen != inlen) { + return TC_CRYPTO_FAIL; + } + + /* copy the ctr to the nonce */ + (void)_copy(nonce, sizeof(nonce), ctr, sizeof(nonce)); + + /* select the last 4 bytes of the nonce to be incremented */ + block_num = (nonce[12] << 24) | (nonce[13] << 16) | + (nonce[14] << 8) | (nonce[15]); + for (i = 0; i < inlen; ++i) { + if ((i % (TC_AES_BLOCK_SIZE)) == 0) { + /* encrypt data using the current nonce */ + if (tc_aes_encrypt(buffer, nonce, sched)) { + block_num++; + nonce[12] = (uint8_t)(block_num >> 24); + nonce[13] = (uint8_t)(block_num >> 16); + nonce[14] = (uint8_t)(block_num >> 8); + nonce[15] = (uint8_t)(block_num); + } else { + return TC_CRYPTO_FAIL; + } + } + /* update the output */ + *out++ = buffer[i%(TC_AES_BLOCK_SIZE)] ^ *in++; + } + + /* update the counter */ + ctr[12] = nonce[12]; ctr[13] = nonce[13]; + ctr[14] = nonce[14]; ctr[15] = nonce[15]; + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/ctr_prng.c b/tinycrypt/lib/source/ctr_prng.c new file mode 100644 index 00000000..cac2cc41 --- /dev/null +++ b/tinycrypt/lib/source/ctr_prng.c @@ -0,0 +1,283 @@ +/* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */ + +/* + * Copyright (c) 2016, Chris Morrison + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 +#include +#include +#include + +/* + * This PRNG is based on the CTR_DRBG described in Recommendation for Random + * Number Generation Using Deterministic Random Bit Generators, + * NIST SP 800-90A Rev. 1. + * + * Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps + * described in that document. + * + */ + +/** + * @brief Array incrementer + * Treats the supplied array as one contiguous number (MSB in arr[0]), and + * increments it by one + * @return none + * @param arr IN/OUT -- array to be incremented + * @param len IN -- size of arr in bytes + */ +static void arrInc(uint8_t arr[], unsigned int len) +{ + unsigned int i; + if (0 != arr) { + for (i = len; i > 0U; i--) { + if (++arr[i-1] != 0U) { + break; + } + } + } +} + +/** + * @brief CTR PRNG update + * Updates the internal state of supplied the CTR PRNG context + * increments it by one + * @return none + * @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long + * @param ctx IN/OUT -- CTR PRNG state + * @param providedData IN -- data used when updating the internal state + */ +static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData) +{ + if (0 != ctx) { + /* 10.2.1.2 step 1 */ + uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; + unsigned int len = 0U; + + /* 10.2.1.2 step 2 */ + while (len < sizeof temp) { + unsigned int blocklen = sizeof(temp) - len; + uint8_t output_block[TC_AES_BLOCK_SIZE]; + + /* 10.2.1.2 step 2.1 */ + arrInc(ctx->V, sizeof ctx->V); + + /* 10.2.1.2 step 2.2 */ + if (blocklen > TC_AES_BLOCK_SIZE) { + blocklen = TC_AES_BLOCK_SIZE; + } + (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key); + + /* 10.2.1.2 step 2.3/step 3 */ + memcpy(&(temp[len]), output_block, blocklen); + + len += blocklen; + } + + /* 10.2.1.2 step 4 */ + if (0 != providedData) { + unsigned int i; + for (i = 0U; i < sizeof temp; i++) { + temp[i] ^= providedData[i]; + } + } + + /* 10.2.1.2 step 5 */ + (void)tc_aes128_set_encrypt_key(&ctx->key, temp); + + /* 10.2.1.2 step 6 */ + memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE); + } +} + +int tc_ctr_prng_init(TCCtrPrng_t * const ctx, + uint8_t const * const entropy, + unsigned int entropyLen, + uint8_t const * const personalization, + unsigned int pLen) +{ + int result = TC_CRYPTO_FAIL; + unsigned int i; + uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; + uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; + uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U}; + + if (0 != personalization) { + /* 10.2.1.3.1 step 1 */ + unsigned int len = pLen; + if (len > sizeof personalization_buf) { + len = sizeof personalization_buf; + } + + /* 10.2.1.3.1 step 2 */ + memcpy(personalization_buf, personalization, len); + } + + if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) { + /* 10.2.1.3.1 step 3 */ + memcpy(seed_material, entropy, sizeof seed_material); + for (i = 0U; i < sizeof seed_material; i++) { + seed_material[i] ^= personalization_buf[i]; + } + + /* 10.2.1.3.1 step 4 */ + (void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr); + + /* 10.2.1.3.1 step 5 */ + memset(ctx->V, 0x00, sizeof ctx->V); + + /* 10.2.1.3.1 step 6 */ + tc_ctr_prng_update(ctx, seed_material); + + /* 10.2.1.3.1 step 7 */ + ctx->reseedCount = 1U; + + result = TC_CRYPTO_SUCCESS; + } + return result; +} + +int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx, + uint8_t const * const entropy, + unsigned int entropyLen, + uint8_t const * const additional_input, + unsigned int additionallen) +{ + unsigned int i; + int result = TC_CRYPTO_FAIL; + uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; + uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; + + if (0 != additional_input) { + /* 10.2.1.4.1 step 1 */ + unsigned int len = additionallen; + if (len > sizeof additional_input_buf) { + len = sizeof additional_input_buf; + } + + /* 10.2.1.4.1 step 2 */ + memcpy(additional_input_buf, additional_input, len); + } + + unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE; + if ((0 != ctx) && (entropyLen >= seedlen)) { + /* 10.2.1.4.1 step 3 */ + memcpy(seed_material, entropy, sizeof seed_material); + for (i = 0U; i < sizeof seed_material; i++) { + seed_material[i] ^= additional_input_buf[i]; + } + + /* 10.2.1.4.1 step 4 */ + tc_ctr_prng_update(ctx, seed_material); + + /* 10.2.1.4.1 step 5 */ + ctx->reseedCount = 1U; + + result = TC_CRYPTO_SUCCESS; + } + return result; +} + +int tc_ctr_prng_generate(TCCtrPrng_t * const ctx, + uint8_t const * const additional_input, + unsigned int additionallen, + uint8_t * const out, + unsigned int outlen) +{ + /* 2^48 - see section 10.2.1 */ + static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL; + + /* 2^19 bits - see section 10.2.1 */ + static const unsigned int MAX_BYTES_PER_REQ = 65536U; + + unsigned int result = TC_CRYPTO_FAIL; + + if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) { + /* 10.2.1.5.1 step 1 */ + if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) { + result = TC_CTR_PRNG_RESEED_REQ; + } else { + uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; + if (0 != additional_input) { + /* 10.2.1.5.1 step 2 */ + unsigned int len = additionallen; + if (len > sizeof additional_input_buf) { + len = sizeof additional_input_buf; + } + memcpy(additional_input_buf, additional_input, len); + tc_ctr_prng_update(ctx, additional_input_buf); + } + + /* 10.2.1.5.1 step 3 - implicit */ + + /* 10.2.1.5.1 step 4 */ + unsigned int len = 0U; + while (len < outlen) { + unsigned int blocklen = outlen - len; + uint8_t output_block[TC_AES_BLOCK_SIZE]; + + /* 10.2.1.5.1 step 4.1 */ + arrInc(ctx->V, sizeof ctx->V); + + /* 10.2.1.5.1 step 4.2 */ + (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key); + + /* 10.2.1.5.1 step 4.3/step 5 */ + if (blocklen > TC_AES_BLOCK_SIZE) { + blocklen = TC_AES_BLOCK_SIZE; + } + memcpy(&(out[len]), output_block, blocklen); + + len += blocklen; + } + + /* 10.2.1.5.1 step 6 */ + tc_ctr_prng_update(ctx, additional_input_buf); + + /* 10.2.1.5.1 step 7 */ + ctx->reseedCount++; + + /* 10.2.1.5.1 step 8 */ + result = TC_CRYPTO_SUCCESS; + } + } + + return result; +} + +void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx) +{ + if (0 != ctx) { + memset(ctx->key.words, 0x00, sizeof ctx->key.words); + memset(ctx->V, 0x00, sizeof ctx->V); + ctx->reseedCount = 0U; + } +} + + + + diff --git a/tinycrypt/lib/source/ecc.c b/tinycrypt/lib/source/ecc.c new file mode 100644 index 00000000..46080bf6 --- /dev/null +++ b/tinycrypt/lib/source/ecc.c @@ -0,0 +1,942 @@ +/* ecc.c - TinyCrypt implementation of common ECC functions */ + +/* + * Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +/* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform + * has access to enough entropy in order to feed the PRNG regularly. */ +#if default_RNG_defined +static uECC_RNG_Function g_rng_function = &default_CSPRNG; +#else +static uECC_RNG_Function g_rng_function = 0; +#endif + +void uECC_set_rng(uECC_RNG_Function rng_function) +{ + g_rng_function = rng_function; +} + +uECC_RNG_Function uECC_get_rng(void) +{ + return g_rng_function; +} + +int uECC_curve_private_key_size(uECC_Curve curve) +{ + return BITS_TO_BYTES(curve->num_n_bits); +} + +int uECC_curve_public_key_size(uECC_Curve curve) +{ + return 2 * curve->num_bytes; +} + +void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) +{ + wordcount_t i; + for (i = 0; i < num_words; ++i) { + vli[i] = 0; + } +} + +uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) +{ + uECC_word_t bits = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + bits |= vli[i]; + } + return (bits == 0); +} + +uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) +{ + return (vli[bit >> uECC_WORD_BITS_SHIFT] & + ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); +} + +/* Counts the number of words in vli. */ +static wordcount_t vli_numDigits(const uECC_word_t *vli, + const wordcount_t max_words) +{ + + wordcount_t i; + /* Search from the end until we find a non-zero digit. We do it in reverse + * because we expect that most digits will be nonzero. */ + for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { + } + + return (i + 1); +} + +bitcount_t uECC_vli_numBits(const uECC_word_t *vli, + const wordcount_t max_words) +{ + + uECC_word_t i; + uECC_word_t digit; + + wordcount_t num_digits = vli_numDigits(vli, max_words); + if (num_digits == 0) { + return 0; + } + + digit = vli[num_digits - 1]; + for (i = 0; digit; ++i) { + digit >>= 1; + } + + return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); +} + +void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, + wordcount_t num_words) +{ + wordcount_t i; + + for (i = 0; i < num_words; ++i) { + dest[i] = src[i]; + } +} + +cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, + const uECC_word_t *right, + wordcount_t num_words) +{ + wordcount_t i; + + for (i = num_words - 1; i >= 0; --i) { + if (left[i] > right[i]) { + return 1; + } else if (left[i] < right[i]) { + return -1; + } + } + return 0; +} + +uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right, + wordcount_t num_words) +{ + + uECC_word_t diff = 0; + wordcount_t i; + + for (i = num_words - 1; i >= 0; --i) { + diff |= (left[i] ^ right[i]); + } + return !(diff == 0); +} + +uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond) +{ + return (p_true*(cond)) | (p_false*(!cond)); +} + +/* Computes result = left - right, returning borrow, in constant time. + * Can modify in place. */ +uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, wordcount_t num_words) +{ + uECC_word_t borrow = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + uECC_word_t diff = left[i] - right[i] - borrow; + uECC_word_t val = (diff > left[i]); + borrow = cond_set(val, borrow, (diff != left[i])); + + result[i] = diff; + } + return borrow; +} + +/* Computes result = left + right, returning carry, in constant time. + * Can modify in place. */ +static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, wordcount_t num_words) +{ + uECC_word_t carry = 0; + wordcount_t i; + for (i = 0; i < num_words; ++i) { + uECC_word_t sum = left[i] + right[i] + carry; + uECC_word_t val = (sum < left[i]); + carry = cond_set(val, carry, (sum != left[i])); + result[i] = sum; + } + return carry; +} + +cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, + wordcount_t num_words) +{ + uECC_word_t tmp[NUM_ECC_WORDS]; + uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); + uECC_word_t equal = uECC_vli_isZero(tmp, num_words); + return (!equal - 2 * neg); +} + +/* Computes vli = vli >> 1. */ +static void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) +{ + uECC_word_t *end = vli; + uECC_word_t carry = 0; + + vli += num_words; + while (vli-- > end) { + uECC_word_t temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << (uECC_WORD_BITS - 1); + } +} + +static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0, + uECC_word_t *r1, uECC_word_t *r2) +{ + + uECC_dword_t p = (uECC_dword_t)a * b; + uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; + r01 += p; + *r2 += (r01 < p); + *r1 = r01 >> uECC_WORD_BITS; + *r0 = (uECC_word_t)r01; + +} + +/* Computes result = left * right. Result must be 2 * num_words long. */ +static void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, wordcount_t num_words) +{ + + uECC_word_t r0 = 0; + uECC_word_t r1 = 0; + uECC_word_t r2 = 0; + wordcount_t i, k; + + /* Compute each digit of result in sequence, maintaining the carries. */ + for (k = 0; k < num_words; ++k) { + + for (i = 0; i <= k; ++i) { + muladd(left[i], right[k - i], &r0, &r1, &r2); + } + + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + + for (k = num_words; k < num_words * 2 - 1; ++k) { + + for (i = (k + 1) - num_words; i < num_words; ++i) { + muladd(left[i], right[k - i], &r0, &r1, &r2); + } + result[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + result[num_words * 2 - 1] = r0; +} + +void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, const uECC_word_t *mod, + wordcount_t num_words) +{ + uECC_word_t carry = uECC_vli_add(result, left, right, num_words); + if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { + /* result > mod (result = mod + remainder), so subtract mod to get + * remainder. */ + uECC_vli_sub(result, result, mod, num_words); + } +} + +void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, const uECC_word_t *mod, + wordcount_t num_words) +{ + uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); + if (l_borrow) { + /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, + * we can get the correct result from result + mod (with overflow). */ + uECC_vli_add(result, result, mod, num_words); + } +} + +/* Computes result = product % mod, where product is 2N words long. */ +/* Currently only designed to work for curve_p or curve_n. */ +void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product, + const uECC_word_t *mod, wordcount_t num_words) +{ + uECC_word_t mod_multiple[2 * NUM_ECC_WORDS]; + uECC_word_t tmp[2 * NUM_ECC_WORDS]; + uECC_word_t *v[2] = {tmp, product}; + uECC_word_t index; + + /* Shift mod so its highest set bit is at the maximum position. */ + bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - + uECC_vli_numBits(mod, num_words); + wordcount_t word_shift = shift / uECC_WORD_BITS; + wordcount_t bit_shift = shift % uECC_WORD_BITS; + uECC_word_t carry = 0; + uECC_vli_clear(mod_multiple, word_shift); + if (bit_shift > 0) { + for(index = 0; index < (uECC_word_t)num_words; ++index) { + mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; + carry = mod[index] >> (uECC_WORD_BITS - bit_shift); + } + } else { + uECC_vli_set(mod_multiple + word_shift, mod, num_words); + } + + for (index = 1; shift >= 0; --shift) { + uECC_word_t borrow = 0; + wordcount_t i; + for (i = 0; i < num_words * 2; ++i) { + uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; + if (diff != v[index][i]) { + borrow = (diff > v[index][i]); + } + v[1 - index][i] = diff; + } + /* Swap the index if there was no borrow */ + index = !(index ^ borrow); + uECC_vli_rshift1(mod_multiple, num_words); + mod_multiple[num_words - 1] |= mod_multiple[num_words] << + (uECC_WORD_BITS - 1); + uECC_vli_rshift1(mod_multiple + num_words, num_words); + } + uECC_vli_set(result, v[index], num_words); +} + +void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, const uECC_word_t *mod, + wordcount_t num_words) +{ + uECC_word_t product[2 * NUM_ECC_WORDS]; + uECC_vli_mult(product, left, right, num_words); + uECC_vli_mmod(result, product, mod, num_words); +} + +void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left, + const uECC_word_t *right, uECC_Curve curve) +{ + uECC_word_t product[2 * NUM_ECC_WORDS]; + uECC_vli_mult(product, left, right, curve->num_words); + + curve->mmod_fast(result, product); +} + +static void uECC_vli_modSquare_fast(uECC_word_t *result, + const uECC_word_t *left, + uECC_Curve curve) +{ + uECC_vli_modMult_fast(result, left, left, curve); +} + + +#define EVEN(vli) (!(vli[0] & 1)) + +static void vli_modInv_update(uECC_word_t *uv, + const uECC_word_t *mod, + wordcount_t num_words) +{ + + uECC_word_t carry = 0; + + if (!EVEN(uv)) { + carry = uECC_vli_add(uv, uv, mod, num_words); + } + uECC_vli_rshift1(uv, num_words); + if (carry) { + uv[num_words - 1] |= HIGH_BIT_SET; + } +} + +void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input, + const uECC_word_t *mod, wordcount_t num_words) +{ + uECC_word_t a[NUM_ECC_WORDS], b[NUM_ECC_WORDS]; + uECC_word_t u[NUM_ECC_WORDS], v[NUM_ECC_WORDS]; + cmpresult_t cmpResult; + + if (uECC_vli_isZero(input, num_words)) { + uECC_vli_clear(result, num_words); + return; + } + + uECC_vli_set(a, input, num_words); + uECC_vli_set(b, mod, num_words); + uECC_vli_clear(u, num_words); + u[0] = 1; + uECC_vli_clear(v, num_words); + while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { + if (EVEN(a)) { + uECC_vli_rshift1(a, num_words); + vli_modInv_update(u, mod, num_words); + } else if (EVEN(b)) { + uECC_vli_rshift1(b, num_words); + vli_modInv_update(v, mod, num_words); + } else if (cmpResult > 0) { + uECC_vli_sub(a, a, b, num_words); + uECC_vli_rshift1(a, num_words); + if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { + uECC_vli_add(u, u, mod, num_words); + } + uECC_vli_sub(u, u, v, num_words); + vli_modInv_update(u, mod, num_words); + } else { + uECC_vli_sub(b, b, a, num_words); + uECC_vli_rshift1(b, num_words); + if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { + uECC_vli_add(v, v, mod, num_words); + } + uECC_vli_sub(v, v, u, num_words); + vli_modInv_update(v, mod, num_words); + } + } + uECC_vli_set(result, u, num_words); +} + +/* ------ Point operations ------ */ + +void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1, + uECC_word_t * Z1, uECC_Curve curve) +{ + /* t1 = X, t2 = Y, t3 = Z */ + uECC_word_t t4[NUM_ECC_WORDS]; + uECC_word_t t5[NUM_ECC_WORDS]; + wordcount_t num_words = curve->num_words; + + if (uECC_vli_isZero(Z1, num_words)) { + return; + } + + uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ + uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ + uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ + uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ + uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ + + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ + uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ + uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ + uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ + + uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ + uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ + if (uECC_vli_testBit(X1, 0)) { + uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); + uECC_vli_rshift1(X1, num_words); + X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); + } else { + uECC_vli_rshift1(X1, num_words); + } + + /* t1 = 3/2*(x1^2 - z1^4) = B */ + uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ + uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ + uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ + /* t4 = B * (A - x3) - y1^4 = y3: */ + uECC_vli_modSub(t4, X1, t4, curve->p, num_words); + + uECC_vli_set(X1, Z1, num_words); + uECC_vli_set(Z1, Y1, num_words); + uECC_vli_set(Y1, t4, num_words); +} + +void x_side_default(uECC_word_t *result, + const uECC_word_t *x, + uECC_Curve curve) +{ + uECC_word_t _3[NUM_ECC_WORDS] = {3}; /* -a = 3 */ + wordcount_t num_words = curve->num_words; + + uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ + uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ + uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ + /* r = x^3 - 3x + b: */ + uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); +} + +uECC_Curve uECC_secp256r1(void) +{ + return &curve_secp256r1; +} + +void vli_mmod_fast_secp256r1(unsigned int *result, unsigned int*product) +{ + unsigned int tmp[NUM_ECC_WORDS]; + int carry; + + /* t */ + uECC_vli_set(result, product, NUM_ECC_WORDS); + + /* s1 */ + tmp[0] = tmp[1] = tmp[2] = 0; + tmp[3] = product[11]; + tmp[4] = product[12]; + tmp[5] = product[13]; + tmp[6] = product[14]; + tmp[7] = product[15]; + carry = uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS); + carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); + + /* s2 */ + tmp[3] = product[12]; + tmp[4] = product[13]; + tmp[5] = product[14]; + tmp[6] = product[15]; + tmp[7] = 0; + carry += uECC_vli_add(tmp, tmp, tmp, NUM_ECC_WORDS); + carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); + + /* s3 */ + tmp[0] = product[8]; + tmp[1] = product[9]; + tmp[2] = product[10]; + tmp[3] = tmp[4] = tmp[5] = 0; + tmp[6] = product[14]; + tmp[7] = product[15]; + carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); + + /* s4 */ + tmp[0] = product[9]; + tmp[1] = product[10]; + tmp[2] = product[11]; + tmp[3] = product[13]; + tmp[4] = product[14]; + tmp[5] = product[15]; + tmp[6] = product[13]; + tmp[7] = product[8]; + carry += uECC_vli_add(result, result, tmp, NUM_ECC_WORDS); + + /* d1 */ + tmp[0] = product[11]; + tmp[1] = product[12]; + tmp[2] = product[13]; + tmp[3] = tmp[4] = tmp[5] = 0; + tmp[6] = product[8]; + tmp[7] = product[10]; + carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); + + /* d2 */ + tmp[0] = product[12]; + tmp[1] = product[13]; + tmp[2] = product[14]; + tmp[3] = product[15]; + tmp[4] = tmp[5] = 0; + tmp[6] = product[9]; + tmp[7] = product[11]; + carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); + + /* d3 */ + tmp[0] = product[13]; + tmp[1] = product[14]; + tmp[2] = product[15]; + tmp[3] = product[8]; + tmp[4] = product[9]; + tmp[5] = product[10]; + tmp[6] = 0; + tmp[7] = product[12]; + carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); + + /* d4 */ + tmp[0] = product[14]; + tmp[1] = product[15]; + tmp[2] = 0; + tmp[3] = product[9]; + tmp[4] = product[10]; + tmp[5] = product[11]; + tmp[6] = 0; + tmp[7] = product[13]; + carry -= uECC_vli_sub(result, result, tmp, NUM_ECC_WORDS); + + if (carry < 0) { + do { + carry += uECC_vli_add(result, result, curve_secp256r1.p, NUM_ECC_WORDS); + } + while (carry < 0); + } else { + while (carry || + uECC_vli_cmp_unsafe(curve_secp256r1.p, result, NUM_ECC_WORDS) != 1) { + carry -= uECC_vli_sub(result, result, curve_secp256r1.p, NUM_ECC_WORDS); + } + } +} + +uECC_word_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve) +{ + return uECC_vli_isZero(point, curve->num_words * 2); +} + +void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, + uECC_Curve curve) +{ + uECC_word_t t1[NUM_ECC_WORDS]; + + uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ + uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ + uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ + uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ +} + +/* P = (x1, y1) => 2P, (x2, y2) => P' */ +static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1, + uECC_word_t * X2, uECC_word_t * Y2, + const uECC_word_t * const initial_Z, + uECC_Curve curve) +{ + uECC_word_t z[NUM_ECC_WORDS]; + wordcount_t num_words = curve->num_words; + if (initial_Z) { + uECC_vli_set(z, initial_Z, num_words); + } else { + uECC_vli_clear(z, num_words); + z[0] = 1; + } + + uECC_vli_set(X2, X1, num_words); + uECC_vli_set(Y2, Y1, num_words); + + apply_z(X1, Y1, z, curve); + curve->double_jacobian(X1, Y1, z, curve); + apply_z(X2, Y2, z, curve); +} + +void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, + uECC_word_t * X2, uECC_word_t * Y2, + uECC_Curve curve) +{ + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uECC_word_t t5[NUM_ECC_WORDS]; + wordcount_t num_words = curve->num_words; + + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ + + uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ + uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ + uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ + uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ + uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ + uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ + + uECC_vli_set(X2, t5, num_words); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) + or P => P - Q, Q => P + Q + */ +static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1, + uECC_word_t * X2, uECC_word_t * Y2, + uECC_Curve curve) +{ + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + uECC_word_t t5[NUM_ECC_WORDS]; + uECC_word_t t6[NUM_ECC_WORDS]; + uECC_word_t t7[NUM_ECC_WORDS]; + wordcount_t num_words = curve->num_words; + + uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ + uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ + uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ + uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ + uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ + + uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ + uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ + uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ + uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ + uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ + + uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ + uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ + /* t4 = (y2 - y1)*(B - x3) - E = y3: */ + uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); + + uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ + uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ + uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ + uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ + /* t2 = (y2+y1)*(x3' - B) - E = y3': */ + uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); + + uECC_vli_set(X1, t7, num_words); +} + +void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, + const uECC_word_t * scalar, + const uECC_word_t * initial_Z, + bitcount_t num_bits, uECC_Curve curve) +{ + /* R0 and R1 */ + uECC_word_t Rx[2][NUM_ECC_WORDS]; + uECC_word_t Ry[2][NUM_ECC_WORDS]; + uECC_word_t z[NUM_ECC_WORDS]; + bitcount_t i; + uECC_word_t nb; + wordcount_t num_words = curve->num_words; + + uECC_vli_set(Rx[1], point, num_words); + uECC_vli_set(Ry[1], point + num_words, num_words); + + XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); + + for (i = num_bits - 2; i > 0; --i) { + nb = !uECC_vli_testBit(scalar, i); + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + } + + nb = !uECC_vli_testBit(scalar, 0); + XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); + + /* Find final 1/Z value. */ + uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ + uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ + uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ + uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0))*/ + /* yP / (xP * Yb * (X1 - X0)) */ + uECC_vli_modMult_fast(z, z, point + num_words, curve); + /* Xb * yP / (xP * Yb * (X1 - X0)) */ + uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); + /* End 1/Z calculation */ + + XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); + apply_z(Rx[0], Ry[0], z, curve); + + uECC_vli_set(result, Rx[0], num_words); + uECC_vli_set(result + num_words, Ry[0], num_words); +} + +uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, + uECC_word_t *k1, uECC_Curve curve) +{ + + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + + bitcount_t num_n_bits = curve->num_n_bits; + + uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || + (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && + uECC_vli_testBit(k0, num_n_bits)); + + uECC_vli_add(k1, k0, curve->n, num_n_words); + + return carry; +} + +uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, + uECC_word_t *private_key, + uECC_Curve curve) +{ + + uECC_word_t tmp1[NUM_ECC_WORDS]; + uECC_word_t tmp2[NUM_ECC_WORDS]; + uECC_word_t *p2[2] = {tmp1, tmp2}; + uECC_word_t carry; + + /* Regularize the bitcount for the private key so that attackers cannot + * use a side channel attack to learn the number of leading zeros. */ + carry = regularize_k(private_key, tmp1, tmp2, curve); + + EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve); + + if (EccPoint_isZero(result, curve)) { + return 0; + } + return 1; +} + +/* Converts an integer in uECC native format to big-endian bytes. */ +void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, + const unsigned int *native) +{ + wordcount_t i; + for (i = 0; i < num_bytes; ++i) { + unsigned b = num_bytes - 1 - i; + bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); + } +} + +/* Converts big-endian bytes to an integer in uECC native format. */ +void uECC_vli_bytesToNative(unsigned int *native, const uint8_t *bytes, + int num_bytes) +{ + wordcount_t i; + uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); + for (i = 0; i < num_bytes; ++i) { + unsigned b = num_bytes - 1 - i; + native[b / uECC_WORD_SIZE] |= + (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); + } +} + +int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top, + wordcount_t num_words) +{ + uECC_word_t mask = (uECC_word_t)-1; + uECC_word_t tries; + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + + if (!g_rng_function) { + return 0; + } + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { + return 0; + } + random[num_words - 1] &= + mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + if (!uECC_vli_isZero(random, num_words) && + uECC_vli_cmp(top, random, num_words) == 1) { + return 1; + } + } + return 0; +} + + +int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) +{ + uECC_word_t tmp1[NUM_ECC_WORDS]; + uECC_word_t tmp2[NUM_ECC_WORDS]; + wordcount_t num_words = curve->num_words; + + /* The point at infinity is invalid. */ + if (EccPoint_isZero(point, curve)) { + return -1; + } + + /* x and y must be smaller than p. */ + if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || + uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { + return -2; + } + + uECC_vli_modSquare_fast(tmp1, point + num_words, curve); + curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ + + /* Make sure that y^2 == x^3 + ax + b */ + if (uECC_vli_equal(tmp1, tmp2, num_words) != 0) + return -3; + + return 0; +} + +int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) +{ + + uECC_word_t _public[NUM_ECC_WORDS * 2]; + + uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); + uECC_vli_bytesToNative( + _public + curve->num_words, + public_key + curve->num_bytes, + curve->num_bytes); + + if (uECC_vli_cmp_unsafe(_public, curve->G, NUM_ECC_WORDS * 2) == 0) { + return -4; + } + + return uECC_valid_point(_public, curve); +} + +int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, + uECC_Curve curve) +{ + + uECC_word_t _private[NUM_ECC_WORDS]; + uECC_word_t _public[NUM_ECC_WORDS * 2]; + + uECC_vli_bytesToNative( + _private, + private_key, + BITS_TO_BYTES(curve->num_n_bits)); + + /* Make sure the private key is in the range [1, n-1]. */ + if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) { + return 0; + } + + if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { + return 0; + } + + /* Compute public key. */ + if (!EccPoint_compute_public_key(_public, _private, curve)) { + return 0; + } + + uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); + uECC_vli_nativeToBytes( + public_key + + curve->num_bytes, curve->num_bytes, _public + curve->num_words); + return 1; +} + + + diff --git a/tinycrypt/lib/source/ecc_dh.c b/tinycrypt/lib/source/ecc_dh.c new file mode 100644 index 00000000..5624c964 --- /dev/null +++ b/tinycrypt/lib/source/ecc_dh.c @@ -0,0 +1,192 @@ +/* ec_dh.c - TinyCrypt implementation of EC-DH */ + +/* + * Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include +#include +#include + +int uECC_make_key_with_d(uint8_t *public_key, uint8_t *private_key, + unsigned int *d, uECC_Curve curve) +{ + + uECC_word_t _private[NUM_ECC_WORDS]; + uECC_word_t _public[NUM_ECC_WORDS * 2]; + + /* This function is designed for test purposes-only (such as validating NIST + * test vectors) as it uses a provided value for d instead of generating + * it uniformly at random. */ + memcpy (_private, d, NUM_ECC_BYTES); + + /* Computing public-key from private: */ + if (EccPoint_compute_public_key(_public, _private, curve)) { + + /* Converting buffers to correct bit order: */ + uECC_vli_nativeToBytes(private_key, + BITS_TO_BYTES(curve->num_n_bits), + _private); + uECC_vli_nativeToBytes(public_key, + curve->num_bytes, + _public); + uECC_vli_nativeToBytes(public_key + curve->num_bytes, + curve->num_bytes, + _public + curve->num_words); + + /* erasing temporary buffer used to store secret: */ + _set_secure(_private, 0, NUM_ECC_BYTES); + + return 1; + } + return 0; +} + +int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve) +{ + + uECC_word_t _random[NUM_ECC_WORDS * 2]; + uECC_word_t _private[NUM_ECC_WORDS]; + uECC_word_t _public[NUM_ECC_WORDS * 2]; + uECC_word_t tries; + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + /* Generating _private uniformly at random: */ + uECC_RNG_Function rng_function = uECC_get_rng(); + if (!rng_function || + !rng_function((uint8_t *)_random, 2 * NUM_ECC_WORDS*uECC_WORD_SIZE)) { + return 0; + } + + /* computing modular reduction of _random (see FIPS 186.4 B.4.1): */ + uECC_vli_mmod(_private, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits)); + + /* Computing public-key from private: */ + if (EccPoint_compute_public_key(_public, _private, curve)) { + + /* Converting buffers to correct bit order: */ + uECC_vli_nativeToBytes(private_key, + BITS_TO_BYTES(curve->num_n_bits), + _private); + uECC_vli_nativeToBytes(public_key, + curve->num_bytes, + _public); + uECC_vli_nativeToBytes(public_key + curve->num_bytes, + curve->num_bytes, + _public + curve->num_words); + + /* erasing temporary buffer that stored secret: */ + _set_secure(_private, 0, NUM_ECC_BYTES); + + return 1; + } + } + return 0; +} + +int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, + uint8_t *secret, uECC_Curve curve) +{ + + uECC_word_t _public[NUM_ECC_WORDS * 2]; + uECC_word_t _private[NUM_ECC_WORDS]; + + uECC_word_t tmp[NUM_ECC_WORDS]; + uECC_word_t *p2[2] = {_private, tmp}; + uECC_word_t *initial_Z = 0; + uECC_word_t carry; + wordcount_t num_words = curve->num_words; + wordcount_t num_bytes = curve->num_bytes; + int r; + + /* Converting buffers to correct bit order: */ + uECC_vli_bytesToNative(_private, + private_key, + BITS_TO_BYTES(curve->num_n_bits)); + uECC_vli_bytesToNative(_public, + public_key, + num_bytes); + uECC_vli_bytesToNative(_public + num_words, + public_key + num_bytes, + num_bytes); + + /* Regularize the bitcount for the private key so that attackers cannot use a + * side channel attack to learn the number of leading zeros. */ + carry = regularize_k(_private, _private, tmp, curve); + + /* If an RNG function was specified, try to get a random initial Z value to + * improve protection against side-channel attacks. */ + if (uECC_get_rng()) { + if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { + r = 0; + goto clear_and_out; + } + initial_Z = p2[carry]; + } + + EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, + curve); + + uECC_vli_nativeToBytes(secret, num_bytes, _public); + r = !EccPoint_isZero(_public, curve); + +clear_and_out: + /* erasing temporary buffer used to store secret: */ + _set_secure(p2, 0, sizeof(p2)); + _set_secure(tmp, 0, sizeof(tmp)); + _set_secure(_private, 0, sizeof(_private)); + + return r; +} diff --git a/tinycrypt/lib/source/ecc_dsa.c b/tinycrypt/lib/source/ecc_dsa.c new file mode 100644 index 00000000..06f077b4 --- /dev/null +++ b/tinycrypt/lib/source/ecc_dsa.c @@ -0,0 +1,290 @@ +/* ec_dsa.c - TinyCrypt implementation of EC-DSA */ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.*/ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + + +static void bits2int(uECC_word_t *native, const uint8_t *bits, + unsigned bits_size, uECC_Curve curve) +{ + unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); + unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); + int shift; + uECC_word_t carry; + uECC_word_t *ptr; + + if (bits_size > num_n_bytes) { + bits_size = num_n_bytes; + } + + uECC_vli_clear(native, num_n_words); + uECC_vli_bytesToNative(native, bits, bits_size); + if (bits_size * 8 <= (unsigned)curve->num_n_bits) { + return; + } + shift = bits_size * 8 - curve->num_n_bits; + carry = 0; + ptr = native + num_n_words; + while (ptr-- > native) { + uECC_word_t temp = *ptr; + *ptr = (temp >> shift) | carry; + carry = temp << (uECC_WORD_BITS - shift); + } + + /* Reduce mod curve_n */ + if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { + uECC_vli_sub(native, native, curve->n, num_n_words); + } +} + +int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uECC_word_t *k, uint8_t *signature, + uECC_Curve curve) +{ + + uECC_word_t tmp[NUM_ECC_WORDS]; + uECC_word_t s[NUM_ECC_WORDS]; + uECC_word_t *k2[2] = {tmp, s}; + uECC_word_t p[NUM_ECC_WORDS * 2]; + uECC_word_t carry; + wordcount_t num_words = curve->num_words; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + bitcount_t num_n_bits = curve->num_n_bits; + + /* Make sure 0 < k < curve_n */ + if (uECC_vli_isZero(k, num_words) || + uECC_vli_cmp(curve->n, k, num_n_words) != 1) { + return 0; + } + + carry = regularize_k(k, tmp, s, curve); + EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve); + if (uECC_vli_isZero(p, num_words)) { + return 0; + } + + /* If an RNG function was specified, get a random number + to prevent side channel analysis of k. */ + if (!uECC_get_rng()) { + uECC_vli_clear(tmp, num_n_words); + tmp[0] = 1; + } + else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { + return 0; + } + + /* Prevent side channel analysis of uECC_vli_modInv() to determine + bits of k / the private key by premultiplying by a random number */ + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ + uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ + uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ + + uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ + + /* tmp = d: */ + uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); + + s[num_n_words - 1] = 0; + uECC_vli_set(s, p, num_words); + uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ + + bits2int(tmp, message_hash, hash_size, curve); + uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ + uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ + if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { + return 0; + } + + uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); + return 1; +} + +int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash, + unsigned hash_size, uint8_t *signature, uECC_Curve curve) +{ + uECC_word_t _random[2*NUM_ECC_WORDS]; + uECC_word_t k[NUM_ECC_WORDS]; + uECC_word_t tries; + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + /* Generating _random uniformly at random: */ + uECC_RNG_Function rng_function = uECC_get_rng(); + if (!rng_function || + !rng_function((uint8_t *)_random, 2*NUM_ECC_WORDS*uECC_WORD_SIZE)) { + return 0; + } + + // computing k as modular reduction of _random (see FIPS 186.4 B.5.1): + uECC_vli_mmod(k, _random, curve->n, BITS_TO_WORDS(curve->num_n_bits)); + + if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, + curve)) { + return 1; + } + } + return 0; +} + +static bitcount_t smax(bitcount_t a, bitcount_t b) +{ + return (a > b ? a : b); +} + +int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, + unsigned hash_size, const uint8_t *signature, + uECC_Curve curve) +{ + + uECC_word_t u1[NUM_ECC_WORDS], u2[NUM_ECC_WORDS]; + uECC_word_t z[NUM_ECC_WORDS]; + uECC_word_t sum[NUM_ECC_WORDS * 2]; + uECC_word_t rx[NUM_ECC_WORDS]; + uECC_word_t ry[NUM_ECC_WORDS]; + uECC_word_t tx[NUM_ECC_WORDS]; + uECC_word_t ty[NUM_ECC_WORDS]; + uECC_word_t tz[NUM_ECC_WORDS]; + const uECC_word_t *points[4]; + const uECC_word_t *point; + bitcount_t num_bits; + bitcount_t i; + + uECC_word_t _public[NUM_ECC_WORDS * 2]; + uECC_word_t r[NUM_ECC_WORDS], s[NUM_ECC_WORDS]; + wordcount_t num_words = curve->num_words; + wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); + + rx[num_n_words - 1] = 0; + r[num_n_words - 1] = 0; + s[num_n_words - 1] = 0; + + uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); + uECC_vli_bytesToNative(_public + num_words, public_key + curve->num_bytes, + curve->num_bytes); + uECC_vli_bytesToNative(r, signature, curve->num_bytes); + uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); + + /* r, s must not be 0. */ + if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { + return 0; + } + + /* r, s must be < n. */ + if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || + uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { + return 0; + } + + /* Calculate u1 and u2. */ + uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ + u1[num_n_words - 1] = 0; + bits2int(u1, message_hash, hash_size, curve); + uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ + uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ + + /* Calculate sum = G + Q. */ + uECC_vli_set(sum, _public, num_words); + uECC_vli_set(sum + num_words, _public + num_words, num_words); + uECC_vli_set(tx, curve->G, num_words); + uECC_vli_set(ty, curve->G + num_words, num_words); + uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ + XYcZ_add(tx, ty, sum, sum + num_words, curve); + uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ + apply_z(sum, sum + num_words, z, curve); + + /* Use Shamir's trick to calculate u1*G + u2*Q */ + points[0] = 0; + points[1] = curve->G; + points[2] = _public; + points[3] = sum; + num_bits = smax(uECC_vli_numBits(u1, num_n_words), + uECC_vli_numBits(u2, num_n_words)); + + point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | + ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; + uECC_vli_set(rx, point, num_words); + uECC_vli_set(ry, point + num_words, num_words); + uECC_vli_clear(z, num_words); + z[0] = 1; + + for (i = num_bits - 2; i >= 0; --i) { + uECC_word_t index; + curve->double_jacobian(rx, ry, z, curve); + + index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); + point = points[index]; + if (point) { + uECC_vli_set(tx, point, num_words); + uECC_vli_set(ty, point + num_words, num_words); + apply_z(tx, ty, z, curve); + uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ + XYcZ_add(tx, ty, rx, ry, curve); + uECC_vli_modMult_fast(z, z, tz, curve); + } + } + + uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ + apply_z(rx, ry, z, curve); + + /* v = x1 (mod n) */ + if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { + uECC_vli_sub(rx, rx, curve->n, num_n_words); + } + + /* Accept only if v == r. */ + return (int)(uECC_vli_equal(rx, r, num_words) == 0); +} + diff --git a/tinycrypt/lib/source/ecc_platform_specific.c b/tinycrypt/lib/source/ecc_platform_specific.c new file mode 100644 index 00000000..1867988f --- /dev/null +++ b/tinycrypt/lib/source/ecc_platform_specific.c @@ -0,0 +1,105 @@ +/* uECC_platform_specific.c - Implementation of platform specific functions*/ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.*/ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * uECC_platform_specific.c -- Implementation of platform specific functions + */ + + +#if defined(unix) || defined(__linux__) || defined(__unix__) || \ + defined(__unix) | (defined(__APPLE__) && defined(__MACH__)) || \ + defined(uECC_POSIX) + +/* Some POSIX-like system with /dev/urandom or /dev/random. */ +#include +#include +#include + +#include + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +int default_CSPRNG(uint8_t *dest, unsigned int size) { + + /* input sanity check: */ + if (dest == (uint8_t *) 0 || (size <= 0)) + return 0; + + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + fd = open("/dev/random", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + return 0; + } + } + + char *ptr = (char *)dest; + size_t left = (size_t) size; + while (left > 0) { + ssize_t bytes_read = read(fd, ptr, left); + if (bytes_read <= 0) { // read failed + close(fd); + return 0; + } + left -= bytes_read; + ptr += bytes_read; + } + + close(fd); + return 1; +} + +#endif /* platform */ + diff --git a/tinycrypt/lib/source/hmac.c b/tinycrypt/lib/source/hmac.c new file mode 100644 index 00000000..cef5bf39 --- /dev/null +++ b/tinycrypt/lib/source/hmac.c @@ -0,0 +1,147 @@ +/* hmac.c - TinyCrypt implementation of the HMAC algorithm */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +static void rekey(uint8_t *key, const uint8_t *new_key, unsigned int key_size) +{ + const uint8_t inner_pad = (uint8_t) 0x36; + const uint8_t outer_pad = (uint8_t) 0x5c; + unsigned int i; + + for (i = 0; i < key_size; ++i) { + key[i] = inner_pad ^ new_key[i]; + key[i + TC_SHA256_BLOCK_SIZE] = outer_pad ^ new_key[i]; + } + for (; i < TC_SHA256_BLOCK_SIZE; ++i) { + key[i] = inner_pad; key[i + TC_SHA256_BLOCK_SIZE] = outer_pad; + } +} + +int tc_hmac_set_key(TCHmacState_t ctx, const uint8_t *key, + unsigned int key_size) +{ + /* Input sanity check */ + if (ctx == (TCHmacState_t) 0 || + key == (const uint8_t *) 0 || + key_size == 0) { + return TC_CRYPTO_FAIL; + } + + const uint8_t dummy_key[TC_SHA256_BLOCK_SIZE]; + struct tc_hmac_state_struct dummy_state; + + if (key_size <= TC_SHA256_BLOCK_SIZE) { + /* + * The next three calls are dummy calls just to avoid + * certain timing attacks. Without these dummy calls, + * adversaries would be able to learn whether the key_size is + * greater than TC_SHA256_BLOCK_SIZE by measuring the time + * consumed in this process. + */ + (void)tc_sha256_init(&dummy_state.hash_state); + (void)tc_sha256_update(&dummy_state.hash_state, + dummy_key, + key_size); + (void)tc_sha256_final(&dummy_state.key[TC_SHA256_DIGEST_SIZE], + &dummy_state.hash_state); + + /* Actual code for when key_size <= TC_SHA256_BLOCK_SIZE: */ + rekey(ctx->key, key, key_size); + } else { + (void)tc_sha256_init(&ctx->hash_state); + (void)tc_sha256_update(&ctx->hash_state, key, key_size); + (void)tc_sha256_final(&ctx->key[TC_SHA256_DIGEST_SIZE], + &ctx->hash_state); + rekey(ctx->key, + &ctx->key[TC_SHA256_DIGEST_SIZE], + TC_SHA256_DIGEST_SIZE); + } + + return TC_CRYPTO_SUCCESS; +} + +int tc_hmac_init(TCHmacState_t ctx) +{ + + /* input sanity check: */ + if (ctx == (TCHmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + (void) tc_sha256_init(&ctx->hash_state); + (void) tc_sha256_update(&ctx->hash_state, ctx->key, TC_SHA256_BLOCK_SIZE); + + return TC_CRYPTO_SUCCESS; +} + +int tc_hmac_update(TCHmacState_t ctx, + const void *data, + unsigned int data_length) +{ + + /* input sanity check: */ + if (ctx == (TCHmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + (void)tc_sha256_update(&ctx->hash_state, data, data_length); + + return TC_CRYPTO_SUCCESS; +} + +int tc_hmac_final(uint8_t *tag, unsigned int taglen, TCHmacState_t ctx) +{ + + /* input sanity check: */ + if (tag == (uint8_t *) 0 || + taglen != TC_SHA256_DIGEST_SIZE || + ctx == (TCHmacState_t) 0) { + return TC_CRYPTO_FAIL; + } + + (void) tc_sha256_final(tag, &ctx->hash_state); + + (void)tc_sha256_init(&ctx->hash_state); + (void)tc_sha256_update(&ctx->hash_state, + &ctx->key[TC_SHA256_BLOCK_SIZE], + TC_SHA256_BLOCK_SIZE); + (void)tc_sha256_update(&ctx->hash_state, tag, TC_SHA256_DIGEST_SIZE); + (void)tc_sha256_final(tag, &ctx->hash_state); + + /* destroy the current state */ + _set(ctx, 0, sizeof(*ctx)); + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/hmac_prng.c b/tinycrypt/lib/source/hmac_prng.c new file mode 100644 index 00000000..84e7918b --- /dev/null +++ b/tinycrypt/lib/source/hmac_prng.c @@ -0,0 +1,230 @@ +/* hmac_prng.c - TinyCrypt implementation of HMAC-PRNG */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include +#include + +/* + * min bytes in the seed string. + * MIN_SLEN*8 must be at least the expected security level. + */ +static const unsigned int MIN_SLEN = 32; + +/* + * max bytes in the seed string; + * SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes). + */ +static const unsigned int MAX_SLEN = UINT32_MAX; + +/* + * max bytes in the personalization string; + * SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes). + */ +static const unsigned int MAX_PLEN = UINT32_MAX; + +/* + * max bytes in the additional_info string; + * SP800-90A specifies a maximum of 2^35 bits (i.e., 2^32 bytes). + */ +static const unsigned int MAX_ALEN = UINT32_MAX; + +/* + * max number of generates between re-seeds; + * TinyCrypt accepts up to (2^32 - 1) which is the maximal value of + * a 32-bit unsigned int variable, while SP800-90A specifies a maximum of 2^48. + */ +static const unsigned int MAX_GENS = UINT32_MAX; + +/* + * maximum bytes per generate call; + * SP800-90A specifies a maximum up to 2^19. + */ +static const unsigned int MAX_OUT = (1 << 19); + +/* + * Assumes: prng != NULL + */ +static void update(TCHmacPrng_t prng, const uint8_t *data, unsigned int datalen, const uint8_t *additional_data, unsigned int additional_datalen) +{ + const uint8_t separator0 = 0x00; + const uint8_t separator1 = 0x01; + + /* configure the new prng key into the prng's instance of hmac */ + tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); + + /* use current state, e and separator 0 to compute a new prng key: */ + (void)tc_hmac_init(&prng->h); + (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); + (void)tc_hmac_update(&prng->h, &separator0, sizeof(separator0)); + + if (data && datalen) + (void)tc_hmac_update(&prng->h, data, datalen); + if (additional_data && additional_datalen) + (void)tc_hmac_update(&prng->h, additional_data, additional_datalen); + + (void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h); + + /* configure the new prng key into the prng's instance of hmac */ + (void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); + + /* use the new key to compute a new state variable v */ + (void)tc_hmac_init(&prng->h); + (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); + (void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h); + + if (data == 0 || datalen == 0) + return; + + /* configure the new prng key into the prng's instance of hmac */ + tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); + + /* use current state, e and separator 1 to compute a new prng key: */ + (void)tc_hmac_init(&prng->h); + (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); + (void)tc_hmac_update(&prng->h, &separator1, sizeof(separator1)); + (void)tc_hmac_update(&prng->h, data, datalen); + if (additional_data && additional_datalen) + (void)tc_hmac_update(&prng->h, additional_data, additional_datalen); + (void)tc_hmac_final(prng->key, sizeof(prng->key), &prng->h); + + /* configure the new prng key into the prng's instance of hmac */ + (void)tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); + + /* use the new key to compute a new state variable v */ + (void)tc_hmac_init(&prng->h); + (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); + (void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h); +} + +int tc_hmac_prng_init(TCHmacPrng_t prng, + const uint8_t *personalization, + unsigned int plen) +{ + + /* input sanity check: */ + if (prng == (TCHmacPrng_t) 0 || + personalization == (uint8_t *) 0 || + plen > MAX_PLEN) { + return TC_CRYPTO_FAIL; + } + + /* put the generator into a known state: */ + _set(prng->key, 0x00, sizeof(prng->key)); + _set(prng->v, 0x01, sizeof(prng->v)); + + update(prng, personalization, plen, 0, 0); + + /* force a reseed before allowing tc_hmac_prng_generate to succeed: */ + prng->countdown = 0; + + return TC_CRYPTO_SUCCESS; +} + +int tc_hmac_prng_reseed(TCHmacPrng_t prng, + const uint8_t *seed, + unsigned int seedlen, + const uint8_t *additional_input, + unsigned int additionallen) +{ + + /* input sanity check: */ + if (prng == (TCHmacPrng_t) 0 || + seed == (const uint8_t *) 0 || + seedlen < MIN_SLEN || + seedlen > MAX_SLEN) { + return TC_CRYPTO_FAIL; + } + + if (additional_input != (const uint8_t *) 0) { + /* + * Abort if additional_input is provided but has inappropriate + * length + */ + if (additionallen == 0 || + additionallen > MAX_ALEN) { + return TC_CRYPTO_FAIL; + } else { + /* call update for the seed and additional_input */ + update(prng, seed, seedlen, additional_input, additionallen); + } + } else { + /* call update only for the seed */ + update(prng, seed, seedlen, 0, 0); + } + + /* ... and enable hmac_prng_generate */ + prng->countdown = MAX_GENS; + + return TC_CRYPTO_SUCCESS; +} + +int tc_hmac_prng_generate(uint8_t *out, unsigned int outlen, TCHmacPrng_t prng) +{ + unsigned int bufferlen; + + /* input sanity check: */ + if (out == (uint8_t *) 0 || + prng == (TCHmacPrng_t) 0 || + outlen == 0 || + outlen > MAX_OUT) { + return TC_CRYPTO_FAIL; + } else if (prng->countdown == 0) { + return TC_HMAC_PRNG_RESEED_REQ; + } + + prng->countdown--; + + while (outlen != 0) { + /* configure the new prng key into the prng's instance of hmac */ + tc_hmac_set_key(&prng->h, prng->key, sizeof(prng->key)); + + /* operate HMAC in OFB mode to create "random" outputs */ + (void)tc_hmac_init(&prng->h); + (void)tc_hmac_update(&prng->h, prng->v, sizeof(prng->v)); + (void)tc_hmac_final(prng->v, sizeof(prng->v), &prng->h); + + bufferlen = (TC_SHA256_DIGEST_SIZE > outlen) ? + outlen : TC_SHA256_DIGEST_SIZE; + (void)_copy(out, bufferlen, prng->v, bufferlen); + + out += bufferlen; + outlen = (outlen > TC_SHA256_DIGEST_SIZE) ? + (outlen - TC_SHA256_DIGEST_SIZE) : 0; + } + + /* block future PRNG compromises from revealing past state */ + update(prng, 0, 0, 0, 0); + + return TC_CRYPTO_SUCCESS; +} diff --git a/tinycrypt/lib/source/sha256.c b/tinycrypt/lib/source/sha256.c new file mode 100644 index 00000000..b4efd204 --- /dev/null +++ b/tinycrypt/lib/source/sha256.c @@ -0,0 +1,217 @@ +/* sha256.c - TinyCrypt SHA-256 crypto hash algorithm implementation */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include +#include + +static void compress(unsigned int *iv, const uint8_t *data); + +int tc_sha256_init(TCSha256State_t s) +{ + /* input sanity check: */ + if (s == (TCSha256State_t) 0) { + return TC_CRYPTO_FAIL; + } + + /* + * Setting the initial state values. + * These values correspond to the first 32 bits of the fractional parts + * of the square roots of the first 8 primes: 2, 3, 5, 7, 11, 13, 17 + * and 19. + */ + _set((uint8_t *) s, 0x00, sizeof(*s)); + s->iv[0] = 0x6a09e667; + s->iv[1] = 0xbb67ae85; + s->iv[2] = 0x3c6ef372; + s->iv[3] = 0xa54ff53a; + s->iv[4] = 0x510e527f; + s->iv[5] = 0x9b05688c; + s->iv[6] = 0x1f83d9ab; + s->iv[7] = 0x5be0cd19; + + return TC_CRYPTO_SUCCESS; +} + +int tc_sha256_update(TCSha256State_t s, const uint8_t *data, size_t datalen) +{ + /* input sanity check: */ + if (s == (TCSha256State_t) 0 || + data == (void *) 0) { + return TC_CRYPTO_FAIL; + } else if (datalen == 0) { + return TC_CRYPTO_SUCCESS; + } + + while (datalen-- > 0) { + s->leftover[s->leftover_offset++] = *(data++); + if (s->leftover_offset >= TC_SHA256_BLOCK_SIZE) { + compress(s->iv, s->leftover); + s->leftover_offset = 0; + s->bits_hashed += (TC_SHA256_BLOCK_SIZE << 3); + } + } + + return TC_CRYPTO_SUCCESS; +} + +int tc_sha256_final(uint8_t *digest, TCSha256State_t s) +{ + unsigned int i; + + /* input sanity check: */ + if (digest == (uint8_t *) 0 || + s == (TCSha256State_t) 0) { + return TC_CRYPTO_FAIL; + } + + s->bits_hashed += (s->leftover_offset << 3); + + s->leftover[s->leftover_offset++] = 0x80; /* always room for one byte */ + if (s->leftover_offset > (sizeof(s->leftover) - 8)) { + /* there is not room for all the padding in this block */ + _set(s->leftover + s->leftover_offset, 0x00, + sizeof(s->leftover) - s->leftover_offset); + compress(s->iv, s->leftover); + s->leftover_offset = 0; + } + + /* add the padding and the length in big-Endian format */ + _set(s->leftover + s->leftover_offset, 0x00, + sizeof(s->leftover) - 8 - s->leftover_offset); + s->leftover[sizeof(s->leftover) - 1] = (uint8_t)(s->bits_hashed); + s->leftover[sizeof(s->leftover) - 2] = (uint8_t)(s->bits_hashed >> 8); + s->leftover[sizeof(s->leftover) - 3] = (uint8_t)(s->bits_hashed >> 16); + s->leftover[sizeof(s->leftover) - 4] = (uint8_t)(s->bits_hashed >> 24); + s->leftover[sizeof(s->leftover) - 5] = (uint8_t)(s->bits_hashed >> 32); + s->leftover[sizeof(s->leftover) - 6] = (uint8_t)(s->bits_hashed >> 40); + s->leftover[sizeof(s->leftover) - 7] = (uint8_t)(s->bits_hashed >> 48); + s->leftover[sizeof(s->leftover) - 8] = (uint8_t)(s->bits_hashed >> 56); + + /* hash the padding and length */ + compress(s->iv, s->leftover); + + /* copy the iv out to digest */ + for (i = 0; i < TC_SHA256_STATE_BLOCKS; ++i) { + unsigned int t = *((unsigned int *) &s->iv[i]); + *digest++ = (uint8_t)(t >> 24); + *digest++ = (uint8_t)(t >> 16); + *digest++ = (uint8_t)(t >> 8); + *digest++ = (uint8_t)(t); + } + + /* destroy the current state */ + _set(s, 0, sizeof(*s)); + + return TC_CRYPTO_SUCCESS; +} + +/* + * Initializing SHA-256 Hash constant words K. + * These values correspond to the first 32 bits of the fractional parts of the + * cube roots of the first 64 primes between 2 and 311. + */ +static const unsigned int k256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static inline unsigned int ROTR(unsigned int a, unsigned int n) +{ + return (((a) >> n) | ((a) << (32 - n))); +} + +#define Sigma0(a)(ROTR((a), 2) ^ ROTR((a), 13) ^ ROTR((a), 22)) +#define Sigma1(a)(ROTR((a), 6) ^ ROTR((a), 11) ^ ROTR((a), 25)) +#define sigma0(a)(ROTR((a), 7) ^ ROTR((a), 18) ^ ((a) >> 3)) +#define sigma1(a)(ROTR((a), 17) ^ ROTR((a), 19) ^ ((a) >> 10)) + +#define Ch(a, b, c)(((a) & (b)) ^ ((~(a)) & (c))) +#define Maj(a, b, c)(((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c))) + +static inline unsigned int BigEndian(const uint8_t **c) +{ + unsigned int n = 0; + + n = (((unsigned int)(*((*c)++))) << 24); + n |= ((unsigned int)(*((*c)++)) << 16); + n |= ((unsigned int)(*((*c)++)) << 8); + n |= ((unsigned int)(*((*c)++))); + return n; +} + +static void compress(unsigned int *iv, const uint8_t *data) +{ + unsigned int a, b, c, d, e, f, g, h; + unsigned int s0, s1; + unsigned int t1, t2; + unsigned int work_space[16]; + unsigned int n; + unsigned int i; + + a = iv[0]; b = iv[1]; c = iv[2]; d = iv[3]; + e = iv[4]; f = iv[5]; g = iv[6]; h = iv[7]; + + for (i = 0; i < 16; ++i) { + n = BigEndian(&data); + t1 = work_space[i] = n; + t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i]; + t2 = Sigma0(a) + Maj(a, b, c); + h = g; g = f; f = e; e = d + t1; + d = c; c = b; b = a; a = t1 + t2; + } + + for ( ; i < 64; ++i) { + s0 = work_space[(i+1)&0x0f]; + s0 = sigma0(s0); + s1 = work_space[(i+14)&0x0f]; + s1 = sigma1(s1); + + t1 = work_space[i&0xf] += s0 + s1 + work_space[(i+9)&0xf]; + t1 += h + Sigma1(e) + Ch(e, f, g) + k256[i]; + t2 = Sigma0(a) + Maj(a, b, c); + h = g; g = f; f = e; e = d + t1; + d = c; c = b; b = a; a = t1 + t2; + } + + iv[0] += a; iv[1] += b; iv[2] += c; iv[3] += d; + iv[4] += e; iv[5] += f; iv[6] += g; iv[7] += h; +} diff --git a/tinycrypt/lib/source/utils.c b/tinycrypt/lib/source/utils.c new file mode 100644 index 00000000..13cc4951 --- /dev/null +++ b/tinycrypt/lib/source/utils.c @@ -0,0 +1,74 @@ +/* utils.c - TinyCrypt platform-dependent run-time operations */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 +#include + +#include + +#define MASK_TWENTY_SEVEN 0x1b + +unsigned int _copy(uint8_t *to, unsigned int to_len, + const uint8_t *from, unsigned int from_len) +{ + if (from_len <= to_len) { + (void)memcpy(to, from, from_len); + return from_len; + } else { + return TC_CRYPTO_FAIL; + } +} + +void _set(void *to, uint8_t val, unsigned int len) +{ + (void)memset(to, val, len); +} + +/* + * Doubles the value of a byte for values up to 127. + */ +uint8_t _double_byte(uint8_t a) +{ + return ((a<<1) ^ ((a>>7) * MASK_TWENTY_SEVEN)); +} + +int _compare(const uint8_t *a, const uint8_t *b, size_t size) +{ + const uint8_t *tempa = a; + const uint8_t *tempb = b; + uint8_t result = 0; + + for (unsigned int i = 0; i < size; i++) { + result |= tempa[i] ^ tempb[i]; + } + return result; +} diff --git a/tinycrypt/tests/Makefile b/tinycrypt/tests/Makefile new file mode 100644 index 00000000..0386a875 --- /dev/null +++ b/tinycrypt/tests/Makefile @@ -0,0 +1,70 @@ +################################################################################ +# +# Copyright (C) 2017 by Intel Corporation, All Rights Reserved. +# +# Tests Makefile. +# +################################################################################ + +include ../config.mk + +TEST_LIB_FILE:=test_ecc_utils.c +TEST_SOURCE:=$(filter-out $(TEST_LIB_FILE), $(wildcard test_*.c)) + +TEST_OBJECTS:=$(TEST_SOURCE:.c=.o) +TEST_DEPS:=$(TEST_SOURCE:.c=.d) +TEST_BINARY:=$(TEST_SOURCE:.c=$(DOTEXE)) + +# Edit the 'all' content to add/remove tests needed from TinyCrypt library: +all: $(TEST_BINARY) + +clean: + -$(RM) $(TEST_BINARY) $(TEST_OBJECTS) $(TEST_DEPS) + -$(RM) *~ *.o *.d + +# Dependencies +test_aes$(DOTEXE): test_aes.o aes_encrypt.o aes_decrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_cbc_mode$(DOTEXE): test_cbc_mode.o cbc_mode.o \ + aes_encrypt.o aes_decrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ctr_mode$(DOTEXE): test_ctr_mode.o ctr_mode.o \ + aes_encrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ctr_prng$(DOTEXE): test_ctr_prng.o ctr_prng.o \ + aes_encrypt.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_cmac_mode$(DOTEXE): test_cmac_mode.o aes_encrypt.o utils.o \ + cmac_mode.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ccm_mode$(DOTEXE): test_ccm_mode.o aes_encrypt.o \ + utils.o ccm_mode.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_hmac$(DOTEXE): test_hmac.o hmac.o sha256.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_hmac_prng$(DOTEXE): test_hmac_prng.o hmac_prng.o hmac.o \ + sha256.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_sha256$(DOTEXE): test_sha256.o sha256.o utils.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ecc_dh$(DOTEXE): test_ecc_dh.o ecc.o ecc_dh.o test_ecc_utils.o ecc_platform_specific.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_ecc_dsa$(DOTEXE): test_ecc_dsa.o ecc.o utils.o ecc_dh.o \ + ecc_dsa.o sha256.o test_ecc_utils.o ecc_platform_specific.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +test_client_server$(DOTEXE): test_client_server.o ecc.o ecc_dh.o ecc_platform_specific.o aes_encrypt.o utils.o ctr_mode.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + + +-include $(TEST_DEPS) diff --git a/tinycrypt/tests/include/test_ecc_utils.h b/tinycrypt/tests/include/test_ecc_utils.h new file mode 100644 index 00000000..4e290549 --- /dev/null +++ b/tinycrypt/tests/include/test_ecc_utils.h @@ -0,0 +1,100 @@ +/* test_ecc_utils.h - TinyCrypt interface to common functions for ECC tests */ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.*/ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * test_ecc_utils.h -- Interface to common functions for ECC tests. + */ + +#ifndef __TEST_ECC_UTILS_H__ +#define __TEST_ECC_UTILS_H__ + +#include +#include +#include + +int hex2int (char hex); + + +/* + * Convert hex string to byte string + * Return number of bytes written to buf, or 0 on error + */ +int hex2bin(uint8_t *buf, const size_t buflen, const char *hex, + const size_t hexlen); + +/* + * Convert hex string to zero-padded nanoECC scalar + */ +void string2scalar(unsigned int * scalar, unsigned int num_word32, char *str); + + +void print_ecc_scalar(const char *label, const unsigned int * p_vli, + unsigned int num_word32); + +int check_ecc_result(const int num, const char *name, + const unsigned int *expected, + const unsigned int *computed, + const unsigned int num_word32, const bool verbose); + +/* Test ecc_make_keys, and also as keygen part of other tests */ +int keygen_vectors(char **d_vec, char **qx_vec, char **qy_vec, int tests, bool verbose); + +void vli_print_bytes(uint8_t *vli, unsigned int size); + + +int check_code(const int num, const char *name, const int expected, + const int computed, const int verbose); + + +#endif /* __TEST_ECC_UTILS_H__ */ + diff --git a/tinycrypt/tests/include/test_utils.h b/tinycrypt/tests/include/test_utils.h new file mode 100644 index 00000000..055f91b9 --- /dev/null +++ b/tinycrypt/tests/include/test_utils.h @@ -0,0 +1,125 @@ +/* test_utils.h - TinyCrypt interface to common functions for tests */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * test_utils.h -- Interface to common functions for tests. + */ + +#ifndef __TEST_UTILS_H__ +#define __TEST_UTILS_H__ + +#include + +#include +#include +#include +#include + +#define PRINT_DATA(fmt, ...) printf(fmt, ##__VA_ARGS__) + +#define PRINT_LINE \ + PRINT_DATA( \ + "============================================================" \ + "=======\n") + + +#define FAIL "FAIL" +#define PASS "PASS" +#define FMT_ERROR "%s - %s@%d. " + +/* TC_ here stands for 'Test Case' not 'TinyCrypt' */ +#define TC_PASS 0 +#define TC_FAIL 1 + +#define TC_ERROR(fmt, ...) \ + do { \ + PRINT_DATA(FMT_ERROR, FAIL, __func__, __LINE__); \ + PRINT_DATA(fmt, ##__VA_ARGS__); \ + } while (0) + +#define TC_PRINT(fmt, ...) PRINT_DATA(fmt, ##__VA_ARGS__) +#define TC_START(name) PRINT_DATA("tc_start() - %s\n", name) +#define TC_END(result, fmt, ...) PRINT_DATA(fmt, ##__VA_ARGS__) + +/* prints result and the function name */ +#define TC_END_RESULT(result) \ + do { \ + PRINT_LINE; \ + TC_END(result, "%s - %s.\n", \ + result == TC_PASS ? PASS : FAIL, __func__); \ + } while (0) + +#define TC_END_REPORT(result) \ + do { \ + PRINT_LINE; \ + TC_END(result, \ + "PROJECT EXECUTION %s\n", \ + result == TC_PASS ? "SUCCESSFUL" : "FAILED"); \ + } while (0) + +static inline void show_str(const char *label, const uint8_t *s, size_t len) +{ + unsigned int i; + + TC_PRINT("%s = ", label); + for (i = 0; i < (unsigned int) len; ++i) { + TC_PRINT("%02x", s[i]); + } + TC_PRINT("\n"); +} + +static inline void fatal(unsigned int testnum, const void *expected, size_t expectedlen, + const void *computed, size_t computedlen) +{ + + TC_ERROR("\tTest #%d Failed!\n", testnum); + show_str("\t\tExpected", expected, expectedlen); + show_str("\t\tComputed ", computed, computedlen); + TC_PRINT("\n"); +} + +static inline unsigned int check_result(unsigned int testnum, const void *expected, size_t expectedlen, + const void *computed, size_t computedlen) +{ + unsigned int result = TC_PASS; + + if (expectedlen != computedlen) { + TC_ERROR("The length of the computed buffer (%zu)", computedlen); + TC_ERROR("does not match the expected length (%zu).", expectedlen); + result = TC_FAIL; + } else if (memcmp(computed, expected, computedlen) != 0) { + fatal(testnum, expected, expectedlen, computed, computedlen); + result = TC_FAIL; + } + + return result; +} + +#endif /* __TEST_UTILS_H__ */ diff --git a/tinycrypt/tests/pseudo-random-data.bin b/tinycrypt/tests/pseudo-random-data.bin new file mode 100644 index 0000000000000000000000000000000000000000..4f174c58bd3a505ddc1b9aea1937d70e1b8e3833 GIT binary patch literal 524288 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

rJU`^D6d+G+0i0*qW(eD6B_yjwu>SccpL^ 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

  • CR7bpa}{W?5;QW-wW%k?(FX+Y-3; z$$uiM9K6~u_h(4Jw6z05xL!KNm_h1#slaBt@u>NPMSQ+mvYY<#VrkO z8@%F^xog|f4bDI6sNAX_9#n>zun-=yPjc+U-|eBf>d_Fz~@y7M8>BPDIbIvEjgy*L%6c1FA-mW)<@^0-C>r> z7tR$S=@%kYjR<`+534wRnw#@wDa^apP(@VmmK)UbcLK+~Jx%LgmRwNeBSj1)6d;~7 z#wYOlC}@gW4%B4e9^MOU(`gaYE&`U%`)+=xos%S)28HwCTnyYtEkqEq_f%H-8dFMA z*LlF(JzIk=+*6EtQ1=NgH^{?uXO-L{bAP<^>Il=u8%bjM=L%DBrI%p)f?fHa{fyh| z)Bg`>CMNcWJE=1EdoVNmICewfpmiwwo-q(h)$_i?B%6Xn0}D#BW;kfar>@DcdCM z_h6X84bm=ZxlpI|<`m6XP|I`LnVtTvX1ipj57_Pjf=-c_#yGglb|J;K6Qf8HuG97H zq@*!L*HFKXx=usW#sG+!wW$chlpFl^h(gk!tQwt-*M{Tz6`J~ASpbn~>hMSYJ$*2m z;CNMSuFm8->~^wVA6+>))JwES#rwpKnDRnFP#DfPGH6_rT9Byp?dZNIa3V#g6`K-( zx_Y1$$xeTH0gxxV`c;hE6(z|M;28#4n>snXOvR;S(bS zOWqmgU`q3e3t6{5+Dlv{+oyV7BVIq{v|`T9YyARz><#qGGAk4AvNEb{CJd0;pU=1x z3u{Z3f6NUofEkt#d2x;K^9Y6hPZMC0fNryS-ZtroB61I+v1^Yyz+y$HD$@>qMfvtP zEH~}PQouM9N+UM8bKZ>ril@ZS|3>QS9~)fA^3793tERJ(1ha@M$U#w?C z#<)vTf`O0(7)6wO9;#J8uG30=3Fd&Y(#3+OnVhocF9{` z_H=p86K#k-ebC!_-Vi?OU@!Xh6)t@FP<$zsj^=EdWrcytFLoE04M6-18%9u zcojFwt;3E-tIyc%g5>^=BirT)TR7P$4`TUtfBHTJ%mBDc%1O9yTNq{P)RF&MiRh!i zV)Lw>EQubeOU*&GGxxec&~o}b`{4K@*po~LO$cbfwqsAiJV%5bDDZ0J{Q9K&O{z$55y(xu}trA|-|59>=wk)^Z z)O27IegEo?<*f68GXr9?NK(FoTDdD@R0I?~w#DhQv=gU5@4}KW-4(5!(q=T3?b*%V z)?k9_J;QN%+kGS0Y^yBHsOfrOxI>rm&j{cpoLk@n5=gR7`!4xSCddtb1%C))>~azV znrb7sku-kn{JJ?htq=6`wSC;;7BkkUK`3FVdH9eIFwU7}V_uUv0Mcb80Nl;421Hdh z@5j-)NQEh6WuR0d9ki7yGM<_rK3C!&hg7Oa;!K?}E@|K%QUPLNsH>^krhas8WnTgP zbW>0d8^rJ#PF<(!G-vUNI77eEvk@kS;Bd(rmGrU&>5V*Hzw9-)$xr4PbqEYS`85^`_npC8a*G^3 zoAu7RR`$0^+7nOO>{XkZp7BOJ&}&KzHlaz{{XUt3O|OG4X^+!n5VyK+3chN5F%%Dv zcAyutEd957@U6yk<-)Y!MMd?#wDk41QPy+=yX{b9!2TE_%be_#MdTC>06T`JkO$^g zUYos;2y&Ey0pL~meL<@G%9Q82k6~l z6?&sZst{p@%)7}hIQXE#zJC@HHd1M9P3S`T6`Sx^9F0U1`VK+69RCO#$p)xjRF(Tg zHalTsu=`a_+QFl;H6J4Ib%4G7`|#;q-y!H;-6m+VT_r@)WLpX|V({Qm9vlvR&9{l} zef3$@H8BSqX9^EY49#XB=l)g0$asH(&NutF+{Zaw3B0F6rsCHv@Ji}NDpJVx8Tn5| z+|56?M=wU?PaBHi2d$=$I<@km${}_L`%Busv(^FI6x<4AJM~e3eF7IM0M-b(!Yps< zJ)|J2-otNDLOxN}g-~utt%+dAo$~3DmOsrWQw>#jZ1xPy&A>H-nV2u?T(<$qxrK88 zDwO`enO6+!(+ZcHdfYqZ1YjWi3_hWs3#Pib0e0rksc?O4C9~Jb5y(sxWDuI5I|>bDDRn%;8wJr&KRdYy z3CPxa_WFaOUFSL|lgvnv)=P}oRf|2v*rCGgA=cGlKXDQMy=lTr@aB7?3Sxv&!lv}9 z@3&zgT?Nnu+B7a@Goj)3R9Iz(B61H5dTqa7(yG{6Am8evf3JORd(l}~&WwhIOjfsV zXADj&x#H=s;CTJ`cZ^#~2|4(%Jh_;;+-cMZEpYYqd{}rfZZnY}xdBhQ0H?zRV*o?o z;^dB#K4B;sL$2TlAm(}9)uI=FT4ZI?AaEYgSnZ$iQUg8g)9f7FvxP4Q)rp-5PO!K?YR zWX%N|V1Nkn23V*&PfElENo-sS)zuNzWg3O1d=&iF03cDHB6(arWG?}(TpNn_*-AsH zP)eg%Sy}gMfvzIHBR#1Q ziFoSS5?|&HWlH_m!RMdzu{@LP=@T*>GY(gB^`*~6bT5_5Lpm^_c^b7=w9;%!Y@s=F z@VvsNx;N3e+2mKcDvFX9BU~VG7=n#0K|P#_{*=iEw&Xbi{%d&nh>C2@atqV+dEPDsn7(wT}r!I}3g z7|FyH-icMW84I})1LB&CoYZ;?&b0(%3uh&C&i*YDMaL|4tXUH?)-q+*SM4|>F$|C^ zGnA&FOY2k-_Wm!%%YL9s#|-YRfb5JE_e^Mqro~r2@rkf*y=DjrIwNi$Nq0tM9-kuO z-~6$RqV-nR8)&$h6U}=&K-y`4i{g_X-Zp*&aRJ`>$dDRRkNc;DDb}X16qw0BIzwK1El`B=JwFQ+7`~`I}=$OkOuJ#tY3F|8?aL% z*|M7elWC|_La;c<8~vY@1jrp^Vr3ULXP@&p$Ibu}OR0LOipJ>F_$C(%eE6d?7~90- z5RkK1eKuk%f>bHg>)pY4qeyRF4s7{54^M>&qSQ0Gd$Wf11Zb0aI;3Oy_FT z!C}2i+PS43OP%dJi4mhB1G9%qq5z{~$E&U$+EYQ*D)0J@^(7I0O(1cdp$JfJ*v}Je zsEIZ1Tw&fAK+Np9O&JhxiOZO_2{HqAW}^r_`Ew!yfC^_8J`CA`k%{J0(MbSF-Q6oO zS&cGAu$$*t!Q(O`|Bt`0)a%n~#?-RHi-J`+vG7aEzAIVZFEWevO1evABRGUgi>x63 z;vE6m8SxLH$flj3z0P*xIa#yc5UD7FYgI(y*UsEXu3y$@DAvkG{Ax4@oBXInvt#!g zX~gE!uxnmhGS6zY1>#E+WqnBe!kaq{7whnSWSh?mCwiTW|SoArc*2(c6m;?et1`|O z3J|pAoxtM;vSjLm{c%mkH%L)!p#I)Dhp9vji3R z2`dVM(mWygLhwupa(US(A+;-)r|CG2DT%fS-$r8tv(~iTA-^0(L(WgCYRZ8)Y_K8n< z7sM-$__`$V@_XJIuZ(Nq1t5aScRc1eIeXecC(|BmbQsL;sZX?@MZq!?a%1w6;T6o* z*dE#v209bs)U12l>N37>kwcDGiYc-J zKxy@Zu0p}!X5X>9wV160_(eG17aGmM(**qCd!J!n}zTBCFp7oz&iOSO$iFb@_(yqeTJ(sdl z`^!AQDlD;nOAI$TSIm@orl;|(;5bT4k@nw&dX?tYA0!fBJ8ci$*2YY-`Zc-{&OWMb zxV+}y-?kGB;+X~=ynAB1&M@n=5MN#Y`yKv^Ka<)Bc^8p{Lz2mDTa=RGtuWAN21aC$?h4fIR0i1X=+!D)c4j%5>_!ThfAOb|Rf(CdJF zG^OPHc(t3A+bsFho+|9EmBDho~jnp%H?D044B2l!N_Q zy-kW)KwrQx1YMEB(8MQf(DF?QhGIXa+3lE}h=Y+m`STp^r?}*6Q_;=Dp$pSjDl*& z)|+03x36Xb%0$ZT3xI0@xo4Aw!JAgN+Qz0hLeM3{V5FT>-nHfvJN)K+ZZ&4KT#hv^ zhUn#BebDaXlRMT6g6^?VsekVV1NmZA(ro}+PT zN|G6Rt?B+fWr1rxYPHw5+Tr{rnHc3rVIk4sx*kMoQ@1dIS%YpGE4lf_ifX_-s`U*6 zWAiqO;rB!3;qk8>fdOm~C@C$78T2q6L^feLf(e`*C;sUQTV}u!^zkKTHr;4r1Nlbq zuJ^^0B;5ZMlT8wwX?ytLaMR}!lJ!NOa4;u;7fatt(@mj6YC5qzw~Pvbx{tgm_~G$w z%@wug$Tr}pF31^nq6VE<=4bD_kac>C*j(5&f9Ft%#C%*Q-NVIzBsWvy_0|Wb-at_N zfJBZ}OthU6thKKF_$({6W_O=)M7Gh_Y+}|$hHo7#>200HUUJ}pmg!m3NOon0onpnB z;d?Zc25GZs&4GOAeB=#Ss`n_aE0Li$PeCtei@?(2veFigKneh&zStI^UudW+vT;>% zLAi+moR0v^CV&4T>~mS(L9jF@v>ylC8K-t^e~ce-zRrF;K{ntq+GbUa7tAgMWT#gF z_uGcEPg%&lr6Fo)GQW-@8sNz{w`r*v$_g}U=OQ9ND`?lK7t|99!_&^5B|?eSBhzJ6%NSn;#lGz!6m> zs7I>+FbCgjKHC-^EC5#XozPZrdz?}@9?jKsGlEAUne4Uw{i@P9dfxes=50R}W2Y(R zDA-T1ii=~US7;kdBHnXjL7opZ_wtCac4H$xvp6le_b)r8e@h18|MJKTR=C4*=?%~I zViI#K`XvJR9=6cw8|TgPhg1i6Um>mXfkjzKZd8bjA&OmHcyvEQ(`r|7Wn!Xz2-`p4 zXKZ6`wkIb@RNC_!Tp4F(fPKzYgQ;!C?6-p7AehR(sZE-S5LirmGT^(yySoLVOk$bd z7&sr*%G;!~d^xyHbEu*M-sp*_y!oaB9XMV*smGI_h?ad{BzNBK?~4drI`T|&38a*} zX{ok@I@0CT`<1^al$qdG@7|3T zjMJe>c{XfKii{xK9BazgsE*+gu5~ifPyh{Z1{q|idMGKW^%oh&oTeCAL49NcVvQ7k zE*#UWEdbpYoEP6%4OZW?vQ;*69x@t4<_3^lHg$1=h|U@ z@{Q|}sy)xwNBU}FaNoN%DuCmo(cQZ!ippS60g6x2EgO)wLC6W$_(V;Ue{ztJtC1%R zu(@^ZVU>DZ0U>`R+(@#u|Cy*HW1UXM*s6NrRds-2H zYDJeYPggdJxcgW%^B?7u%qg(NlR|Jr9)m~bY1T$B`icl|iYTbwp7Qn$r2{q6aCMh` z5Yy6Gl~?*j8GBH^pt|5b$5HT&YlR)I<(neW8(AeRMHCEZ>YfoBRz4fyX0QQk0i=0q+B(qtmH=DR@~^*iA)-Y@eSCL_cVI@ECiV6}r{}f;s~h zNTa%-p&8y|x7?`IWGlCu=^45TiJWE#E@L0|ekXJ@45G~7LLPEo`HPV?d=UXK2H5yi z{e3K+Orah^@H{@N0fi^ZtiPi_dQW}q+aJa2UdZdXOt}z~a2E+x5x)|KhOCWQED4xr zdVdCse%R5m!jGD0Hv(nF1|jU~ZMZLzO7QhmFZA>E#)r0L#x20b6GAYRqeqp9giaSehhZ6G1;dfg50CxQv6e$2z@ltkZQWcovQ?7)*?p9!J#5Qo#x_ z^B>3O+DQ^yACux$QjPJLk_zet?;`xpZlbYL9R*H?H~f}*r;GQYffXFth~OTpMLXMI ztg(I*iRdXGhZVW@=pi4^%zA(jJlSdXyi5uLYaKmmj*k&?4E)CF1~K{5W0}Wg17Vg^ z@h~&si5C=YcM(=P*L?s`Gf*~QB}-=q8{@(}rl|fXG1rm-6uR?04D{gQU3x6LHdpbV ziUad7%K@dR@1TZjVD|NiAfr_{VM^p&x%W2`FE>O`m6vQ4yw&N9%I=qMXHX=H#tI3w2VKuqyCC<{d_Z7E+^`tzpiz z3PJNMUO1b1*UeL3DnIzXKasv7UYH3&%Q6RJoYv0kVdD+2mQN{3Ly-`tpaVujr&ivj z_;r#&$~}6D)+U<5BeW|@HJlm-x%Oz1hk#g{ z@T$3?{C7n=9*U$2ZRFS9iqHP{Z_f7M`+*PNkt3NNDZZ2n1H7SMHub9snBk%R1>%eb zwok~q?4%)tz2b=A=6D3N^t_2BsQBG)!@kQKoDIL*&W-r*0-NB`KY^a2I=O9R>Qrx4*RW|0Ogl*lwe#DHbc;2fw{fMCrTP^JXFHoY z-ZG5736ANGo{{Jm4%$US(=uX&MKHU8bRfnMraHwB#`jk-e&c!B#!lrZV#uADGZO2w zL$AbZq48$X;iCo*To|(v)PF8P*t48SA_pxkLpNleVQe}ZFHBDLLi9id7okOuigN~_ zEYvLYj7$|bVkllouwbhIPZxlYPv=u!BTX|bVJ+dUCKykS(dES52NazORLyF2?qh+I zq4ijhcJJxSGAOkTDbkxoe_fwErpW|`3p?;t83VgVh@S(dD#a@tM+Oqf5zlJlVFVk< zf?!AjIqBCU9!WJkHqw3dgvoTc5UKJ)uRPo6#jdM7IiiM>+JBeB>^k7st5nFFh`vL4 zWdaaplb^Z7m1@n~tHjgcN15rHI5tpRnN+Q-yyW+PI9hgTKg6}YGVjvFr?D_s^Ijgi zppF@C1QNOKNms$37OK@6Met1Q#EyScVUjGqz}3z0EN(k`P$_q^1AV8=obO^M>nV+H2jkB`)~GcrUSnhlewEz zU$VO^7KdU_@vBnr>gBU|3e{AnK79A%!6V}~Rf$*={;ni!Vu{tFZ;C3O&VsDQL+VD9 zbYY?nE&e)=czkk8KQu}6W@*v0s=i-{O$ssknRWd4uT*MJs@5PmtL8Nw`OmLC;O*Bi z)Ds>J+8?-g5pZf-k)5(GrJBdy0`VWv6n5WGsa)^^>s-L}aEE2^aKYW2x2#yE(D@4P zA%khaT1`&Of>@n3!IL%DX4w=+5IGK4zcg4|U0qzlT>2~w{lb+Q=1~y_e2P=72!Qh+ z{>%AXRly9*lNJ5u3S?lZ%e)HsG5YCm;Cl*!_Kd_<HP$e126BP^3dLq%aV0OpbZyuBQ-mtY6j23^0r_=BTm*^$ zY|J_g?+oO7?Vjwnr#I>ZxyV+qPjcX|k@x$O3PUOnd;#`n9F>>6eRTbT`H>sc+@m27 z|6-^8HRZ?x@h#RG70yV!jIbE{_8fMsfSJe3q9)D?dGE@tVsWXDH-~2D;eOBX@jSx)XPS5t7SJkQ-iF}A zVjYc0oc~|NKSVF>iVUHr3SYFO=RL2mNu-YA=YQoP;x!a|M^Xy+lSbpq*Khxg_=yy| z0F6w#jr#VJAb=F%J9%~MFH*Efp3j~eK8u318=3hSbBI-_gTm+g!1$L zf5aFRV$v$jM({I5-R^kFC){jjMzpoo*?r>Ws5U;2y5vD_(;`?M#NSb_ zDc_CSsJ{oecef)E47ULmNQ5ak2{|m(anE3|+UChYf%w;aKzte8_>POt-^3Zh{2^Ab z8?3<*5hkvw%I_vTRm*nG-iP-~l*Ls9NuUYtKQoCGYoOhWiN-IxxhN;lz8FoaZj=7! zMEb*j^9TIcO0pfg@25(*U>%c*lr-B4u(Q&E2qnZg-Mkdf@FG(%UyKyd(V0uCXd zH?xobI#=bUBtHH~#z+*R(-E8x&$S*5?KpEZRgF|Wp?EL8z9~IW8t_eHo58bYBk$pI znDkD;0ooS*E%_oU8&@|8jY~^olg>zux_I?_QAI=Vlj) z%w9e0Bi$R2k6mp3ot)(TH?EVO+IWA&zq5Saq`tX2-^+W49}m=YGwC@#@1q(vWHOrS zwmn+@Pt)W3abEBcM+idde1r37r!hta-?% zn4aQ@#?7#afwNnqHAlNt=|DIrr%c5LSe^2Y5v5jHlbUGZw&+DORT*iW!2Yl*5{Qdv zpj`j%7c)K;oDeR|RuncM#nD#*B0QO|38d~#6?}cub&>~erd;kfbc@(ycGS@`Dr6yZ z^T({1`grT~AN*EWA??oEd?^O`MRc=ASo+K=z0)WhjFxn1dd1y>y-fL=1@;UiYr!-K z_6`@+5p?z}oTdOp{Kx)hpewG(twfXa^=O3`+*wg!R+rhra>tnRRXeg>rNSA=IHz#* zp}+_)K_G@YB-&8l3}xHd4Znb4pB?%Kj8O9=KQdSTDO&xwTiZ8&{mv9e+uu5(?&et_ zvC>A$H>)~J^!r=&Eb9|VZr7vuKj%X^S%GfOUyn}%pJ-q3k>q(;7ZV(<( zW{-Dv6okGP52jtoK#)sQCtgVG{-Y_B7GD|BG(Wd@&z4HfJklXws0!SOR#c>DMtUUr zXqEh<7ub6y5wtxC45xLgMkaBm$Fr<)v;3}!1*^Y3NiD7rGF+gDxMTE|VA9?G#B$a; zdS)iR@r|n9O$4!A^s`vdRvA-RHRzHkJYw?B?Ap9-U%SUsPM_PeJ76t`>qb9ZT|k@g z9;-;uWFs?v;?iIiQ^;QjN-w-r2XHhH9@;kV4bUJ#^JQ^!Y##eQ+S&9mC2m8T|EWx!{g1J;?#$(6@R|1s6;qe zzX&n1QW!mnEc#YGH+Fc=j*@OZr%0(MwZq7g^|K}YSPW%bdWpu<0lem%pFDHt2^Vrx zHWkTVtSD*=i?EyWg}k~ma@%x#$usxJ==({{FQ;lkabj=}`4CBGUhkrgQ4X>EC47+& zOxlL)#HP`9XPk;y$MXeU>3}rxHT|eVl%G~Qj z0vXKzb*TM=Mr$=h#c3EAe-M2pCQynE%AZ-TfmA=I7jBl}nn&QYzU{W4fz_BnSsO2v z*3<2d%zYafD|`cr2W20xR2nE%NQ=Gb53&SF#W~QPisCe>Pa2fzw`?#`7GgP#XQ17CcjEWfW8KTM(s zf;&1>g_V(0fIkCpijgT9UVUHR=t__Bd69IG#o3;H_GV!=g*U4eV>sx zm}c?0i{I4->|)nHy^DX=_%S&R>Td0L=;uPl)Xe|Bp)^v~gxj>+%u1lXd_427a*Vf9 zPe6OHs;XMOKZ03a=SD&tJZy``DhH&L@WPO-4yeMr^nr!AW{6rloA9J9VLPO^VYoqk zQd6r6epaBJ0!TF3v^65ipG(0YTeQ$A=4AFM9gEkH^H1ca)ZtOnWs<#=vWv=Wr1!L` zL_~P*liFEf_i7kgbE-&D@yOxVJx5IPt?6C|v4*62L+KhtF~X-%jXB*UHOCR{W~h=p zK!yLXSmt;&!}=q&onIZGkZo~qRTB2|v=i3bVP4r*ws3uAYklN+&rr zn?klqNhg)sgeFyReqCUrgAvfgYiTQe)e>j2{9m@qg`MMpt(JTp*eUdX$*d@osrlaQ zybVflL5Y=Jdk-q%V*_Qg+PJwHZ(*^xo9=-%N8Uh!_zeLp=v7TUBe8fT;XHUrZ;ab| zk(~B`bCl5Rm=V@6=WQyJYIBWQ$zf(fljr2Rb&iDlhT4~&rm(cIp>B6`QR}h8xntyU zqCSb_ec{^ei$FPg?Zkp6a!*o$p>R`W-*nI=Sfh1`1Z_|dVtvmuESD$pE`h1(?^Wy4 zrZV=8dC7rYG$KF_ zhr!v}(+j;i_5cUPF8Y)nTh1P1`7-jdh5!0G(hpTIC=d!-He&m-?TP{2Me@Zj$=wW( z?~Yp?V4JV03qH%bU&ah_A=YWT!X;g9wN^XzSWI|dl{Xg8L2UUahE<3(%od@Ga%via zwl~@DrcxV24o0qP!v1NC#;tAayRdfgCo^U!Ur>AHtM%KyV+8p@X&v zcfrgUW@2*~@*UnP8jE!$G5fV~x~o12_lbbtz(c^d29V5WwWJzVbx*+tg#EsBRTzOD z*YnD(_;cj-Iim0ownbIiUw$hJHtB{@&r+nfu%r0C27XF2GgjeP4lr2;1gSKK>3>E& z7eBT1DR;0fF>bl9WzWNmxM0bNfdL^#>>F30MLz=N7Iv5yi5t}ZHlbrIC z-E<x6uy+(5x=@@B|L)IBWY2P3q`p~CJkxg5<0^3zHL?6#V2*l%5`)}L7mbLQtGgYQ=CiMI#MV1mi?(w*)xa>_V+C0y zY$cDMsq#nyPIS_{2ghPH2Ww-ZiCY0=%polw{<7_(;}|_uF{My`bNs}9Ywi#gqw*Gl z(!9Y~O7I??7(iqLNi#qz$zHXmV5)5m)oclp;MF+hg6d30U*XXqnAYy3QRvYdKv6=4 zm~ufwe*4Gn0s6akPdPPxqY^}w~L-FN38_LkDay{VqPdXS84YnGZ*s{7JgrUPG;C4yOay8Z^{M(X_q0i(2XlV8@ z+TD$OiT_g52N%p;OP7m1+0#6XDWQ@{*@y#<;k3nr^rql~n+!6#+tYy`067};C3QB$ zz16}OoVcUr!x0I%?yB;$A1yO;#df|6>!2bU8CPgd#zkpH@xaSI$o@eNPOsNyS z`)Tq%i%@cSwwH>kw19#`5b`1Pd(lmNlA@E)mGOM9fCi=-8#ql&_E+Z%}<`lvLT7$W@yy5XzH;g(W2$ zqf_fMq{aa^A!Yb0_EY<4;4Tbr3ZkWG3->VY`C0nu8N4ChXcVCy*@o50+uN(6EAfn> ziZk#d9!v`>VRM`;&{{T}JI+l8q-5_;e7!GTFv?wJfFJ`;dI&q*l;YD?y~-6=R%}NRPejjXAaf@c z;!@HBMUI#uT?{f7cTbw%-gs4q=UC$wRmQogO|-VaX}x9~H*upNWRpO=bWy;kwWdy(pMZ zPzG57uasQ*+@|N=eM3@E2j%qa@y{mI5@}YHvwW?<=^2t?vYoB#lkHqy%x~6>6u))V zafm3Z8&P&Nc$yv0f}j0OmltnbBj(3<>I2Q7X+sTEdF=ib@N}+{GTea%B7aL-s8igt zQOwY~3QBjZyZ{1sy6|+v7V4hdE7VqBtm#a;R?tk?YbviHGeC!p;sF~ftM4=&>n-FU zU|$d%uh!6TqR+^uu!gk9_)Ao)7#Hrwi_d=KhC|ql5T)PkQGxAi>1ta!DG(gsZwxZW zPXCvPjfp025Z7bBpM)yK;V9$c_QqrcWZrcl0D&@MXR>6;vi1KG&jw+@oQt3I&fDWH z>U(0CSt73S|L}l>O!>Rum*nzGmZH*s4>QX}EcH7=nGA? zU+_LU6$m_)wpyNHrCd5#^D>S?bdGv~0wR9WT0%-|9uVjb9r5#Oj7w0-)K{K<^Jkoh z^+28(RH@Xq|H(4CIf*ydpRntr*imKcLuwC#5cG4z2*fc809a-{sS|sZp$;Gkr_0oy^d&6HI*v&`eu{04bV_#}{ST|; zTBO~{Hbz|pK1i`0%L;U{0Srgg{A!9rg)T*i`qs1~x-PP&P5s;K@p%CRN$Ign@Er=MEQ%npH+6VCN`ql?8+YHhR_nnrJoAJCuPRnR zV7$IIOLTEQJ>!G##zL~uX7C{*I(Rc^8B9X)iMcDk7gYq6auUE-ns!!3`c)Ud=n*ET ze)QfFkhb!!zp)K)Zr4|SoQ6(l}~Cg zC&Wtj<%chj(BB(kBJyAqL{`^5p(YQ-+SXfgW8|n_D)bGlcgoH3gpA0UqAFG#iU&y` zEhHLQBdN$quh3CrOK!MFZql&pV)+riJ^2G*DJOY4? znbV3bdqQ3U(bY<_lttlJH(jKB?OO3KA~ z>2)X=?>;#EzDHa;j1E-TJq+Y+dT|dYbJ~M4h}4N4Kd20ritZX=GnpmcHV+Q&YrB;9 zb}|M2hsYsVu`37PH#)r1E1>ea%Uei@59R{G29j=;;^YVZ5hU*dV`K(A+;ZJT6emPbb!Kj;zlbz%4Q$T z3Ex3u4tdO@b%Q1@Dg9*M9M8=XnJDlB8IJ6$8cYKhcfl2v>WH@ec@gJRMhdE5Iwe4J zpVz)B*wLM1Qe}EC8w`dk--y2B+rp`UF1UK2Njx-Hi|{@TKDCQtoLBPGEO0M2H)VS+ z?Efys-WF|T2hSw`yVzC5PJV2JI;bV`c5QKY0q1;(?4SO5Gblo^uSO(x`sIsvcx3JTTkS6#*?ih-q=h)xdoV|0OsL3&LQsHO& z%hE=8Vmyx^V$hzVRl-xI8<>0mp+Cy0uvni}dXy}Ty65{HI@4OnFWd&7e9Ff9QCw65 z#yf4zvWOTrq`Lqu>o36Cc{Ai=A=0#6j=Zoy?ec}trCxsJjp82y1bI>W0B|0`M_UFe z8TA|U!11sVRO{N~vmWsbpX57AphgC1)iO?tikT>}47exb0sSSi9k#JLOYdY(`N)Pc z3(8_WG+YH|!Uhct2XkbA@(LpAZjL_ogVsS+76&s z9>3zD1g-g_|A>=SQuc~-8zeEY__3%d>gP5^`mb*ghMP(7v*skU{*b3-OFrCzY%y&E zWNRDx+xZsaC{BaCr(1*>DKI8>!@7##G<+S=(U?u_OWy^!?U{vY_$ACb$w>;pQ$AI3 zUlzsK%(v_)UrD5sRpkqijrJSzRNcc8?=<{CGEM3pDX6gV+>N&N)Utj1)xCv)j)C0s zo?Kd9@%(VufAZYcwhi58k097e3-}z3cTnfsYSOieeY;f?VIPqrlRj!7640M3sI;yQ zl`mla0{oJj^FqDift?b#LK^Nf4gPVjtfw5aLkCpWX@`aUaTbn$_28B%7?z{f69pl9S>Sca3uZe2Tr|@pE_3rHyFq$~+y>rkwCx z)b>A^7=c$^TMkXN%K$~qaSR)$h|cdJeX-skQ~om4j0MN~s)lJNYmyR0ngJh|4QqC@Ff}|+`4n%rKZ0D24$PJVEQLv!5=pxIQm9()6 zSgG9C{u0?HkGi7wy#Q+g4*D5u^H{-Zo{Ue%+)uP300F$2@p1KFcLsWQ4LFq2S?L7b zQ~9>u%2f!dQ8Fr!B-CSYcBc%pK3i_dqGqu9AT>lZr3{?NCVszi9{H9}JFdfwtd&Sz z4%z6BMZqE>359oRX!P(=30-jfzTTL`?nwN!>x%h%=jlWTIQbxSc0CAi!tkk5Ra?$`iX>v@z8Lt+e$nqtg&zfpQ@TjMtBBJ_SkJ7Z*jI$oOlR+PhffU`mTZHw`os`D7?yHTr<@i508Ys3JkZA*~XDN88@=- z1H%m5b%Xwt4LLL8GXy3zXo&$&XG!Z zM7zC;#JZz=r2YD$aUer4N`qEDX1!WG&_j&LiM@AF!D+B>EUu18Gd}a4+@+-J2#a4{=zrjZ&jUARd${5wE$>FiZT{!}P4C!;=Yjur%%(bSTz_ix?6WT%A1rw~S-6OYC3fx@ooG zbsv7H#?uoKcnGB))CfPd>1GftZN=l2fh&6y3kB(PS4c8(0^H`^qHL;?)^Z=S+d_AI zLp&CZVB0}~jmNT!O5LCVG>oi>OSveb0St9*_oH$sW_H^5)-^LY?#O#oW^Z)JqmJ-e zR(1rpc-ydnGt(F-9z@E8pqoqJo0FhO+o8(=d@Fc+1AzD_x`@pyiO2I8kdX9ijGX89 zkaw>5w5~x=Ww|pcyZ;1uE$+)V{QT5=WjbaiQmpHWJXhj<6_cuulqdB;ksfpbmT_1@ zl1TG1`CTj~#m_D(nzeo#dJ-LwzkX4Pg7#}t_lQ>!lnza7Tx`Psmbvi^D$s`_Ob0)% z3A6IPx8K#8jsrIDSb=7{<+?p5oxd-K#nwY)RHE(m$#FoJnGIn%XU4S?PizOLWTDgL z!?g{WTV8Et_^=3y2N0#=82J;tz91UO;|ZAIL08UVqa@2wwD2FXv?*(J^P-2O5&y;L z&2?&@JCMp@q3L+@4hS?#Bs*UlD0F7f$GA>g)L0acLurIg_Z4Z!ufkSP;qvOJk1rZD z(MajAwcD|CY0No`2G~RSZ}&!MG)7#4H+YK}Ik= zqcCrL2jNx&zb&FkiVB%YoWteeP!*$HaRP4-sT?6^Vwcp!NWz-c-h!;*WfO1mNXz* zZ@zpN$6(;OwQ6U#BqiJ*Jsoxcqqb;m+Al(X4zxMr(u3^!?NVRZvyoEhEpzcf)}01R z&_E+Ju8DPuwHDha_`K*3fdy3a`+{uU>k}6yb^Lgd*Y%$ni2P&(!N?z$e->b zLvYRnaPZ!Zjc;TJ>5GqfP~IdSeR)(eIQyTI?)&+~)YfgiFG==H@XUZXmP1+^D=z+V zeEUz2NmCi|{z@bN-~`!4RRhS9<`r(ZNiXS2b9eK=B9ElN#+%587O-^v%{bvKU_8AS zCyQ>}`~vZLL}OZW=kcscQ%j@5jb)c?^UTs7&7%7kT6#Q0e=vjWZB6MCQBimVQf~Cn z;9!zU)agy!`2uCd=hsez6_aKTpWg{-Ykg$^pZr?7tG9I8gTSXKTum0Jlz& zDP_v?z^|%<`5Gc~#u<0(Q4ct9#3~?otk~k6hhh{ZNCBO|5AmsW|vG;_JFBihY$E+}a)* zub$}F7pJnuSiGV%Aq^lt<;%QfnT^A~DI``r}?f>|n{gxgkE3AEhOsEGAHa zCh=!iZ_EZl~gFS$u6W=;7$ z*;W?K={w-XpTcy)$G0-MtSw{Sx3m;!A30_^B*^+DgEgP-P53!lO_vdWX?Fb^QVSC+5!b6|dHmWnsh=Z!!@`A>m+rr4w;VVAKn zMn`w~vv|4bciA@sl0%~}Y5T&%YXF;tj_EY2OSNpH(eeU9s3*p@+G7sK2sojy*( zA~!Z5>GW(@Sd;czcO^HCD|dahPnlv`S^GUWBwJP&M4uS=QJG&+-n8Ef;Mdh;naTkn zJ*J#yZjoD7$<%>j;;Q!`=6We(A#5uUnb=yC*ge4bodiv$n$4sW_P%tglNqFX7c39a zCaGwus_TnQWVH{W>I6N+lF#m3q$e!*E2m395No<|o^-^RYHswyGIDt@dx9}lz;M+; zCUz5U5t;D(a6jLja{EytAVmtRfm4Dh$1y5Rq#vY?RnECsa!-U+@xyrFj zqaBh0O8H&WDHpWE$pw@g)R}zEl%U>)p)7R*s)MAbwD(_w+GIFH4|2;ydrufGaWi-4N6H8o7P*e|<7jUJU3*3Wo){hn#v#hb(5Eo3q`u~K zz#sY&EujRGapl1QJza5>+di+)L(p8qr@IeM(w%e0lkh8gVnak2v388ldUB#MBz?l3B2BVM);F@ap(drFIhzEUDPz9Dwj;9#^+6;yN0H`jSBdkF8Mq;`2CGEw>k_-Sz_Hr)qr9So zAi=^aT%a+Y^bhtTSYoOk$OX%QJ~^6EV-5wG9om4{CTNMBTkom998^JJJB6j0QM9MU zSn{>9*?t6z(tG*5o)7@7N>lL>R5s2nYMhK z;rc2T&I2m^(=fH@-DYLzIFmQqY;3v!I%bsS*oHCosYA7j>EB7Z6f*5}JpSfrdKiy` z#m>cSr&BItUo44CK6Z-h7xY@N9|qluG7J;sJp0o=T8#U&uk4nLD$l<_R;@STSCI#pH*6R~AvpsylRE#43NIcZ;WATT!60bg<7?`z{l8U*1s@{TT}i z=I2&!FUr{YCPch8m4{#mg&;o1q3H1@>gD$o{+P>_Eu*%DpvG4LsZ}Ob%G*YZ^S_rP-urgepAipAAwxQDqAp;jsyCP-H=- z35!z(M+}Z=N8*Va)z3w?FQ?c8M)&tW${2p+>v;{mp7OxV*_m0uwWO1Gp=CZ~`*BFD#53(PxFP7wMD-S=rx=1^&}25|w&%&oJ}=_Bto6;Ja$6W}8krKE zYja!eiW{nFWOFx~vqGreyf-qt@pPiIlj1_O%g#Rp3+U>@Edc_wH11)qZ$c!$K2Q>w z9w+fj3NExSU%SxY7poApn5{IRsZh5=_b(-QuXr;|R3c2a+jqCL0G&;*q@r0(cw3ohJt2fZ%mN{& zrFchg4H@HFn@vbfMbfybqGHkp2LKHR)KbERf#qNpC`wnKP&i3dPwOqaCk*J&io?A` zG)zXjxZ>=Dxr0w)coKGBiJ}eLWAj%S#`En=jL2aXb{-T}L=x^tC!n1WL;94Agr)-D z9y8_cnNXom>L{l;y*)@_xIGP}Q(wjQMj zQ5K7Y_AMYL<=HGvd|<^LCIxC4q@L3NB=yCMoP<@$flq42|@xuP-?7d{TJ7fqj1-_gU+Rm>y(tllghH zBA>?nQPALcA)=s+{q!cmTTSmc8fqMEzGh05bJT=$tma08xk)Kjy%&-;Je^eLBq@Pm zt?V|*ZlZGD{|i__Y;uC$bfzw4cUpY|RU;qZLg=oxw(}TL1V8Pk?2SN~t`AeO{(@PC zN7y4F8>3<~`yPKnRH<)*wz%J=#alVIw7qk(<)QVya(oyMT>dRpd~xH@*I0M z?$jA(aqYl`p76HW0x`AJN{S7ow5e1h3Kf75`AMHFJFBz=CkwTu@2dLb&-#G{6>N+6 zNw1SpCo4Fw5iLO=1p`-TsTL_I{1_@RdDj4kBTDlZLN=0$+?589bqd7&j&eYgk^pcJ z4FX3fU?d07Y7Ssy`|3ec1;4%>aLzsgZt*(44D{SPR4j?XAcE|QApF9y7c0pI)Jl$72F-Q6>@dTxFPAW-=wa()4c4bw7xTUSsU^(tr9rd=02O9<{?; z+vva6dSUUL&TIKZC!@soepp9M(YF950p_=Rd`*=Ru0?Dw@km{L4HbT9up(BGW^j>* z>EUfFs_>~IHO;!G>6^FLh`>s__}*z#sxWl2i5#weTRCQ=Jjp!-oO?oNM^Vyf+R*_2 z`1ROX72Z|k48pLs%4I6OroTg8>Qs1-4u&ApZ1W0mU!R~1KLpQ=^)cl36cu8beAl0k z?RazI(yVeGnWW|x-eTbp(=qX{PJuSmb=j|*<8_iei^mz_JhYe4fH&YlS$S?ZG0Can zvs(^wCyr!jK-@Z7p5uD6pt{lP@E&I|Y#kOp&!hmGzz#p_BOQIZ#u(*2c?w${-@@ds8( z>${YUF}Gw?#fd&cgN7kb_yZjSrM#szlzB3hNn^`#>Z^MI3|qOK8yfQ9lQvDomfqlW zuax1Nal$!+slH=o_>;+-dJ3!;?jCNDsPz!<@j(jDC7sgcFS!ty$tU&!$3%#E<`p!t zxq29bC5+Z(B zJ?bv=q64Fk%$~R(ujDp`-X@tZSCjN4_&9UjB{fbsht9H+bkv_kSb9MmnW1VH@cHuN1~rNF#%X8mtb{0afh=S z> znUm*hlAW`%^9f8Dd>t+|$enSpVJ_XGl+Z53dcQ(bYD{KzaB;GL9GlnFFW|RQ_P`u> zn3FunbbjW#N)AuS^|(4ib+t9F<5`0P2V{fh+h1S1kD+D8X*(#JCm(G~XU3?Op;+DM zlKUhqv-%2-J|sJ{8fB!B5h6Sil*e>Xy9Mu9Pf3!0*c!tVY6KVIA-f&9)({3vKD9ve z_`SLS{cYB-on}%wXVdM{}nB%cM!PS^0-4kPpv)_E#?0QNUz zlMNaRSQ}C|5QNI*mDG#QXNyPYJ9A<%?` zupMQ&x%8hTTFWhr5#L*K*h5h5Qwi(Au--}gE4!o5hHOx z^}TD0i#jU;Ebg{lNv^F^2zenLqU3@uGDQ>TN$#O=fx)#9GspVgZ?d(T*`pm<#7L<0m0(e~vwgA% z_7J91R`V&lq(@{{^q1WXPi%MF6_Ve43D=e%(Pg!A2^TE8Dg;j48Y@tWx!pmC>P)xPfLLvM>< zzMX;jRX5m_9_UHy_Vm4uP}>G>pHJRb2RsTd?h`{3$Eq9`zrXT zBQciDQdFfZryGTgW`~~z=hk$b?NU2zkqxnrKOqgOO!P zJ&%W7x>RdlYZk-tQOhupydl6EhM1`L%fB+B@;HGn(63H|`Cvajt%VYN2}F_JZ?zRr ze*|sb;eyr=C0BT2w^7hI6g|?Ehxj&p@Z=O zCQ0opC+-wOD#CrTb7NiX)E0D$Kl}>o!DPNbfXRAJQnoUHEhZ3VTBHrMSQnRlQYCudyeh;LCE?Z>7 zA8ydBx;uxVX44#z1wN87lNna>Ij$(z{%ul?VR&Fax54oP6;Z3K>&nkEAbeFQgO)GA zZZra}EHUq9;znQeIYz~Zn9b@T3&-G*45* zgd{8gq*dLiIES%U^FAuq{Cp-bvxqeNpkjJU_%S=Qfs13ozRXbBWcjLV$Z~>KZomrE zzQJ7+)@qUnZ>-Py0uCVVT`{Lqw(dP4Fk%MppZ|-QE~IQ9n+D2BCZz8+9@YhIa2s(+ z@0TVt$U~<`CoL?Za_+Dgdtna-GX3kF!7JO5IWy_BvD_Mwt@8JgehE&MzbRNwcY$hgiVh3xsF(^^$qDdIO(@t!8-BBgy(hTcT{pC=pdVVX`t0? z?bqq>j}0*aga)7lh(lw5<0?llo-?6kN^SI~*@w6gyY02=$|Rt19tdv)m=Q%u;07wX zw&-)^M5Uzen%oBpp4mPv{{83eVa+_C?u=qoZbRiHCJJnN>p{H~p)SA5flVaZLDn@; zLgaK?C)F-?q?JFMcmL(#)}}>MW{wG6LQL(%y$VB^LA30?j05m!krFkH5SVWp*>BtNV%i2y&4Ew|-$Wa3!=;SxEFFNz;LrU$!o zZsVHFr(WJ)2?0e1!0I#S)~`DLB97(?*A86}bJeZF7u>8@TNI>SV%Tx!7C)>6yxG33 zXBrq1rvQx6!lWxy$M;}pu`|)MIYbAK(M=-KnNnbw)?Ei2Q+E$uAiZgTzr=rJSpyWh zYN*em--uyY{^u8to+gmhuEMVusI#KdDOMKzh~}#y z^&PGY?09f@u`TWboR9%f^1YD z;2+~>+gv1(u~#u`GlQio{PvK7ePx)>=i8E*zdXkRdk);O3OOM$0wm~8kI}Z5EJII* zG;8Ful7w(yWn&&j^i3^Q*%&WKX0(WvJ5sFTA67)ibE+M%K&;zh--cwoHM`q(JU;}K zWOpzr_f;v3{4z%}_60fgV1~?(jSmYpAmFod-8c6oapQacED(hn1P}cUW*@!a1HBn2 zrNu8Wypnn9BwgBfP{pjq2+x%LDgS`PQtUy!fI%O(B3Nk4Yyx=_XPL$z<-y$aLF%!k zvL$_nUeK6L3g8kYKgg%$@7JKYL+G(@7HH14Hmms5^xlAzZ5kp{X>-NU?guEiIN_dl zJJFU3UZ1hJ%u~Z=RYAmDvA+|CFOh5&je1NM+^ZG*@8In8>O#GzORhD@*=stOjH79` z+D8M6kcS+V52>voN|;iM3HWr}v{W1@DJ%h|Se%iMwtg-d>w4cncqk=?e zxgbwHjP3pyq`|<6 zyXp^LsNhPxB@b*8#LLPRwe5>J6G*R%5Vws6K1uXT4#n%c2O1{plL<8Z6zBJ2C)c=IRc9YrwHdZ zuM}6+cB_AAGE+RudrZyoD5ux-%RtkC7xnUoSj}N9;80T&MahJY^lmLX<`+)Bn=n04 zt8>dr@hZ9R*n80ZEajRXm05(qND3=cUg&|BDkvD)T4t^Xkt&ISpC*R7fa8=@#<+Sa z^M22h=-%+uC>tBtz!An59U^lgeCB>bB4{*QoKFr4o{n$lIF9OQ40}dEf)Ojl!nACV zJ)clqyOTE;4WYz~WHQ(ms@iVD;r{2a^INN~5Myl~7P#LP4A&gj1t z7hadr)wXsFQeQOx1I&=J2a1}pQmAq5_+f4+N)Pg`=@02CkuD`5xx(5bOVNzr>M@`> zVip~MN~U@IQZ0UmH#dFe&#le|csUd~1u_|}`J3rI(TuiH(C|sJDsWvD03BcoVS z?|UXo@ctPvLxjuZs6*1O*#s<@=kjE~@|Ay%{@e1cDeD0sfeYX~lnSC~fM5V}wJM1z3H3Db|i=up)_sdsFrs8H24G=cY`_mlv>0lj` zjn_BRE_va!FPqZ4$B%@UVD!t~tH@xCVI;UxmaiA7T&mTW-)dGF@0c0k0uZKUEM)GG z!xKRFKb>>mWDFk`LS2kN3i7!`=$9Xe>6~wP`8U7D@M}xpWz;N6KNlLVZw!mT@Ex(S z0M80LCr7~@ds0kzWC67%CMf_bp+q60foiHiHf%b#xl>!P{*bCBWKhh6CT3~4+ZAr( zjp&G6fJ{%ro`b?yFVC10k{^|5Iy1{7JJj-RbqD!&xiuV@(yK^|Fy)r9M5{;TETT0N504@ykch;W_M?LhPfd&L>k{391mE|6wo)PxeV zoXcTSlT#=+iC_9X#Q3|U2+vh=kW6MZaV{HqiW*I%*h0Inj)k7d;?snj z6$Wcxl0I3w-^~(s9cxe9h*2Acnt@sMIeJ6xAsIf!Q1={ zOr0Z-_b$HUaXR-Dzw&(ieLsNV%*M9WdA7-b(xy<^6)&nK&@%&p12UD0F*(!p z)eHG&rTQ>N`Q}8!L%Vvze9E?Nant^pqyK7r)1?f zzwrQnjIYz?iquToDhLd*Oxe$ zYRPL!Iw$QMK=-jio1AZG;qQcqrV3cJw~?s3rHzma&Alg?_2~o>fi^uh_I9F$28*pd z5{>pG>lr-Vx(;3R^?PJmi>Yk$#&nuYoe7pIFqL?a7akw;VR${^WZG>6F(qbt+%$30 z+&E`|sQaZGi{&zvt@G0dtrP=8Hk2*MMf6Vnc_^z8Z@X@doN8l9IJ*e7^P3Px35n!a zH4%Mo{r|7l{m*nvS&qL#C(_NEmRIRDN3v5jdwo-Xb1eiTGJ^%F$h{oxSnXpml7Uzy z<-_V|?BUT;7aWB~h|D9>ofy4)X&@G7-Xnca=m=5OFe?rX{mKKAKD`!v{B>ZeQ<&@c z;nte+fg(;J#%z!O@bVI^eDp_mRvPy~cD(=ZCbMO;Ae7pw;B_vzHx-fGRZ3rj?%e~7 znY_j)i&JGK!~GcSqoz{uDTcdn<-znR3`D$%0;4cN&H&U3PNrker>^3V2igJq{FU@~ zBESCVB~8G@^`?4LcqCJzIat-q+N0V6l4FaBTEj$0W_q-y9*V{}>*>dwjet#@Dj>zC30Lh{LOqDil@d%<;9fMu z;!k9xN_SK_fDca@ubKPLW#b)Z`Bw?zt?xb+fHWK?rV!=eDsChjcwS@vB-P2E!`^EPmVpg|O7*Jvp>#I&qBfvc zAVHfVXd4G~GUoci<3(4_{U-&#Q!nczYA$`ELnBS{HvUhTxMuKAt~Y~XB9G{%y-pKY zx`uL%|MvcA)DR@*K0GBZgkc&`IlwbwA*FJWs_a-DYEEE^{VRp!a))piq?^`@6-CnV za(7kAFp$%&76!ZGIB#0d>X6p zC;Rm&&Am8)zsHpj3%_kxISw^ac1j@+KpM;8SFjxUw5SsqO_Rg{$;JDkTEiyjwUVyE ziN-AOh>pE^#$@YNCKC}p&NPGgMmgI}dhaGenvu%DICi;}U~yN|=g1!?EIq+*r)ch^ z2-39|%KnJ$4rjL(W?few{YJ5%eC>Q?f@F}pbc6aZ0SkNw3;vczGush#%RN0^L6{KYUQWv2A_~tGaIr9WZ|wKi2zS5<` z_8li9&TnSu3TV`t!B#G>qY87dj;K;A5T_YpO&C#oXZ-93AD`v)=z8L(Ab_;^)Gi96m$jBS45Fv)b2OEhJ=&#Ekk zGxI)gbusuzgLu@`DzJOO%0IGVB6*@-?MipLn|QGzxHOQzQ*JEj@1kr4MN2bB3n$SH z*GrSo_9u`IDCUGT%OVmaD&t`NjuvBYMXwJhTW-lIGazObh&rN?JMzVA)qWhZX>87) z9M%Mfeq2!pU5=~m$DhXFJkj`7{wH4!QCG)wEE%QEXf!F((6eLU?Jrn`3q>Z;lGi5; zAAf?;3620=l{^W*?OSZPsSW9_cC~U8BD>W}`8F+B`Ex5pFSs#A3_O4;-Zk|d-WdtU zo)tX>ta&9EXQrf@qEYbd*1-rPgfv<7^AHfvRv=vCCD#nmJSwv2mCsi$O^!ui!;kaF zi9h?vHm4IA%zVoXjJQkaKCB>7mB;Bhlyw4rf*rIP=v9UP*_9+@eG!FbFpe=ymELj# zoX;MT$8>PFpcY!4!5K2`-dn%<_Ox&31=kBLWvF*R1!1a|ON{UIEy<9`v1K*?B8joV z51o3t?H3gxo2pp!npK-Fooi~*othAjGHaYFKa|~#R09BT+hBM1g>)6wT9LSI*S{bE(2 zpb`v|szDRYw>rfIpJ|L)F@2go-Bzy{?G?nJicE%Tuc9+_yQ!sJTUjNuZVDf$TwVoC2GbeF@N>ib$b}qxEa>8dvJ*mWx%C{WEJ2)O zTouM8LAd%USC63Q`L%v!fqD;*aZ^E&d1i`m!GwpdPf2Ut&_}ee^Z+rh+gF0H%=1IS z+>k^zEv3hfv3OV}&2eq#P!1J$Zp5ye^@Oz}iGfEOXZ#Z=-Nm)_#wp>hs{`}ZyUZBC zV|TNni;Zoo%qvAKoy%`WUO5$g$83Mqo6(9;mEsmJe=bndf0eG&iA3s*v6Zx3x$Ovj zZ`EYbuMtb+-bVdYR2bxXncG9YpX?CSd2X@AHqE&0Od(GCBT`TBoZvL&3cocrYLj(F zvF1%W&g8C2>UqTI1DM;q1`oUg1K_J=r<`rs-M6iKDKgA_FPKQe+fsJ)<i(^78s_r=Ms{qzW%UBHBlAsQj99I zX4GHZW}S4B-Bq-2IU1jHBG9CGYGrDNux`P!PIX56U)~MdCMA-Hl>7@kg1(8p<`_=f!;XV zM#)NvWA8e+yWpHLZwTO#bimo-$=Q8ZI>5TzwUt>7QrO@zSCVnAi-H8T&fk6N0h>l? z^}d<4R2ce?7hJ#QbXcvk_-8De7$^!S{J__py;|y|{@AmMs`bBw(-XSt+Kcfd4oZ5_ zOKTFoJ!9*GZu;NOWd0tO8uQvO^OH0Pe2JqkQ74E+`m%(ie@T{mF808??j0U?g zDyTx`b!AM$P6#cVK!qUVKomL!B|1Lm z=|r>5JjRU7)uKdpgqWoG@&B+9v=cmVQ~|ArQNig(qgjKg$+d#2jNOLw&NwnHm7=2#~aEi zEEoRdA!OS;5gD5_n>2uPJx|jcr>YJ>AeW+P1N}zUpMXNE9azHBFKvl>MpWyH0DMX* zy(hyLp_*#du$1c*>{Op=-RlI7y`qQ`BLjKI!Mz}wQ@qr9DV5Q! zvo*k~srM)a#JC3366|dkZtOCfoGQAYVE1}&z5pF&n?t$^Q0%|FfO1GU{@3Y1uf~}@ zBs}NvR9n$oM`U>Dr;v$|WTb7zbDFrTX!aE_lAgQYtHB{pE7Z=G;0%c>U;{~iHPIAc zgs^MfJ10LicCOt5yqNOW=S&iOdZxpzbo<$2nx*Kdy#KE^hF>KUcTIu+``}EQA!3<{Ho^i?QV7n%B{T% z@FRjdrAjPX_x|_F5`#y|nWa16yz{07oIm8%T!VETQI#HIW{A+)Eg>c^21HavmU2!!giD17woP~ z1I)-u$xFV1;>VTjU-6%yreGr*f!}cTyra%q$o{;>s#KcCEhxw?5sKp4U<}vkOO~zs ztUDF9@p?m3v+v?aHNDGgR-Fl-_{*}+T$-&FB%ik9gG{fkSP<@9-&eIUSFQ<9uXBuA zw}P2e6Z^N+J{i@v$Dw0hlX$fAA6F`@7vs69k{<=!M@bwYnbnb zh$ii`e!C`d;m;8ZOu9s`V1C}3t9$(4*no79i8h{i&^}`NXR*evjnei+n`XfZ_CLp; zcKPe6KPmd%%8R6j(;R<9O8-7gU1~7CYMgYtyhQv?j`ZWI1#16+WWik<^HAx#??x;+ z4{dSSbs&5YPM;IdLF}oW!o&&_C0@-plOXW};eU(4<5HqDL(GLkgWyp9q`I<3EOdpw zN}*R2TN^FUr$a9dGgQug(+Ge90E3tk*Fs4#+>)A#cO69fhuFG2F~|ftnl;%etgKkI zGi>jfoJ>t&S)S0rR|;Dv-V;!lF^%?(&b62~T_cJ*a7OZ@(b|x#Sf@iRuu(4{f6qyp zOF&2Gfld|}FyfwfNHM7GirI+uC`OyhhvDqT^;hheIcM;!Z~1stQi%~_Z6(hK*{>P; z+tL%pOQ{w!{|N^{{2 zU4d?u6y1?4kyG6F!M8e=9D z)??v2BO~i%d?Jw*i|)zgB)i5>XjgvbiLS=3Rjszh_LULUoKz`5TDIVny!N&%VrDF^BcxHM{r&Ns|x*0JyeYROo?!v=Z3 zE<>D)x$qy4uv^+n8GFBXtL_KP_!G%EP}|^6=I8SOy0m3axTShur7gCMbg>uOyu&Kq zjgZuz0nOhl1keZ7$<=lzYO+iH?(stEc?jqCz6?=T*`_T&6LJ2hUqphimz_&?l~hB7 z-}!nDQj~WpgcHMmv9{Mxv}XS|_w>+87hrAl&h=6bV=-~jKtWLNb6WFDx<37npio?9 z+oEstO@p{BA!CS>1AbswVbXS}*CPxd&KuqcG5!xt;#4dndc zowiifL^e5gdq}o-B-J3B(b@~lY@E;Hd~Y@JF)e~WOb3Q;Swi8teH%hx>H*yT zg6VOZ^# zie8e1dH=gjzTn0%G)9uLp^c-W9MSxIsCa~f^W!&V59!Rn01;YT?GuSVu~4_)%`bFS zmS=M-)952~$)rKs2&FFE6-8EZ$VQw6tZGZz4}T{?OK!Mej#m?MKa4B(jBbFc7GDYg z3^tG&5WyTPK4p)$-Be^G%?qBizS`H~h{?rKqM9j6i9F6pP45e()!&D8;(cg{1+x)z(||}rpVH} zBwr?PKGBhAawyaRtror3E{TH&Npz0{s}`_&MPYZv{fE5L9oEF(h0|r1GBzN9Wa%C8 zx!EN+ctws+*(D(_IE%|jNrhIT%)?hs#gd@`{OGO2=3T3!MNi%sH9`idu?eT(kmVzY;b}FnLevyG0WQx7$QS3y`hmjS{oTpr z-5qZ_G@ZF*4)MpopcNhaDZp~{m=u@MNz^sq$uODALSyGcyv%TxNMYWmZ+B1QF+%Sd z^w+kG`%?GRM!eTeIV(H91LmDVdcMmXDs1EAJI|DW0dDKuQ{wb%@Ujj(;NQ^z=w#Vk zBx?t2KfA|Un4;WOq9MDv8|en4J_<^V9G6!E$(PL*`!>1po?$)BPh$M^5)e~f zTbVUsD5yJR$;WZGz+nhsn9^tlL*}(0--#AQms0qU;!|OYHKu8I^7hU%r0}hb-djP> zMO+lLy4+l?bJ^_|0uxmr)NReX-_=vcXTdm&ewneKsr05=LLyF&2^xgDJrJNf=p{yj zMI2;^{B~tC5Y(8W^ks>-*k-I(;-{ZV#mMiWVuiHahXy}vdGGlhRyKAnaYn!uh9tiswBGe# z2MKnz$oqf&u&-u8?62&xm|H%Hj-vgq4wtN3Ko5?UBQ~#wmSL3hQRPrT%8SYGP@>a$ z;SzIohCkBFPzHhxRHcb%7#T?sKmw0u6!RBiR9O^~*fMKk;D$h^ZS#ljQHK$q5lil? z9lv#1h?mj2c+Qo10}@3a0CZ-_9r-je=k+G|2VynY#R)EzZzYizg8U~(Yp}m%WKp*w zD+2><^JDMWyP>}HS4V+CzJuyCQ}UbBMUCx&S7>K?ER2cMl$#ZVT3dzn%(g0yAd=bM1eV7 z^o5_F-!-97HW@noy`+8spg+ZDzBBW>M**}BCm$9aGWPZQJ6Uvt>CWVeqoYrSLh>^P&I zH5b^yA|plC+Ey=dy4F$e=7{b|wNqySb>g(sU2ID$Ca(jY4-1ZK5td8wyHF98zJNZo zS0PZGU`NPMz8xZ_Os~>o9gOMS?3PEOv~z)TrdKQ8Q?pa`(-%N#3@B7b9qxIi*UvJU zxJ4an1TZ?H4v=KE29H@=lwq{boGPtA!q4WZp=jpSU!B&|v(a!X^BqHhUe2wsq}JP` z^Jj}dqA&GCCh5aBGrrtWR{j7h;X(Iu0daz;AN6k+LlUpXW9F^IJQsmJPqiATM1r?^ z&fycL5^($X4Q!_VGt{QADp`pX&v^m=2)A?9t3=YF70Gy?H00Qb#nv|^3iUNSH9`9} zqNC;mBUG-R8#;v{BsXry?k!Iw5GT?~msKktjLl;!_6fyu@l$q8mZo6-nwgDR0Q%Gr zNZVy+lYVMkOpu}?C22VE+1n$Czyfkl9h{j*X*;Y2ae$*mL+R$vHg+BjXT}I|HCY=bAorBMWpFfSCkot9;P~^BgF^F(ENfZ(e{) zwxw^*f1^6@jD4K$xP>HcZn4G@%=|y~$#^f3ze|)`Olbs(95Wx;Ob8oP2>rP)X=x7~ zy#MwjV|+d-HBhIP_IRwL?ZFAL9ZV){S=2HB{4!SsK9+?uRA=J@=HN0zo#Xe4mmN$K*Q6IO9W;bCu6Vi5pz^TRJclbrRSOF- z%1_xH6IWNh@FeDjnqgK3oyZ2A#EEc&KuxtGqC-}g8=8j`ZdZLjC)AhM!LnLcH9S86UEPNJixiYF1T zsfMG^xV74au;uKO6%_&GC=UW>$FvDDPrevn#qWRK&V~ki!SVE0L;^|G+6u8#6ODR% z5h*?Jk8)|ZhC1L;5i4A*CXc(95fb(}!aNw9fgOh@O-`%q(%iEqvc)Y|H#$V*>_)X( z-d1L&qv>;X-*oII^>ZglsN2{w8|9!{g^PWz1OTZBIQ7KSM@Z^(5OMgt&e8RnLorLU%ash=>K~kOBDd7(&sN(%yHw4 z9>3<%qfy61cEV@)Tj_!;>Qv)mFL|-O?|uV37ewAMZ!~ZJP9yl!lA!FOSSeUxS-8`! z>ldGF!7=et7N{SW|CerXe}sw-5W>zMBrn$jtivQ9I*{x9JWt9rEEr@`G#4+h4nW?J zgojuPDcEEa>X0-6IVf@h%#^9i#&}eYvVdL z6Noqywupyn6`}F4rhrDDp@RqP^`bcELh#By(!Dtn`0G)IpGLw46O=E)nrc|K4+jU( zfH-)uVP1+%makDoqyUD@P7H%%B@ zog{9jZcd5DzU9Lc>@L>cZq@yl znKB!`+{tmpu8SJjk=>^%?GXm~ge}e>8QnX`{g+idtNF5hGt+0`!?EUzr?^<);A0Qj zcq5@5C6jrc3#G)UnFgh2ogcA(_aJJDOGRk$yUi0>5-B64iC^1^w0f))6&%sW$VlRk zxMzLyMIK4YTs+zu-Ob^TK9jDmlfReiTOB~6)Q`BDZdFF^BqE{ruEDK#x=g4 zM-_!u+;w5yRRHR>#JrgEfVA^o_`L@A)G5RGy(b{OSyQ{*;_L0>C2`V%lFL4LJ_WW4 z`wOWnwe;#}iV50^Jjv+?O!ru&p&KuL$@%5y7PPgZD5x1-h~E7!aGCKEIr^0NS1t5Q z|N8c&rHEg4S!*u^N$u{l>eIeqB-xoQR-5WT*&C{gF}@p0Of7>1kF1>jG}9=N_p6P>9aL3UiT%)wtQJmlYf3Nt!M8Yt3<|Y9z|!dpL;oa#4*m1C#?-f?vnUX!z*aa4#t6Tn^}Sc2X(6CdldXT=(1eJOAE&sEM8|lufTnoqL<@HX1hbl5IJeWs*I)gveZaWYi$jS22wkEHPX8+wLWC zXEqG}1j2N~*BkiW<6eab9^LEI+5dyp7-A0O*I**gv>s7%Jw-z4&MKsCM5QU&L9wcYzjf{GLxol!p?!`jV@66Nz>#tP1nt(gl^QQd_YB3=zfA~DU zZ3=!eu>!NP0k=yybZ}vL$O|q%RPyC&D;PuoQ>(!kMfJ2x1iftM0_v^F@=!j)t_k2` zX5QVQWX|eT9aXnkXtalBZUvW#SH(9ouqb&Wa^F4rJNtXPJFEk*u|8Kwsv?>-=fl3_ z>7Se5zg6#q*_ECpRrK=t6Q`mpZ~0DK{bmMw8QQ!t zDhY4P#*5DUmY6>=lly~wWder5_He)#%1T@$3xjUb{n9LejGkQsGJl1Sjn=8S*%f~;nK@SSbs=b;bL z5q`P*b0QfpOe|n&;-x%=6bufiGPk# z%9bfFYZEh&$Ge#22eU5;bp_0pcCpCO+fW^rFn+O+t|yMxd@RbHEP3%|2+4`1KU6OX zeV~f6!X9nxdm0m-cjahHoM?DL1G}R@4p*Ze zJ~|+Tl$MM&^Av|n%2n3MNBtYoqFde7`@=c$`9wuOcl?PHb~T0FwZxY|Q?f6}_;8_; z#=8iZHgON~|4y}ueS&UH7rN?zWOMvZWXs}9V2)+bl%Q!7d~UXj6=oe_M~Xo~Kct@! zc>tdKJ!8Kx$y!ZP&% zoWh98mey(uA>Hod1|k|dc}03K3o?z`mac9e)+((n_iP}{NXrqf4sv?G3-c~^=iNhS zw(Qs*`KDK8%;~b(cCiqTRh9X_xh=u@K?*?e_9K8v_*;9JgDk$X)yw6uCT{K|8gj{l z!NcRF46qibGAN|RU%b+rBXL)!0jy}TXAeO=$12GLZ>V=!CpBbYS;{fC#2RbFOG%h| za1Y~0o$$ekNPk~70S?$Tg;6lIB*_`a&&WLgT0OTI+^0NyefcSpKZg*#5GA>*al{V; zTXoXxR!| z;pxs?P&jT;aM*bFVFd^nN31QI{$G)H6@dxb&-WLcUo>i_zy>bpDIx2?yG2s!!6q&n zTmSVk;&!31n0Wbk{^8dX>x5J=_vxm`Y&j4|%79rBpvF7yso&7_-m@axE{Yp8QbtC; z-gY5IR-z62HRGHcQhIby1(ZfEa4;`KLQk}I(@fC6pL63BV#4g*WlBR& z8U)fU_lff&__*t`PStN9tu^DTktV{iHGCuUpP?a*-`dv>9#NOy0(@bGeTZF57yOeM zkksOZ>m;-9a_Nu=`K)lW;;=JK;`Q~MkG%-7y%i>E(dm^jwpq0BT(6|3OrW~3%*f^M z0{I1^%kFlxhU(mA#U`CBIsRu zqd2C-`awe*tMfIvv@N8KRJXH&jpDCEajB>FC=jJ@_cg zpLJ9Z;Wj+ezFKV$h(fEy2&IyIf-PHXjyi57a5FWOpB!$+A#A25HshU;#JQ7Fg&^j& z$G_$dwkB)GUZR{M^G*2WwmDw?H24j{K!No7=WWL=otA1rxDtWaP>m zBDs1`ALh`p=w9VL!mZ3K?1L_dcbVw}>GL1KyDOOOU7eam!0z^PnN`2?M5#M(5 zN+8J4yk>Rdk@Da%^yF%Mw$Zxgz3fT#ZJ^rP6)$2X7x3MjE$w5o+Bva2dme`1_2Mn# z&BM%{;|$4+9m%XOi2ki1c;LqRr^FY&Oj$u;N`8Hj6_8H-l>k`7)PEIKo2B!968wEM zU=AZH>DL1O8GtfyMWXJXU7r2Xt)&sIl7Pyq!q?iM)eUXlkpPnV;cKK4;I-hbHxDQH z?N;}=0G-Mwtf#R2KcRdXX(>#nYdmvEY6L&k0W9b=yEO(lR;%zC>h#IzV{WZ-Fn;}& z$k~)fkI}FPMIW)f9B25-$qU5?sz|fVwK)F?t_)3C;kOqUIpOq8Ah~6|!!1UPzM6W@ zf2Gb-Rqp>11}1}R^@o^;8bbY*;wD&Z2w(v&L`WK3gXcZ8`T}TxLLi+sWEPJ!f7{s> ze?qykXPZU`oG6`Xa{T*C=TzGr2SXG#RN<^o%YM%1rG3i?o0w|dn@h(Gi2bk8=o9tJ zo?=q`0g-d(+uh(XSseA;z*fwwak|EV#KjRr=V#z`Gz?HVeQB(B3i<5TNH_{0In;YK zazcr;7Q3yX!s<4Wbnr56@WDo=_pU6*ZsW*ADs4gY1Xs(eXN0dEq=>B?XDERq!G9o~y(%EqF zjK)%^8OQDZ8nh4U<-Px=XNjj~Tmk;Kmx~Fafs+AXY$h2=Ka*DGQhngMD;nRVJtg^L z_B4f(%Z0#UD%=kMLIPRp2RkV=IT;De8v+Y~N@@e+dya*ld=UaTUoQWL&rFQ^GqK*_ z+;(1mY7OWQacO0tBuI_#lRFpaZ3^_e%`-w5gkt%;sNE}dquL?!!NDBln+RpF|>5MeQ1R~g%aagH*z)vb~ zb%&9FOQqw_avj=EWQn-405uP2Qt{=fE@`eJNwI=*8i##LZ2F?(tDWCM8DU5pMVmcdNig$irrc2Wi2p9kDeyoK@-TC&5X}v0) zGxhG=rLu7>sC37?4WZWgo!ui%k_k2qc!c+#XNZ81fFULgQ@{gaDAKm}cK z6Wu0#G55led#pWd+)ygx;U|9MGCc-D-ZgNpR=|Y0*e7UQ%4VlAX1zs>mB@lG=C~2U z?rXOJxUtl2kxea6Ulw5M&_jwmXt)rKkEuzId{GPWMHFN8`P2f`NYaWbXq^4}u; zIsavt6B)5w(ZkRwVpt@=I<5wY*b5XU77+pTJ37+0sx&;{y&oay-;p}L!R^W!_OxMD z<_-!iU_JN2taZ*v;n|La7y8L-<@~H-Fx<;_x2WU@cl>I2I>AxW3i55K$(BzY8!X3$ z&U>Wo4xOWC3BCuoOkB&BN(kf%m|D=`3)Q%mr%0GySzQxk4nN3A&G7mgT4&mOchsx%=?yQl3bC6jmaJl1yPPiZ*BA8dD-akmkY1zd`* zt?A|XIaGagL7@SDEKbYbL@^;woS{7f=W?bF+uVR}JDIIbM z@>_s7&$t#~V^;+->fQ;S3P-TWKfx`-tJS$kPY{8)w@HvjRN-zXCt_5BA<3U|_5X-o ziC6leBGki|(G(cD(QeJxg4=*FB#A8W^Qm{U;7;7IQL;Rm2rcT7CspGvRU z76xH`^5BHz+vnkLY>>TcGcq<3wwHq?EMYCb^{kmjb^KXv)L%?p^g9cRIZtNy8Lbzl|FT_9J4uJ(-q>O9@fuj2LiTK#^NGFpc&Ry(a z4vlYo(OZz!l%?(QK$0IfB9?+gnO>Yku3vtRC_({y00SNuekHw%d-$M`B7%oZLLz9% z3YGwVj$Ei!-jAEvq317=FiF`p0-4Zs|BD4eVgSzHb zHoRzU0-!{t{PFHvX0E_b=av2!oq1Uyy!c^~pfT!=3DXm`Dk|IOfwnK@3Y=_N>tRL*N);uJZq z0NA3r-ss8Y%_~Mj@JWcNmO=0^`z@GQkUm_v-osf`&HGZXCibKzl04sdt(Aca?kCdI z`ahD~kzm~|2**ceHVqK5;;S9krhs1?d_RJGy8;j?E|K*fSPa$RbUXd-A|7<+MiL!q zUF^EOMIf=Ba(nGJk~{;m+92;9C?RQ*>o8GjQFqCQv6sJPp+)|_Dx{5vyQ>WMmev)> zHvVz3u^-|y`);4Z5fy&eh z?a}Ien7QR;twPy*p)tN8Na#Dl8=LuvS7xE&G_s;ZiZ=tTm~}eGB$Q>6Yo875vWUiS?nnTwe=lc=M@tP>`&b$Qn`k|AC34*Ud7c-;11vCy-% zer$gq)#s_;(oh*~m9jiMD4l)Wi;$*#umHJAE zMdi;{{&8PasM6i>KAu57v zH-lq9pSkq@>`SyP+X|<9VnS(+3@uM0hy19iK;9SI?#%ct&)>=F+0P1QD{>28tkCqi zDLN>ZtvZQV)YK7@1P`m zDNJ!$SCT!i^pJ@`rse4(E&bxmv5CbLI7_u^~>&2li_EN%5?EG ztKWU5Z&x>X&?QFIC5HhEuR{@SudV7wb`wfXmK=H+PD=ywMWwaYRR3(>d;5u|N91MZvd8oko zaYj58&l!)^x-1lFdt*`CvK4jWgNh1?*4~h_qz3MdfLmj-zfuPnbtiEHSK#BDqOnsw zX!Vp-Tfu6s{kn2yLoJV&dygR4pJ^c766D;gh^A;{q2X(!O~Qu3Y+j~aHJ`h_zzrLt zkV;)oXXQWMl?P$l^Jdb&!mahJe6$&GZk?brGeyP_2c+BViM<00FbV|233a0x5ZfPy zd%p=(WowhanBQcT8utJS9EY=nGJ(+8$0hldE#ykrblod^#t>OsYW}xAhS6?Lpuk?(A1fG*fTdR9Ax2Yxx9Qp5u5!2|SM3dawRq?Ogz5 z1))EtkTtA2(D6o3FNcW;lC}>!+0DMYnV~g)#@ah?T0p;F+fsgAzD@=6r~IN7eJgkH zQXqVrWwgwN(do|R-FZYF^?X@>^cqXtrj)i5A3BZFj7w+dUId3S-eD628aimQ%&jJy(97TEF=Uc=`eWzuT>>yAxA@F( zFvg=Zlt;PdR^JAIB+M`)o-dkG&{tbs>&Ax#a znVls`z{u`M)mIJ1GO8e2JM7gWH=ytA#gwYDTGwn$v}t90-^Rv+j;IoaLGK;FF4(pthTq#hCba&bM`>?wj4cHPX zRJS_Dh1$_RGM=V@WBg;arG7q0!d>(mpI9T%RF8UXbx*jantdcyESKlNkk_khmD}JG zI@D_i4%3eAQ8y+d@%o?=>rdn#Z`>iCR%3j>JBzcSf3(V^p6sh3>kqZkqi1XfEdVs=aKNlI^Zr8=kAoT1 zDJ;Iz9i#`Xuo(qdM)Rc?<{(kz>+>YjuL{hKxLz*}Ex6*hN&61Wa^J#w*?#6=LUnZ= z#DKb8Wmjvrj7W6-kthb#L~2}dpC9$3o?FFNoSZSs<7{1`KpLR6YZ20!?so3LLk*kV zWsic&Lq$@-(RHhvn+0Nug-KNRTeEoIQBnb!9rs%D$HRNP=mY7Z^5|7zMKm?9f42xsEhE+m2nq&jA0XCoe<-C>?7W+*U2vtswzm(3#RC6&VJLQaT`)}TPM?=5`uQ4-cVX}9B(lc0j`M-Y~*RtC6aZ%8;R?2pyxC3r-*HW zDYb>Fl$?ZrRu#EHf=ty#!4FFmxIEG|govmyMOaLRiz^dbI5r0WiTkyQX)Ik=b7jL&=ipIFBhL^LTWuP#Vngk9^I3V}ylXUMGhMwf9#Nl)!MAB9SwN7t0|)eFfoai#4V5mifPyuCx5trwaB1Z;y?*(~s!psgV%XpA#UgQyzl2rR{k5(VJ%slT z29FWD!pyF@7tg3&linxQtWCR&9H@&|I>ziNa+$N6U?3aibBIfC+<4t(%{1T^`S&N_ z3K=31Sw#2_=x~{6ebmpXb^+!8Un*FC;O8@*#bY8waJHrQJ|aXPO2{ zSWqix{;Xs@z&kwj!6vOnX62vs-L{AtwAQ`*oZ3up!5@^3Kz8$pUS6-O7mAZ<6T2rX zEw--mJw4-0mXPJcH*&?51Gj*tIPS2pkNFr!JVT)1nK0ZLV(K!{}c(y;{(ky^E#U9{Q0V@L$gT~@h4}0&AvxE+>->vgG>R2nhJ4! zq~mlPB9-^kV2I2Cu00fq443U{qf3xr3dpTp-uRSL-GsAmHJ>=26Z-R{6o}m4iKRo= zox&GDxIRqEi(8Vc7NF7lA2H{_e#nb;y`!EExV(cF8?=N&n%WXEjuueHB_y zy&D~&f;)ggn%JSC)fcIE{9?+ytjq4NBb;!OBCtk`$~Ixgub;91F&^{-{|N-Prgmk_ z-ZrA`{y#<00=aO}g@Wx?=Anr=D3xBmiIJ--=NAyz0C)IZ5DVR&I{rOx>ntA?_FjBX zU!gFR&k52qXmR^rXdHK=Z)48K0Xliek%5`pX8(1N2mS4JhCSBqfZruxXP!tV7&}B+KI?8 zjQ0ZmI?M==BMAjQXtHM=kEu(Z^Ka~?_@hl-Nxeg7O%TzUQ7WL|<_yBGEk@}=9%r+6 zd5Cji@V704&~4o%2_3kth#~)sH)mkzTzpSF79hPIne?{Wk44gsYJH+moHL~!*=gO* z`5&UKVO6C(P`}H`Rkjv3IlsWL4^Id6%}cZ)Bxb@T*Th`yxn+2?yQfl@dVrP+jS@*l z;8KloZjf$hKM8r}LRU-UP?9a0GWCDiB|LL&3TxKms&Xrd4%G!z&b@N2&88=GIeawF zxX@iu|1vu9JAmyD^9@xzn$Z+VP;<0soE*n83lQoGJHvi$8M>4GrXFmYa5pp0X6?f6 z_L}h*Hyj_tU83NmP7Yh)P=a+R@58Z86C{1>q?~IHp+8z?y zGdq;YvXFgS*BHyb^R7y==E?bdY&R6_MUjKY@l4mrGEnk;dp;f9DtmOXYCjR2K34e? zNj+1Z6()eCXYkBxjJZi@B~XJz6RJTu7~)%5B{2}Cel;zPI!@wNYIz5yVEjVI8l)q> z!1f>7M!O7h>{elgzjlvZTxshU7xefE15ZzjULxmkzGVWIh*UFFElHP6a zgZ?ZFb$RoMn%=(xlWhhulJ6}ly9B|AH`9vHd?kAI(`5@X@&>O1;}!XeFcCKHT|OH| ztXGNO`SiPx`pGAp_~ML9fO!$+Jn>Ozyc?$8~VshztNj==9~8q_cY zv8T97YF3PU{X;^NWlt=L zQEQnRH_o?F{3FyXYW)-XFi1**c8!5<-&2tQc^4+3ss^A*M(@3wH0T^vl6TtcO!<9B zRcRR(DGmHNnWSWPJZBisX*vriCw|23gSE{!bWQ(-_OwkyHE))Rw6Wx`Z0CH#8ToqK z=TOokhTf*8gz;cVTdRe-{_u*LOSXXYZMe0B*iH$Kku}gzDUK^49B-!Sh|uL#b4x&X zlCjQR)#>bwIB@Rji#Hk@QlV>D+P6aP$4ZcB8gwRK$fvn!n@ zX!mn`Ro}mk`cnqYNeyK?l8%8QIS;=Iz5od!U(F!|U19n=y80r!-1ko%-#>&u-xb}9 zw{a;FZBAEB!~Kr;epM$4HB(wPqIWj>70z1xJz0t}|3$IDzk5AZdc(Z{`hPBV5BYQ9 zE+h(a40WUk1i4wrBpQ(ZP~1S#sZ1pO1tQw5fb0SbWc5$L0%-XQbGDuGdcu}3Rm7IT zbt;$bfu~>+oF0HN2(X%`qfhH0RsE>`Uj(wU2NMSzkwqX9`;-r3<^ER~#^G9YPim_iLGyLtzP zFp4>zkc7PuLrV-J_!pF6E8A2oqTO4erpdKn1HyQ1j}j{5Eot!N$_1F081t)<0AlUG zsI$2c&tQ%|)KFcE=f+PtdCS!G`On-?!?_$uyZ$dh!JL5E(uv}kif5%hL6wgmvBTmc zX&f$Zj2A2l6t4X>Wpo9B7yJ%^=5zfXBTEw)XveA8GA~_u2opaTM^QSQU=-@&H-GV< z&y=l#(Q|k|D#se@aOT*&dhHUv0#xv3H7X=F*%!F9g%is(c_0~tDN&W@fFrTZjn)g%ve`aY)2&HzuNBu}ZPFvZoQ*_kW@j zrOyVJ$f~D4QZGZyzO98-35g|BtsxwaxN~WtpY=1&#liqNK*qnX1gx4wG}q}?^3HI9sz->^6osru zalz%ia5#;0uoCqo7qXIYO{aN87GIZgfMxtw;MiakDM@CC)3@g7=_r=eJ9|wMD#C98 z`v9#xJAs(aT=d10!vPTbyEsY@$?Oq_x;xorsRz~mVy_xuNVfN*>qMw%vW5SzeY6^r zeyndl;QD+((#%AX$x#O$Gnvd=UkKun&0TJa$s55dm}f$!PF^&TxN7QM7idDfo|z6< z6V6*ia@`nWB0SZ;^f=}<1kb|$rb>kv@6XI=VO*k7Q_zR&E@tx1`I_fd|mss+V7(*z3mdv6 z$f1p&gXca-B^^^Q?4}JyiF3wMl#}AjhL^|leT>82TIE1S-|S8|biry6^N|CzenDQg zgh8%NrL-(+et{^({m{JWvhDWmfXpcm0d1}vtXn4=p&GdX-#B)`)K#H3+3}c~T-|S0 zb)fqEWj^`8ey%1;x00PWCQ(C<_D0GF6*jI=bn$qVQtr9ah6i)=eHZL!!cP25qAbBi z;1T68Tj=!P4GInLCW!llRbEWOb|fWP_DzMxYL>Ek273fdk7vVobfePj(<87ST1RwT6$gpoDfB~?55M`Fw;;j>=;hO^zE?QSn$)UKye8BQMC~+< zE9h%97KU!S;ZrE~7fqA1O4yT~h@E_xSt(oy>7_|pJf3_Fn<7|6RU&>VHpIR*`)e??&Ce#m z0a?^Q+J}^UhV$N#(pye9`;X%L>>RDlsgDA^JK#E&nnghu zeHk;DtPo|nK4mpL;U=8-%P1oPTMKx+t02=D#&1_X=|!ayB_KX|`zl1IUQ`s{(lh8% z+7KkY^`mV#2eJ`8p6Av;(LwsIL%O;hQl_|%f-w~cDzdoV!RLmxAzxNIL9{zoVM#K% zbi%fAI{MM zl~L;!at7QXCm}WiO-uzS!nUCEo%F3oULTMew&Z$B=iii**trhGQI~(QlN_~#n)9@t z6qz4lUL1Kee`Ytmf?Bv+X29Hc*q_4LGGi=G6A5IsLO9uEmx-Ihn7la`x!O8Hu2`zv zUwKk!Dy6I`XQ(y85fCu!FS+}KT;2qG?dvG>3MRr*)!OM@CmZ`#Q-tAqL%DVEP5G%3 zDLK^#KYRAdz_3Lq1-!yAG`qm-v66NokVS)*$B&qp`hBQY@$meQolSISRb1nS&>J6`-cM+k)lO`Pso{!t) z|73WXi-O$M05~RIfK^dctdc&?tt=MuZ#>Hso0?rH->-oK>XIm(p1!l+YZI$>noL-$ zpIsi_Ebs+EjkITf>aGC~y8*e!tm<2H*qD^cO2jfwdQ>Han)I-P*5FkqP3k70^FG68 zO$=EgPVKyIYP)}@8aA;@I&tldy@=yd@ghmK1Jf$y4C`hx!4zwZT%9(T& zbd3BUkiftSGyOSSKEh5nQyKy9bESby@sAYj|sj0+zK3ngI!YV~@D=f+2Ehn*jIV(0^5K1xY-vIW)d}My1 z)!nZjMu98XWUaLYWZ)7n@7#lZVF)ly9w0gzPZ|c!mUKOsvfFKsvR4`Tbc+V-p2uN4 z#S3$IA;-S)Z4Qhq;jyC5oVVsc&8$4UBoPJ9!E{WbN41lUCcx@kecgq$FZiK$PIN3} z9;%?_g1^&hNkLxREl1&B=72|1b>4_I&f{?!UQxx}GW>rVN-SpSE_&vZ&!%E3^qC0^ z6w84e7Qv!7m;h7DNZv^{~Cg9vqHTN>7f# zMQ#zOkW38#?G*TlAk&gwX)*ShRQbbBNLoi<34x$+GXE`$QrFQ}Iz~S`m)F@o(AEE| zU1v~miI?I}gBPt6e^jQBM;DiFj8O$Tv;odhm3|1qsy1;V8#UX#HnVm;nu;GwYq6c0 z&IkjsED0xhlYD2DsgaYg^7|Y(GBzcug_PM-@uqrep{E+QL24`J;kU(6nh24M5pbxN zYY0-PlQu|-bWj|3o3BoeRLhemW=eOy>0fW8&oQn)zYvJKleFXjQje!TL4ZCl`P5w9xM3QEE2X`AK6HA(`Bw zDy529p+;OVQnFecTt!)?{(^;#LK1z!+LBKFu`=4CBJY?2y2;q%qA!q%d@L<1_o{H8Mavfoci#Ynn62&aE45K5iY%>pd~6X?qt-(1@Kw=1)`BWha@CEpfCWIGwM zV9VBbp?CCIk!5k*6fPcgMObqd$c7Xk{L`D)8$vtrn?^R)V`8Qa;I8j{&0^UvSkB0i z(K1DWKyJs=TMFF<^rk7SodTR(l35b4!xw}xQKMVl*~!1@H&FO;whcS}9uoP~sDe8- zy`gBmq*3d3`7?y!V#mvIOu?9;-JSf$0sb*;KwetQigiyAV+_ae8iT$_@}U0GP&C4s zi1({0wQ)xS5P(wnUWchLPmaclcJC>~(Xo%dw1Q0Js7Oy2^^1W&<@_5|tnR51&Q4mo zWz-%1Tw%8D5QImSih|CeH~Mt@Y+*3FV<`wC0^)gOQhU zY7EJsMEiP`34Oj}4r74r=+htlSB31I&}d~wRXD2(7JT4uVGND_HwIg#Q>dB8M|WswQvZ;!e*wOKc)4az&Ce=}<3tflHk3Im zOHa-yv$#vgMP==`32(-RA^(@s6-F5phM$h!P_TO+=*W#U>?i;=vyWDbP%OsUQ{8T{ z#O``*r51bH5*sjr*vQofEt&1gLnzkTkINQhRi^~%;x__5nf;b*SJ2otK?PbEb5GZqxhS z6#LIW8cA*{8#JAt^?hGsa#6vhoTdvL5UQ8@4#D|7+i1iuu{`1@i8cslqB1`c8Ac0w zlf4tmSiD&$XoD!GE^C-tn%N}*J^f_wcs#mLde#nq(sf>iiuVAEi;#`jjER#ZrsG~0RtN@_JkD9@na{SS5XC``((U0y`6-ir!4GVgi$%rDjd+qpR zS(wcnehbE-XMA8z@sgv2Ib+uZxKe1ioj$j-QO>F1 zkq<5yhM)7`n?K0p=Uv7_Q?*4~18@aVn)U8qBT3r%XmrI>apVE>fdOTXMvRTb znt}KgnmQ>$ujt{?c4^20QAA-%;zmzS9WY@JvA{^*V)O7}WkZ9X7s(LyaZ+h&@EVk*qM?{zQgB zgyg`R+d1A(+{$KY|0$LZq)Q2YG>`KhGBl?YH|i>~ZW|&>(18#>oNlI9(qkCEJ{7ZQ z?*h~>naM}E21F_(Iv{?1wSc!5enVJ;;my(*`$iK>j?a7mMf|e-i~~>Nh046yvlo9Ak*^(sS(4EGLj-DX6p7k zWW(rI(%Rf5ACN#0LWnXMTkL(p3Q-~z%@((0Z-NazS1HZb9!zLSx$LVi&5Z3U#W ziB8T4`~8=HRq-FJg?Y10JCh#<$Nqp1 z%mbav@tQJRm?^=Wg!$HTs4S<8pa{)x_rYtKp_wJ1azHt#w_?jw;w7{y2X2xilfyU6 z%BfEpa<;s2C$xtVogx!0eP%ME*gxrV~yNn5#LtuK(`57_cE46ntP9uh{`F6kMZaJkTul483m!STl33l0eW!6O`{wKYh({g zfWM^b+9M4&>#wTUKYs~+@15ja+%>VtqbI1R;#)L5vtpp`@C1LM^CPU`$u7(O(e3kO ziwsHtmLwq^?R%+{B*{E@fM93LBCm6BOoxFX(`3yxDBBK>GvVvL2*`rdIpBPSPGdMf z13q{!-fz-bgQV089=3%nx5NMH@OTmOvI-ug9h~|#q@ZijU>A84ty{7GOWvKCmdqcl zOnYdT#j2SCTzi_ZlH@>0-#+>dF^ZL>Fubo2tO)b4{O5bD7NIU+m0}DztSY18t^w!8 zj<58hikxjXd+74*I00q<2eE+om_(es=&N5zD|SDJ@;;)S`oG6>Q%c z3e0ITz?<|T-|R1dfC#Pu#eOmYqLL0O1Fr1fU}6x6OKB51)<_eK8Q9qxLU%lQZ3YzZ zcIGn~pl9fPAe}}TuxvporRbp!t0;6oe4nNMjx0OIp%k8>amJ0Qe*;eT0QV8XYAz3# zhYA7(hrFxgi_-ni1c0ST7-3?M^3&REE%~=~cx(TAO^lM%JNNg!JuYY1Yk_U0W4iNu z9Wj%-sdw)tzOI^F#VEMJTd68i_&Q5L(Pw9$31Vb1pE~1M1O;#1L)e$`Ov5ERO){O= zRZh3Bb68?qi*BxTE#*buK{sDAa$U5|kC0N-aK)&xtW~pz1zwZZOjGNnJw;_1i8@?; z?av@iSq@IM&v~wqGm-qS?xYnVM>A9nK>uFeF)CRowAI*PTG)){Hp6NMeelwQ1?giO|$v_Skt;ah6HP zfMH!@G=>QdcfUPJO%faEyE!bUDbtIx!ycFG1x)7icAj_FppK2F6g`=b*L64i4*nq_ zV|6QcFM^AR>_;CHS~*l{@am_L)r@iKEUriBxx-do^h4A8i^vq%M`0=#*=x%ckZkY$GH{ET_Zs6i0W5Kw zZRmg@Wa&bEv3_rauU*z__K}@Ohe`TFmGM?YdnhS=S!qc;%!VkMy(2#;(pIs*%xl8URCeisx5@CO^hAqM~Mq zS29^%AEt)t4@#S>TUJ3ner-7LzajfjEnPqqzpHImf52`52T&z4{hY%S^9U>K;UEDs zrwoL7oFibobZO56x51j`!xzpY!OlZ;DBJHgC}oG45Es#3rO@VCLIesxKYK9(ai`@D zOh&nL?>+83Fz|gujW`usRdtbhem1l>PCRC$A2gt?B_gKpiT*j|DGv7L$=zY=sosy# z$FM(NJe^1VSUPa6HJL!^E{9wt+D z`e1wKruLwI#fP-x~AF#>n`S$(5`QLr5)n7A#y#GB3L1MRE)C$@ZSDinNd zGtO+G8V!X^(qY29Jd7Ld0E8&*G{tXHs#u3zXir1*v(2ipAl<1J7IvM9M;~2duVetn zOJe!nDgImeHF}b5N)M&o0p-I6$%Qoed7#X#(!#&b{GatHSmFs_H<*cc7+wziNQv6n zDm;RyPz}Uls45oJ^`IRvjl5vz?ociqhi}$v1VO8Vn0j&%&Jv^VZ7a zH``;ikIP^eIG_d?6okafQdh3NdpZ@EwQ8&O2M!TE4+-6`y!MhY!#twCvd{o{V=Cyf-1 z?LO6&URj!55wi;uv48_%%ay5kn96XIijH(^ib$1Poh$T}{vApQq!D#Sy_Mc}j*~$8 zc@ksjLKp0OyMAvwa_QUET=kRdtRk{Mz?iqzQVa@_m6OkiZpT331;rKl z>b5;ea(3)n+)Ir2K?qvPf&9WWSmmzXRl)+W)wE?r@nZ3RRU5;7Q(Pz`wYuCjv~j8a zI*AlS*Ap9Y4FN+i%A|Kk3?3CL1Q>=nRpV)Z$WxWAH6sNWkkp8HmcjitjAK(}EWh|L zDt6|v$&&*4<5;B>P%joiM|uGMO9EYK{lAv~cS0Qk%LjsmeJNcHD&!BKCkpZ^8v(hx zK))6FGwV!f5@avCHMqIXMl)(#&?UKo zBAo*KYqa9G@LD*p#uGY9W?1B+ALcg#w!hl+Y@5cKHv$Oz1f?R&;pniRVEBfINE=_!iN8ep-UxaJGE-L2Vbo%fF@E( zg_HB+Kis8pfTN(`Yr3zZp1K|hidDKU65UR}6ciKRds@M>TPcJM zxk{DsmoWW@K6LJsiMLBinjdAAA^mw=wBeGzBt>wbqkhDveKmgjDw1seUf3H)4q1G2 zy)dFUB&lnYi`tU5?Bb+;76%khU+95F2E+x z86LU*&xAKRPMj3#kVK|-nS2lAE{~26r$=&qx)h4k$SJIlIaGm*Csfg4tN&v}HxvZN zwxZ1IYTHMW;dF^x`u3>f=fQ5}auKWKkw<*SFPg+}R#)9F#Ao{8d4N6K_7>PlbRa_X zmI9O9TCykALu$v5(D}Vf-*9z<(J&F(>mP;``35?3NFJ?zpQ7m_(Hr}RAQZ62Rx-^H ziGutS@1SwyS}prCLG(&{WM;UqK_UVoVFcyB20Mw!kUZqZI(fu%mwT?rMc}mad)&pEpM?UkOFxxZ6A^gSj@n1ywTHp~tVXoda8}Ht zK*AkZRJlhf+ck1Gx;QV^v!@C;lED*tYtB-Of@N(bKieTU&M}}?r5+wyYG+By{cT>l z5DjErr*7k7k3zQ>&ibb4mDob#y$77c+)GL)zw^l3tG^_uW1GK;i2H*@C8Hr-m3eAqCQhXQI8z&j0AVZ7Xm83O|Vx|lZ`JSd?cbJ(5!PBO(TFL z3DtnbGkY0pX&m~OMgtGTE_Ax0~DADO`;I3mP=n42wDZ=_l;#9#%pC0J#&xRrk zW)$jo1t-jVD(c2|AVr@rjimBIV~+rSC5GLUwro*D%jF5shL*n#|p6&I}>By zb?w&K=v!E%Kh*C&+-9Kzc`aYBA^|?VMRpXT(gR~v5H24sdW6&IgrtEr3eFXd@O~(oS@g^)8EFSUnuVpJ5xeD zFE;wb50M}GJ)H*GXV5bJJNV^x-rOWReBwXX%k#$uq7f`l%IZk7r``%J(CcPWN^PFJ z{c|E4fJ6uKKjNTFfV*E{k<7W*&LoeV&270WTUkRzhW%bPii3!(Js!2FeS+P^?5Sbe zBg=Z`VqU}ocQOu_HoD%l28T|g$tL!kvwbzfi`Y_0<|rMwVVDDPBo&;_;zH5d5k%M= zLH4Bv%HX~-9Z?&`%B9U&*`2^^Mhdzp$?8q||3;WY{Sq17_f0??G$Vw`-t~#I!>N&I z!T~1~Q^!|{i2yNBpxpPghlCzvXRSUL>>}f2`22*`R$;_vS zS#nGgAW1#t%RLGFK_M5T25Ex9|9_ND{ejeZ2vWjVgTAHdjKXu?9O_Y*S(?VlD`Ucc zd5ip0E87j3D=ZK*bklO^SP}#uY&`|g2GP8t3(o8o_3abA6PCp#64dM$QzLOiv`6&{ zH(|Qm?(C(D1a^1Tf4l6`J&v7-rw^P^+%!?|te5!3rF`++q5t&{6%6b}sO(kO=-_dH zGrbTPGP4)G_z-IZJKbAFnegIjPGLsD@n>E70}D01Te-hyJs|Lx8g{NvzJ+zv6tk^4 zY&_J2#3)4D=o5FXT)A%7DkBs-oiLA_&>4FWqj(kVL0IiMi0e5ifZwmKL59EkD8nRG#g5L=76(!in&S)P>$aUNVEMe0mbmHRm# zr4W*&qCV7w|KK*!vZN$KfdfKqx>Ty)&{l>!$=E*pr1vs^b_m*7#-&YKHz5?)`>1kA zO5XQg23P)=^2Qg(kTH@SiLg*L24O18puIVJi0PpS2V50I=~LWwNt0_Q1OZlPtSUQ8 zJTSo^t=91#FNjY0F(9@nEj!D~c9efl=;*KU5elXrYiR77MYJjlVUTy-J=CBjo#`)# zC~aPxNRfSu8Ujnmsgm)E)5VO9ABlV0A<0&=W*qroBKFGmQYnLq96_YEMLBId6 zWR=$<_D2whz%p_D%+7H#OSs9{cB$Z2uh<3njTPkSK@_qhVgx2q>MVKGWqZQ^6imj9 zB7EeulF`Z!q7l68Z8Z>G%60-4j?ls{Dw5B5S4$G0-Zf+8-0>t9p|*=rZ>CS#r|+4t z(J~=+9oxSi5_pH0E^aS02K=SmO0*w)YE1$4c2$a6TZG;vdJ>tY{O5#o`)alORb1eO zPHS_ZMBwzMA~gT1>#RlM61OTP7w;+SiU3Ks6s)yd!yI5Z_C8u>y8)^g-~!I}{*21R7q= zyKA-a+^i5C9WDejAVHu3X;!+UFvff-I&Kt}EKSyxQ52lXynpKt1(yGc|H{KKBz-1&YtQ9vRf0M5g^QrR|AN&|c zG@|a7?Nay$(N)SR1xwX-W5zE=sE+PqV_k+1GNO<%^O*Lf7p!Dj@gzu zenAfzi66{wA&4S;EKTK^+ATBcuDpJ2-7X_|10-A0f{4?*0mS@QpH5l$u^4pSdV-zb z?J`$0=6Nm+F6yQYA3O@Qiq-s2yb{Rg^N@87wkCzc5|Yg5sFJLPqY(lbcyMj$ow3-8 z0V+DnSU5k`1@O>nK|;D>B#V}`a<#>sOz17h$V#*!mBz%5IL$rtE`|H9s3yYkKRUXU zewsC$Adz<)Dh!FAcyOT^a37k3(V4OmtnQO+2|=YFjy%@fuNe7B`u*haIBhZ3%^`pO zCCP>;UNy(L|7?MF9$GE4bGP*!6DDPKmGJGvt(l9= z9Ir^J6;khd@xs>9PgTs_#jfw5_DssF1!&4g)J%42{r)cYr~qeRI(OLuWWnuv^%3A& zDe3jllMmq|Gfpk?8&-fx+V?C5Jaac3pMT>I-sJMaB~$kwb}(O6@fuQw%%_=ZItqi0 z_D1SG<1I`e4<)yJYp8vROK!jSSpqtR%PyQL-gElFe!$M!(NUu2N9~ ziQ~bo!&%ku1QCaO)8c2w?xJa>#Tm#ewk8qhiAr8Tn}Jon{i&&Ad-s@+*Ml#QUC`OM zMdOq#S%dqANr=)~oFjf`1$VUwTMkJ#Wbpc%RA22A4SzN#O6wPoj(0&pbYLQ7Zyp%G zGxj;y|90v~ge=vo^lTKr-c^R7N}wg5ochZL?f-|SCyq{nI(=mvLo)n-MdvT$R>>c{ zf1vxIp;d;`GIo!i9GI3hqdLWt3n=w49D#IJ#&EHycLLdvpKMS@gau~JA6bn?+-_zN zd>7qZl}QXMaXQm5SBETvg}sFL%6MiI{tuf<#%Z=Ii013#!hh5{1M<2bGNS*=AM#VBK0DHR+6S|5u+sQkD5>oH|MLif@n+fmFQ|g_ zQvoI8$1R()5pyCVOz3cEcwTA@+HRuGK^hRvRnxP7S0F#is3be6l9 zPeq&7>bvWn52=S^ZCz7B#!Xeg_N$9-rer!eW0ox z@)X&gbe>ClrUlhaR1h+}IGkmFu@|~#@peK-5N&?3e0@6*-(rapNUchKO)ZK6_1>8W zi&H{4qa^%(ccboa=<9OA21Q-f@DvQNAY31>KG5k1KOWAWn7$)%=-4F8K+}kwrbRpR zdz6S*L+1&}1`^h5hEV61*w(lGT=e8*?%x<2%o|Bz`18tN)e21}fRS|&3Aiw@cu9Gy zvcfMV+rS75#9W0sbHDxP8C_k6<}s)J1nc&-VXZ4L?iVtTq44edJ%hq(R?Gp8h&rXl zeEoc)_C%#BHksRO3t@#{2avd)X9`pdR#P@{8SQgQT{27BWkWYAuX*8bb+wo7lDGX} zY+an3RM4~pLxQ5C#ng)y6l5@#>-DLK;@8{{s%l7XEt%QmYy}pHa1`xvBt^wBB-R?g ztnd84d7Aplsi{`>XXJSl4k*q`&#*GE!3-3?yX-K;BmNHvRNiXt#z{|*cd5(RpMxg6 zi|eP+=t%v^H?Xjh7mk8nGzu8=Llpv|jo^xF--kA);)KR&=`Bmf@d%n{0gVvkl+3nP zw$?IJTflItkiLHGr_nmjg)CJh;`cxgzhtj(0CcQy*HeB)7At=Tkz&Sf* z)^Bg@A%Zpn3T-Xh=f5@i;}qs^U$N0{$LNzt%-Qhl7W|T?V=>M_T{mvp$TnN=pnYCh z8+!pTsS@9|o191KVI3G>p<-(_5KnJOzvuL+vwg1l679&PflpAZns}UQ_xPHo9gT&i z1m}<6Ad5<`i%5nRTRcV*(_qZLIw7mP4h*h_%PlTe60O_GG`c@R!eSmDfMA&5D^0LM z?~@byvO3T>LivtWxPQ|xYV$RihPgcl(jO)@OD8@MxM!0lUl3X(?}&X_>IYNgiKRV; zKqjQ;4Lkm>Q6-SA0pNhIpfAmW?PyOsEN_HnjJTw^ToZXvIh)EQ6%<~LYT#MX7QokK zst8pgd@%@)6po!F1giDpbO^?4-T%>^E#`n^L>6Cf3bHSb2{HBQ*_p>iY4zV*Ic;$b zHFQJ6YB8tAgB^>ud6fu17_rW~yAzh64tUbj^cj|h<+2^;6imYN*GRS% z%XTxL@=~cgtB%DUzuj|oii@67ZiT8_aI_G z4{iA)bCl_nb6EXYFK7LY!0{w5;HA%+_ByE0g3rZh@Feqtn`YRGS7ZNd8c_!b9yX=i zlMW7vhdS_KypFgv;pAkZ)_@#>y6=~K4f5aov>A7D=E%%yb9A~b3=$;@H-_kj`~e-n z{0E3X6aT7(7^A=sax#aRBQ_4ePbfCb#)QnO@e9SkyJz4a`xYH`}Co_Q4A zF|Db;NGd$mpiqm;>hV51!PbYV&Vu`=9~{2*+6PN|t5v(_Ds(hfe`&BuYDKfc0cA+% zpeV_Pzqe`iz06_5w?x{Kik6@#Jve0E&f@=hf%IeqOgvTIz{cNUKApT`Qmwsy04d46 z8HL5b*Z;2?1yUUJ9fC$B0Ta!s-1(ba1Ex-gwRC98Ruq}t7eAxc$@Nk4m0-(PZjfs3 zMj?9;hgRg0^~DYd|5|%kXIBqcL}&V5cH^ z==)b!V^_faMU~^Awpj8;o!!kYMx=y1JIva?E@-eXH|2Nz1@k+m|oh$w& z_VrkBEWryfioQRBc7P%AD#E~2fK=Gov`Pn7srT2xZa7A(OKC4E0d8c2$$gSh4Ab5T zfmY&pt-R10X28qp@zgKLthMIGh`cFk9~$FVkjMjpAIT{G@u`I)BU;&(RkFIlhm@xo zw+>a$ndR5(fPmsZ7YQ2nbtmnSrP5hWSp06-mx)m-T_mEvEAp=z^N_13>a#Uq;$@Mv z$r^Hb*vu~8_r;l$unIz`TVXk6t3&Hfq6Q%ots``h3x9Dhrk{KYN28I$-KsPN_rsVb zcD;PNQY@fUY3Ch*e1ETyvdtzzYu*H*&4Wsr$!;_x#Jv^&_nu>Znm3soQH|S}0H#=< z#;4>-L#q>3wEGLza%++pQEtx|x@0!U+KT%>L>%PvDEWmaH=A>PhtCXZlT5Q$m%_-- zP}v_7mimM{IP#bKW}6DAG4FIc`7|tr24J)oX6~)%=lph=#eZO*WGLqT0L$Z9i$i%A zUmpmya{W3I^j>{t47r~1&-PX_!`@*N8-{|D5bv9>%QT?p%*L*tBK+k14}-r?Hetc> zRNEM~g%cM+%q^LA&e(eT-p0j0x67}9MCb3R04JL%b>Ya7#J&i@oUuU@3sC8-@Kct*bIzKy5 zt`;TwM)}7VY$D6X|45!w!Sd%Nne9zEFOPZ}EnY&zmSndQ?bXzpn8`;lw6Rlb%sz{} z^CC`Nmf%|GtnohM5y_Z?3j2Pe&w+aI939u5 zZDSh$sFEA;AEtNF^uy<8cn;*_C`1Ma3fPVxOWpeI+o?Jf%l>G(L z{$h^jnx$UrN#eE_mouQD`LdKmt}(n4$hxlTI%&PBeggQngU6C0ch3ABPV9>Ec1QMw z!8H0z)Jw${G42;0q)IbIJM_z1{0Bpkr5{aDT zaU^J?p)QbHq1Tawg)2~3sX(?~umSpe8G}2d1u?v{5|U_A+LpDJr^fe%44~b=as&qT zL^ZKAVK6#A-z{t5I<+1jKhI1KNC^*%O+irPJJK3zA&m6W=on(pvJsj*%p`kFTp*-n z;7axKdZPxw)Wg*98_~OgK-lN9duK_;WIFsS$kx_TiN3<@=^v1$k%9}A zUi(9h&>lS&BF5yJWA|@RkxpzRGw6BKxI#TERzWaUe z$uyC`iSE1znPznw=Qy%5jxS zYKMEuy1$39{>`5ss*nHs5>aj{_S?2#<=To;frO#O#mx}=yfn-fg=jB84C!=cnrT@n zjgORinJnz_bN@g^p9$-bw~jlYADy(N=>kXoS}ss2a}gL6_s?j14rc3rQHLb7MpK8RrX^y#Sm4CfmDSVa!3~|2AWtVSSl*@#Dn~)lXxd zfa;W4#)t~BJZL8h>N9>Cn)=)+UobrA38UE-(o$$F(5AI5d)Kuu*peooaXj86kCdRO zU^^9`_6J@f>Ft>EmD6xF=^~u$DE_OkZ@WcYD($j8`w}4Eelj_O9NEeKk#sjCUZYR3 z69p3w?73q3I(+;qI-4^^%XgUx{p&6$8_)uE;4)13%!;W&U_a*PEnLOfyA;89W6k^o z`rx}V2iia|{W#vlGBx73aybd-(qFHl=5+u_{6!RMagwTiwDqO^XXTv98}+2miZjbL z(tOy`MuI&L!9~!ARqWf4<}N(f-Q%y9Nze93KVWGy!_S$3YkOnd@*zRtV5*uQDmx8# zVMxhExf%l#s|==F91kF{fB^!2Jj{oR9j}EuozE)4KEDzuKcYt0*Ct6bUNVQ#21;VP z^ED{$G~R^kih%~v5QSKTwN@9*8K~*n^3bL*vAJ9v#wvZ%tIW%$VqPXcKBpypiC3y7 z$nwZLB`hmkSA-T&<6Et=)>Q=0%R{8)c${nM(iLxgZJS|nSU<@-Ew6;zKX;=PZrFtI z+}u4u)0shNly=iHD{u;8SNC|2V?1iQp_x6{iaUmsbCb2MWJv>5 zZi1n*#2_1a;@UMAZPo^W0K|7M&1O;`(P_`LgO?8@F#wZCbG0MP9A0 zZpDl;19+tuQtO;Gwqt1?V(_mQu=bUhjQPF`u^c^4XRNJD%MPooR*{`QI#%0k$E7>{ zgHxEdL8*6Wf=4(|f(|OXfhZUdnnZzhzxC8i9=l$QU~Fx2p_n{02mvxM9F8);#sCZc za{sAjnUdS?GPyyuvrSZh{Q)b|B=O}UTTPY2!w@NXqs4seVWJ@V(S!;Ew-d)!PmcR6r6U*#h^bzr z3}?1+#)_}3W0-7Avgj?^$0_=kI^WlRdZDHk?OjA4W_mFA1s2 zBT`Te;P0VmqK6s}GX&j!dX4vB>PTt@RSCDq@)iZGPh@NbP+4cIlQGvNbuRvabchu` zH=?f0eWUqr7@Hz7Cp?(Q_X?egu#DS{BGA_fMtm5xD55p4R9z4hgNLeuKWH~4qiwM= znp;zlM)uhDQtEOY562{J>TLo(*0&$4oV*u{sy$-f25?2$DhF9(FM^q#NMT4I!+^R2 zNH8uW=c4{T4bbLXNb`fFA(QA7i&}S8J=aN4#Ggc!_=2_r?4y}YFqVRTH&Jc(K{Gy~ zr8hk$5_1qFhlh({5Y%AWnaCHQrHj)0Tel#&>M1rRhY(brB}=uRNbzUdF!&cP*|tWS zlf^I6*CsHSRy3OyOrLqHUOP!r)H=|V34JwG@ps5+N8>$wSTH}lB4>W3P-W^z?7?9H zFEq!_`Mrt-SJ4g-1b(46NRZ~Fr~i=}>N(yIsH)W*a)HFNKUUwS?0W+hv-SXfE@_`Ce`So9Bub^|jOdl&7liACdV zt9YTw9C&(WAX}m$dmVaC6TH2OpNr5VEdqkL9Q4b9P6!AdD-g*K5p>@DJ}*D>6~k#L zMY{$!%g!hMA6DG%5IomwI*+$Ik~NqHR#}gIje;)&z1_xr5GSbV2)wcQ@0V1WS`NKY zw=sgIgKV^b{_5o-9u0GhXwR*C&`E__(dh2K$zf>(x!O*^ktC}q{?8|6qKZ0ZiG)5i z6r!)^QPRwIr1s6|yTjlvv88Xf_=O0k-=}TP0;`keb{OLQ} za@mXg6j=P;64A;EY!xv8>Zs*9YQc|aKUEM&;g`q~kpUaDh$sp!lFf#kL!E#SO;$BU z#zLQlr9eWkA0p4YM6?Xb^5YReJ{Is{58?n!ZEi|zy$h`6xkV@Vn9=p7-N38@p3n(^ z4+C9q8D0e>N3-`fD;;tf`>+toEmkby=(_cFuNh5n5YEibvg6~z8&^v2HkS2|>O%Dy z1uh@RHNO>We!V>)FpXdt$s=xf3$&EPqEVNIro*Ppa){I;;-Q9tAvkG@7-dEc+gWnK z8(_o-Q+_7Zi+!38RZ(Id!~YU_oXDBc>EI_KVY$yCOz)R`|q?LByNP$iJ za%$EITKymibKJd&CIQV-92F^Amz5;5$jsn4$BBkhpPPHhFJYuaj4`yvP3{9K0H3U^ z%04v1mRFw}M5#4{v77xa)*pH`E3hZXV8{TjZR?f$Ako0FaHQ`|Br;)J7R7d|8*!~_ z^z6EkADMVv3xVcVL5e|C)s&@iPJ2OYa4Xv}G<^lLdp z(Xb2zEu?3c?MuL2s|0a6X!=X@8q1#YTD}1hk$}TfMgYy7Qn~sB2iW&IVQycQ%M%Tz zfVt$A4?HocOB?zRROj zOaI0h!eD73!|;To1->R~ARpFRs+c?wGwa$BqN+wd5>oE6tJ7R2Rps_P8N{3aSKo-y ziO`qETOFh;OyWOHT!GMawiwDEu2_)>HQ&$tY6^2H)o@0-d8fK4q6*ZCFP{_o#2c(l z#5PHVv;x`O4wkeu%vp_Kvjj5N{#d&H_z2(WavpcH+uoFk|L#`(^c$@4+{=lYe7Epo z5HWzBgo;aKqUY*?HxArF@px#bNtR$|G3lheJ(0?j%Wo)mV#oI|Lqt+aepZ@q?XZis z9o2;16jt@nX|W*!owMf^%SueWcy|=sKBlxbxW%eV+7tsEh$58G;#-sj>FK}jTM~i{ zC;2Nevxk3mUMiz0l}G90gatRfiOaFhR@Mi(BfJF}R<&Tl94+*0bgXNe%@PyTq(g(9 zEd8DMieBWzNRgRG0ks1M;k;erHfyg*i;pRNZ{(STbO$n?d$endDietfy}qCYu`9kr zN|iX$BnGE*!$0rY;;4`oVax)kY5ETjZ!Xv{C__~nk1T)Zi`FkrrJFVbgv3LjmFnNa zeZ6RAdKh)xfCAHcU?uVm{|$y0C3v(@Ly%iq7Wk$nn zJX|m(@bt-w87r|5QRX(R#xeDp>mY1V=5!XZAye41k&fLD!xbRu}{EMHf}_X9!m& zS421g`jG8-rFFt`4cMB}0*T)9sY+f*MHkrbKz`43er8Kj3`OQuk z`^^C+=ZFr@q^>&OW@KrTsPnWl8RG2L5L5M))%>}s0KeEkX z&tgz+Cu7b8K9NwZ3$c{7OkqH-!Aj&hU_`~U<1l7KR^WEG|g z3r;GW3OByz!Hy?Y2Wpds?VrXLNSsbf?6jJ^-Rj1ld<~;96%e9(Si*rORkp z;Y7zmpm|u5>ii>aK7St=?-QKY-xq}BS2Iet9?G;2F(#mIK!rKnQDf_>epkYu*TIa? zaga)e;c`o}XG=Gm9Bp{3Kdi#>U}tx{(_E86AhMe%r^kO zmBhz}h4F4v6vYJPc?U3cXQvK+Adb~EF6ov?ol;_f$6WWWA0I#eW<0N_IeLz^z_ z1f2hH&3B8)PCr)-Q@M+7^~)O90hG+1tNkzH4SW!jVq9{B&Twrh&3K+z-fSuVWNIbH zaGIN0scH>raZbhcCa0nMy203P#7=hUWBwGxZ;ERab=IxH5&B->iKpw4bV}BP?5#<8 zlt%aM{PU(CW7k+ZKd;p~cRvxzh6Z!_ZRV{^j9119^AL4D&E{XsK#9>00pt#NsIfyH zliSI*l92o3{7|b(PD2TAGg&CAq=mQu_D=iL47{AI_q!891slpKu0g9-Q7Ym=8=TUJ zbqTD9Xnnd9>c8*~S3aC@5I zId9<&{@Nnk#C2TRPty4e#6Rh}T?J}0r`r!1WIE@-f%LNV17N|e}3HP zTTe;T_PdA8+H&Tv4M32HJ~!Z$0ouEEdSaO^6x6&x`TPhrFwU$Ql7mgsLl_b-rwB5K zO>`N#I%M=ce#7P$#d!|3CXnUj*;?06t$KudJ26^0^&CM2K+L2#1VPfD`|fWhT5pWQ zn#}!Lw~rA^j0Ldp%>@W>as|Gg&{aM{W{r-9B0pm;O+zq}=Fx+iux zem>xfP}p5O2sIZ_N}OxTvEXZws-G|#5^2vEV3Iki)iZyFFm$)`$xb3YF~bdAuTO=i zf<_`3rO5BaPf);TzLy~A8p#>vr`qUyGwiRcT0A4AF=3m6YWw`2+x8ARiM);;8u5%(#v;jEKpaZYe zB5ZR5VJpxkQQ)3PkuRu!^b;uVy7E8APBrIyP7%j~5xL;BR1EiYV@lmN7Ozm_aW1X; zUic;g`7AlY289}mBIl7tXMh?-uTh88lw)Mo$dwL+yGzlF(mB)@g8=L{30@V${HOX_ zGLul|Tw~+X_MTNPgO*FpaA87cGHWu}-*5$~jUEyET1|PcBYKVnGpY;CgsG+OP%fpvvPkA&;TN*yokxN9&0`*&@ z4Gc&qtv8Ev&7~S zWe^%?q6QFx#*o!|d^NzLLECW=SZ5-Ep!Zu9;PF$BZ>@!-xK_%e%nxlGmrKwG{ zQ6BJ&pyLdtYMBAogX#HGgj+o%VuvdB2(!Ui^}oj;-W0i`hR7lHe)*_0vH%o6LDFIi z-xecdxs#g2A!LTIlJDV_qXSFwq$UnSMc;h4>}WYNjdrFYZOjaKnl+v$9fN#|Ho zxez)jM+x!%P*fK4cSNseEaur4e;Uvi8){6e?R@|KK^3$>o?!?t_ip%!GPLSskM*hw0OvRLvqFvVO0K%;v6a{)I5+jme_zS1LUS&F?)lyO`t7- z?#?9X-qnG40C;#hLx;djm1N|}OOiHcZM4_lp}n~TEC%62;YdX5A9??C3c!V8jNoiL z)&7_Yue~qMuyC}@EPJMoWeE)|!1Nus)|ki_sm5lFLwe!RCk#QpxR0R1`9JFZ1Ps8% zDk1s28e|}tEl4&~X{Ee(*D+x5QR*HrJ0mo*yE>1Lc}}u`5}WQ)zfms(mJZTA`#u*s z>dKBN>i*6SW!fCG>GGoX?AUy_SA?f`{XmgI=FpBepLqXJ;#~ z3+Y55$Z>9d*7j@=thCRXp67wmIdFP6=#v0~QTfmEcS2RQU$=Q0Qy#mGGVp6!gI`SZ z28Mj#iDWw^IO7`BRV5-L&M~nkSO!+nK7@sgQmAoSxI0g%2%S87660uBK67rNK>DPi zTTVFDr@@2p!Gy;uDCo{HCdjpwt3+{nwFOzkjrBhb5AA-p!PCyq3b}rKnK;}H6{8Ujdn+&lpT@2E;#09S%2C2A?m{xYp-+<~*JzB-q3hjw zc;+2K@p=o}?N|I9ACtM<8r8%n$=SvT>;6q46_n4HO{qJ8#`<89ea0LXId|2aN?T*Z zQZo`tgNlF!tRx{N_!a<$mq;R^!m|tcpE@=qa-=2S`Abw!(Gb2~zm(a63n6SQoYqtL z->jS;XJOo{2A*`gjgOIR9=ho}L{kvu9mc7^CAKNal&K;w4y<$l;84Kb3#hLYfcB)g z7i@;>039|;K*&j0o?XPaz7#5$UW=9v!X!l<4BBdN4K{Hc-jTPAIxk&BvV4f*p_>yn zCwlldoBP!-_jd0U#^FxckpX`dZBkeY!n55h+PDP_nE-X82;i-wv^{>=ALW2ozcBMl zdl`|gEtDuV4-%PA!pw!n`g-rNlNu&jo5l(y0e&>A04Yy+e4?BSn*kLSDqM96Vh-Q} z7lhHoCOpo*^_}~f43I_09xCaK7(S$JEDp@3ZcgwHzk>3;$N`t13tT=Djhq zUce~sS*4Qbc$9+o=)B2gI42>LYT-hSxL|a4;~V|L=$@^8y7eXTK04&dSbh9N;$7<$E?Dlz~1%_ z2(9>Uu4D}vGNTD-!VgJI!<4i&CR10QzDZ#(E{=*iI|T1AJ)=w1 z=!WHXEs{p7-IMD!S0P%4qY61Wd%USygs1ru6kMYEW`m5KNC(V>O!)xn@E-`4YYWGl zLgKq7P{|BRWvW4L!kMr&m{{GMGMS+8u!o`>2(a#Le26U1FT-dUc9sAqMb6CGl}k1f zB-m3a+$kTit$ol~wj))qt9QTf1+@O)Z>OWD{3fglE1LCMx#Y)_@UyJ78iiGD>OeaAHA>Z78Y zDwLH{CDH#H>9W+^BWATtpYgry%-r}jjqXvzTy!CgeK)vvYXTPcq!*Begx{k*Gw%;w zjC2-}4`o}Fav|7u)&Jy%{1;N^p#qhX91?L-Yt;^u#;yGK{aBwY@2mACtZDk zJIo6ct9_3)NB-*J?#uqebhh_9zgw|xQ2g`1gtb3b$0w;gRZLHb`ru=b`z>M}r#7H} z?YK<~wDSOheXo@#|TFT4=q8z4a99Yge8H#6M?c^AJ99-d7 zY{u%!#xmY_A>y@1A)FTl2In$BCbENRruz@I+xT-)hsUjMK>@j$tTPTo;ReM|Isf3g z3N=n-90JQ(deC~-qj50G#V@c79zTIw;i$ELQC;w=iwIx0(wq0D%3-|W}5 zyoTgE>}C2Dc@ZJ@#II8Xh6g(?1E&xO>B%7hRhf$Sen^ zzzhm^T7epO8A)jdhk}{VR8Py-zi(?*tX?Txnl8-J~r*WnYQi=McSVLA<42c_D3Z~9Jc&OK`%gcBPs!)-4n0qDyUQzJ3 zYM%Ca(<5w^cN1e72pzwMnPh*#alP#XwAf|LLGzsk+u#Fam0p(0roA~XA|Z5esckRG z$)Ic(ZxZ#XJMYd51cD(bwDkASn{zFDL#7sake)zDD|S2#tMYr(o?HiD;!*Puy{n`Z zkH6aNO-uom-Ss>PaD)qD@2v1xf7cWn>0Kny_G?v{+ifXy!F+vzrWFgTgKBDtjc$x` zM-*ZTv~O{Aaz*!)!#da_EVeh zC;CjgNIKyzy&;)S;^>0wEkkb=GlJraOM~~DP{U2hUdvwKkYlnu*L4>nmvrHUxz!w)~&GGG*mQ69h}K(zftNZ|1@*H68q{}E{a(%W9stVWMyp>1qongc!GP=H3iEww=9Ptgkmwfw-Q7?1&mR+ zOKwK>=+T!BaW***SEGpJ5y~Pt+PGo1SaY1(&_;rYjya4Ww0LCH-{ephzsh}=r-1v2 zb0x=0b3mc-E0y3TAp(8!}hyJ=v$Mn8D5IRkJ*);CT#bF;vU zs&rc^e_uo}Qja^;S?}AUuC_HMo1;$)DqpY@n3f9^bo~M!2#Pz7Uxs2)7iv^am{1?5 z`^&J}g9%!Go6-}9_P@eN)j4;*pU&+eon6M|w7v(+CXos8(M4QFP+^d4x_-vOhW|ai zeJn0@{6TY8qxu%26_ngEp@bZah_t+yztS%WN7ycf^RTxxb^rlARP>l#^LLvk$?7pS zbLAET->mcGtTPZusE~n~LMXAU19owk|M-Z;)$F!!5!*CI*xKYLGsONJI&;h8e~4&FYFL&ry|;mYJuWd7{Cuk};7UC6l^mB% z(Y`A86t5$eIIwRW?A9dd%>LHiil_`<@eyQi>nDjX#S|=WJqEtA=w)SS$>JzLn)ytI zR9@Y+bHcq;R!j@ujA@=uCyRsZko8!?SiGIYwxAe!gs|5Lp$MQopxpi< zGhn}4JhvYw^zIXO#0a0|g*TmUVe=M>*stciVQQ2iC66B)XH2*IQYXnl_#|&WcmT7X zHw4SV!qlzg9<;tkR`h4lhG+&5y_oymNBlW-(O?&^T6Oq>*tT_NbKdd36=(hK1 zynFTPnntk=#8*ap<-Fl_fM)be(gSlZ#?rlkUdYdk^Gvq)efHNGD1Ax%Fw zH^LmE$-Ka8x!8xQhD!BuB~j3}Sz@#VW3~*i=NqvwT{8^qr1{R>dGD2W z!8X-Ho+hQ07ZKgI#9~-8e`IjV9mW27UGvpZY0USR_w#2uqFvRgjieKP4{OJPrAg29 zatl0vhIm$2wQ;ULV0bxAa?LxV^G!`1P1qC)L-6S?2Wi0+_x8yC7g|_0@-&!SAs~#?%Kp(>5Y4#>b&XmJ=_g=VkV;NLq)(r! z4Gax5;b$ob>DL*U%QE%ri)BS@xp+)6h%1LZZ{nuI{Oix8g*+jG4QbM*N=5NK>>^=K z`E_EvP{<`@kRC;BqadGz&wk0l4>Zwgk2j&)>080asak$C)8F7M_q`d3*m`e8FK}y^ zY5mo~X@%P?86U@Ew2Nf5HTa(-1Z?uL4VlYDvMUwdBh#G)U|7WPj|@_*n-K$a!9gdD z%fG=XbmG`@lX8LQCCMsVrkI<~`HEIGVx`;D2iuYmNu2N=jN*bs6ivVkG}I7!<8Pye zzhZymC?BT*CC&X8#BD+)EjR$8ph=tSUQqz4m75t3J#Q5m2}P6RMA6u2Y~qIOO;7P# zSX+PepRmk?Yr!da?6c$uy+Sf0`0mdYcu8aL_BqFP&Q`_VOZ_>v(4Je^4US(VDZuWN4mD|jK zH=8XAtC|PRMGcGPrGATzwm%i_ahp;fLC-dgiRvgW^KIKr!18k4~U!pRS^7I#>IoyoZ z=yS)Whl;GahFESHPU7;HI=23uuSb>D4Ju^K0>11TVOAcAL*yWbqum@=~u38>>{MVW8 zwb~q@z-p7%9#M*RXB^5o@PDR3`*MwEWwXbWo_YII@NKvX4!;uXcjEod!I9M{^vu|b5OnLw$-B|QL^ccy(l8#6`4LAetC4WDyY<4aCyV_xK-U))b8TbgDu5> zStAj=2$j4|Q`q*dj?I+V5uc8O2;#~*bZ%CJp4nFNbPdwexH+Vib~e^t<{jAGJEV6Z zKR^0y-^LojmsW@I48?HD!cjeswRe(3E+(KYh$6|*b_Q0!3!TeM^ciP)!pSBuUD^?N zl}F$=ON3H|Pg!9SCoB@IAz7Nh8ohnesnAz9&Rd72bq+YsZxaT0i_2fY(NHV^@E_Fs zCt_T5QnXQ_qf2P= zZF`225y_pRHIX&@Hy*u23{h^Nnt|sgg2YiXJ|ju;RWX2vq-K4$q^l)bypN>3bhB5 zJL>9{&cb4>JunW6>S$myXVG*ztlza4ie{rFo%$xw0 z`Ar__XDhdUqCQ9`Gd2bNtyv=3$-H|;VqL@fLh3uSYo1RU2UxFg0h6MsXalEF&`iR~ zajdsO0$vIrnv{Dq{sNHrux1U?R0!L&sacn7+l7RBoe^58TE@;Ibt=BM{a_7fk^}r% z3(&&-wJnYKCQp1lns4Z!# z76$GVal~P5XcL*Hl`>seqt}RVb%Oo9h6w=A(f#ZUfmrDLd8qZJ&Ai&Z?m^uR#<)HO zFOX+)dAj0|nuA6k$Sv=eedJODwnejibAG?`mnVX7KH@TR%41X^q-uv zV#_If0Tl<8!Ft4pw(j#*rn`VCtpw|>7MimUR&5!u@i+DJR7w#oRw~oua$4-H8>qiW zh)US}dU!)n)r;qLVm!xnU?8}KBklvj9{t7=O)^W@@$xVZst->;jTD(;vQyWkF}Yb* z+`~H1tkkTlvOt~0uFwl|Sh6ZRro&9yE9X!HI&PN>8HJ;A-Qi9rMVPuWg!H!KIFR9g zA+QleK%>~SSOmEuYSgcE&yk?|GDTw>bT?^?iN=r8s!T^mx9Ij0jp$DG&~xCmp58<_ zmpzhu)rT}tIwcW;vt49VbPZE$5f`9L=>c3PP}z(K~M(0$Wuxa z8cF`cY>(L;{giYa7vPCnT8+EMt_-Qt^u8ax=qbes+<6B#DGnEn@5t85|u8@=STjaAv&br0Bt% zsqpE^zC(`%gS6F7Aq=@O9>8I$H>Sy_F>MzX@ze+TZKEtD0nN`8?LPGMDw|?ga17nE zg$qH`g`9CvxV*hDu(LTDy2DcJ1Z%<#&KOzyPUMi*(WIkQ!L*RL(&Ff$MClXNFw@X~ z(O6J3=JbzC#-ZO^`&fg~lD!?hE(>qK4KQ%nJ%e(;aYgMg1b}-&(A`6~%RU{S=p$_b zTvolzg})E~5pkQ5&E~7DjCXAUkq*C+5VNrfGNnbX5PxRU86AOPbnsOa8YI`v8_%f4pMc?Pi) zv2I?eEeJg!K#D4}+n3_^iI^5t-4)6dLLtykk>MXkaz??7X*vcK*X@Aib`=xYFCN9^8@^Z^C)ZeIw5uMB$Gu5c^AwI^`|#3Qwy!0X=gOyi|M#CmgRJd zjusn6pm!Q*j`|AmU%tOozpb7YjOau5zk2t$j2x*2pvSpkEc|CL^!5z$w!mMJGx}P% z)tPc#8G3Kq>nL<(fj{(p!!5y6K^{9USZ+8|0Pbqs;GV!dgp`b?0LMo`-b=J&_XC78r=a1fL~kwQvIWCo-P=( zD17H^8bqzI+5mGGrAgs&-Lb^K?QFr)6h zc>5olYj<)C16g+8rW6t^Zm%N8=>tQmJ?&B63R4yt*9v8ec%9Pf=M{62sU!93r0nPj ztWO^vEt|+<&jT*0VaGRipa7C>-5L2qt#0mQVp~z>sAx`-I@OB*FV50Hir~iR;8_uK>gks*C-DvI806`P$Lci& zXv)#SM3<#SfuKG)dpluU1&7vV7wKyF+pwjXdjLm6Nr;Cuulhpi(aV}g_As(SeqhS< zNiiaDpba^cKV(}8z3Bal00IL$-^ZGhd;q~1KK&Ajak*w`F6u@gX*G);v7nvKM@^1jgHbA) zC_~DyA3YyPI?v+OX#z{+az2G(1sVLmTp-Mg!-0tY;)MLc5T#zyy&O{%33R2hQxK@3 z#!GM_WeHtb8udfWCs34r*d=2nCo@=siRuqK!v_5VnCS=!>$Iy&h=#P>$Gp%7!HYN^u*HFGP2pq3;jN}i7chGd z7mY|gm=jn4GAX|JN_b<$qjhvtQO)^G;WtSKg`3^gCY$`wTxAgO6e2~SVM!Xxsd$oj zO7P_gQ0?1so{x$hR$ZnUB9Za#^%J#;QzQ0AvdGfYkOlbxiEKeFyp-guTMzR}v zPQQ&`j)+2?W_5eKMBr_4H&5;Q!ODt&_pwLpVr1*^+hc1rnxib_<*9bksRpq^3p!t~U2P7V9{j(Z7je74rCP{x))Pjqd z)m!nQ&7CDFHM9Ac@>9l%?-~q8n>lB zjvfK|KrP1E&PE@Qa7hzRW?iXUL8!+8r0uFdD=v~IjcDwm}iV?mavh=%%+L zk1zDhsjY)|5A3_Bq2HEVJ?fMcA{~VUS)8sTU;-XW@BX3YSBEOx-jyS7>vz8;gPv2& zXjJSc4U1oFCRM32q90cJ9J5Is{+L3nlSX&QzZX8iz;%p~8e`XDB*Wcfz#{>0bc)lN z+j8VbK)w!Qid+XZZ}w-;@36qZ>uBN)UJWKMy=z=*YYKHNvYkc;p(+*FQroLLt-!an z0S#Q`{zPGGv~i+5YSze~ou3K5?eln6>T?{7~?$r-gLBq%oS2S^hR8 zj-tQxOk$yMlACQvNtq*HKpsgFl=rh`?C2A?^A^}T+D`5o^uYp8Mk+XqbBC(PKQHM& z2G$&{Iz!6NwFCX1bh_?kyOPKOS<16En?>!-U3T<-H6O2tXNsXE-)5=uihi)o^=mlJ zTidJ(?Z^u~-=53TFO1B;uwqY66IK=^nwNBCYBc#_@#k|6!lell>8ygOx+hrR%TV%=0(JSe0cu6O{K*A)l z8c@)pdl4R>q3v=`B}p4whsBX*KkQSFj)tapdP7h>hW;&Dy3t`MmySusQMn#(hi0^8 zUC+79*R`eY`^Wm{2UFLI4Xj6ZDq6R5pL3w6mXQ5gZn>XJDd zXq=}br;%^Er2c?nG}U0h-u0hOwyW)MHRYR1xf$PCj*3rI+pQ(Ee&D0K1M>O4#R}^AK-T)fvZ^<;PwXf!m8)6|e7-=A*2s;FtD^l%qp70cgUx zLm_CQ+w2Q^))zi)yJtE~_u`S!?cu))+)k8%I>YSFK62GgOgNZp7m=+<4vVD{9bpx_ zb*i4_bk50Up8)VWvl!^tw|<4<3kl4h)sE$chcF_#yg7)eD%ER>cQH;<`+S%EZ% zM^~fKon8taJ0rx@Fmri%uu5sKufBArl4Xf-D2i414p<6*Z0JeqkRZrh{z`Zmdp3r| zGj##C@9{Buc=3I-Lo>cIIOT&eYtr& zn#@-@3+^GEC*ZG*Hi+2cKJu8WG@#b!7rfT~>Si+h4tvgag7e z^C(+vT1WyLer5u6Qn~^qioliDKoT$++5dE6ig*B2QM@`JV@U+ru~T)l1~XJu86w!7 zda`GvY|X!yx2hk=rlWN%S6DL&CFY<9K3HbaG%#{#76>suiZ5$>uu;%0V-672X>*g`{}>epjHJ zR!U4{sd;#PY|LEenxA9Zd-TYJZDZX-kCU0_2NE341jcO9)d~!NjX7hl$xcyXD6CUU z2dUo;4>ge>u&b9;tvxQ?)j7{skKf2RIseFarDTA^xS7BzIzJ0Pf}P!tWcbY+%bxz| za0L*Hoex1haHmQ8N0@Og-u5Av#&@KO^hHC!r;;J=(8?NPMhZA@41*b=gOg_ZJh}t< zSQd|GlEN4=Bl|*yYA27c!1PjoiJRBNDDZVFUIqf3Zup-om@A{mXGbXaESFUVu)yxT zOrSKe7jiluYj!w`+Cb}lP9kaO69A6i@8u6 zGkve6oEvN85tE2r^ru|cmv#^+Zf+wv3Bo*DJ!dAwX@a`Gt1h7!>pzz(UzCelH~p}N zg1N50pvqlgBn1IY1dvYBc3;D)vhN4iEoA^*OdN5#T@&IRD zHn1|=sth|Uyyb?BJYRc?wxj8^NyTC8$3+im^Du^Vebw^s0X%{%onDBb`>s#T((PaI zf`DIvf$2^tEc0ZqV4+(mG2h~>_EY1i2^^R}3)Nd7Xi?KV#a&i#e1Y$~@(_O!Q5s^T z<}pp~#QkmjIl#B)63OeP>TH4>{h|MBILk0BEkuC8hR=#YCikf|9 z(C-0_?h_9vrk^x_p(9}3fDo+=`cD${I6)Ey3vBV-&srtbm%Y+I+^E;Z>)o>ZW&p*g@qtIB0tFhpXdk0HiZUlGkkFv5zA%i`KRAk(&NRPh!Qa|@N-~o zv>-)~Ojb{~)E%aK_n^RDLcPN>6IB9w9!}C)S7b7Ok5a{m#Xtg)u9*C*>Z=w!3$hN| zdus8NhR(hZEw)x15a3}Y5GT&;8 zf_^XIJ9lka!Xw)aC5SAOb|A_Z%q2h>-+%_vlvG~Y6opiQyx>?D!sl+_fvQ?S9*FQM zYy@ah=H}I@sFK#y(4Ps)7@&G|2WMj|aAz60fE1(xC;0M~CFQ@0dN~bW=J+Zpxin7! z>BnN?5^fEfN%wQC*yQVNA_EhW%~-d>nMMJE;|J5u%NKD1Zf*BUP+)_r?j<}l656$ZNCwRvR&GvMn$nnxCb2q?Uyx2%VzhZq(+!LvAR8e$Gv+6L0 z6{|9roP$X}+86!y016P-_1!4PuKQ#*D1Uu5d)7^k4M-yHyC>irOTqoft07y^WfSyr z5>|Qq<7m)b2;to7u`V-hFjnULn4EOIfpwa?nWM0` zl?jCIJ#o;IrwhNL zr^fdvnmPZL-@$mZ+axxKOAIh>R0S#1UP}jOq~4YtTe+CXG}v7U8TGHO>>OWN5BVER z72#cbU3nL7!+IpiL+%rs3L-E0hIxz5jIwbA+JUeW9{)v5BY!^RGA=LeW3U_f3DPxM z_Oaec82salCS17h+(r%k>cLTl7{Kig<65;A6ryTr$}6CAI#9 z&pyPl?enq+UXX|K(fA9aZ6!XS$;5)r}&s$(%gh8`AaXpmBrdfB`#RG*iT|50t;2j1XR z-k>BF@qs-$S7ZS>*`aUS8Qd@noFz5P63o{cmV9kRahJ705f!oL6$F$BhnS|XR77Fr zG~6y*DQ{4l^=XRC*JX|>K>YozB#^c^8?EfAXBUhgR>{Bg^C9iqav`$mPsW8#fxc{b zf~&r3=xl&Sfw@o#Lnn;a^Jcq9UxZS8LG!%62K~?Ii2_fqh&V>l(eW28T)!(G>`~d{ zFca6RZ&@wgRS47SZqXj#RFY<6r;YC<{zK?;#s(y2xTj+*u=VUdJv31Siq6&b=}EWD zjGO#xTY2EfOnGdnx&6o3xzA3TCCt~=JBfzj{IS|2Gqs$N1DB&njvj`pPeK}!m||7D hNOUy0#u09TXhj9o^w>0(3a*~BF;BRP>DRE}e&tyyhyefq literal 0 HcmV?d00001 diff --git a/tinycrypt/tests/test_aes.c b/tinycrypt/tests/test_aes.c new file mode 100644 index 00000000..ea3e2da5 --- /dev/null +++ b/tinycrypt/tests/test_aes.c @@ -0,0 +1,2078 @@ +/* test_aes.c - TinyCrypt AES-128 tests (including NIST tests) */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + * DESCRIPTION + * This module tests the following AES routines: + * + * Scenarios tested include: + * - AES128 NIST key schedule test + * - AES128 NIST encryption test + * - AES128 NIST fixed-key and variable-text + * - AES128 NIST variable-key and fixed-text + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define NUM_OF_NIST_KEYS 16 +#define NUM_OF_FIXED_KEYS 128 + + +struct kat_table { + uint8_t in[NUM_OF_NIST_KEYS]; + uint8_t out[NUM_OF_NIST_KEYS]; +}; + +/* + * NIST test key schedule. + */ +int test_1(void) +{ + int result = TC_PASS; + const uint8_t nist_key[NUM_OF_NIST_KEYS] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + const struct tc_aes_key_sched_struct expected = { + { + 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c, + 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605, + 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f, + 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b, + 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00, + 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc, + 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd, + 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f, + 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f, + 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e, + 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6 + } + }; + struct tc_aes_key_sched_struct s; + + TC_PRINT("AES128 %s (NIST key schedule test):\n", __func__); + + if (tc_aes128_set_encrypt_key(&s, nist_key) == 0) { + TC_ERROR("AES128 test %s (NIST key schedule test) failed.\n", + __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(1, expected.words, sizeof(expected.words), s.words, + sizeof(s.words)); + +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + * NIST test vectors for encryption. + */ +int test_2(void) +{ + int result = TC_PASS; + const uint8_t nist_key[NUM_OF_NIST_KEYS] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + const uint8_t nist_input[NUM_OF_NIST_KEYS] = { + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, + 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 + }; + const uint8_t expected[NUM_OF_NIST_KEYS] = { + 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, + 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 + }; + struct tc_aes_key_sched_struct s; + uint8_t ciphertext[NUM_OF_NIST_KEYS]; + + TC_PRINT("AES128 %s (NIST encryption test):\n", __func__); + + (void)tc_aes128_set_encrypt_key(&s, nist_key); + if (tc_aes_encrypt(ciphertext, nist_input, &s) == 0) { + TC_ERROR("AES128 %s (NIST encryption test) failed.\n", + __func__); + result = TC_FAIL; + goto exitTest2; + } + + result = check_result(2, expected, sizeof(expected), ciphertext, + sizeof(ciphertext)); + +exitTest2: + TC_END_RESULT(result); + + return result; +} + +int var_text_test(unsigned int r, const uint8_t *in, const uint8_t *out, + TCAesKeySched_t s) +{ + uint8_t ciphertext[NUM_OF_NIST_KEYS]; + uint8_t decrypted[NUM_OF_NIST_KEYS]; + int result = TC_PASS; + + (void)tc_aes_encrypt(ciphertext, in, s); + result = check_result(r, out, NUM_OF_NIST_KEYS, ciphertext, + sizeof(ciphertext)); + if (result != TC_FAIL) { + if (tc_aes_decrypt(decrypted, ciphertext, s) == 0) { + TC_ERROR("aes_decrypt failed\n"); + result = TC_FAIL; + } else { + result = check_result(r, in, NUM_OF_NIST_KEYS, + decrypted, sizeof(decrypted)); + } + } + + return result; +} + +/* + * All NIST tests with fixed key and variable text. + */ +int test_3(void) +{ + int result = TC_PASS; + const uint8_t key[NUM_OF_NIST_KEYS] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const struct kat_table kat_tbl[NUM_OF_FIXED_KEYS] = { + {{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3a, 0xd7, 0x8e, 0x72, 0x6c, 0x1e, 0xc0, 0x2b, + 0x7e, 0xbf, 0xe9, 0x2b, 0x23, 0xd9, 0xec, 0x34 + } }, + {{ + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xaa, 0xe5, 0x93, 0x9c, 0x8e, 0xfd, 0xf2, 0xf0, + 0x4e, 0x60, 0xb9, 0xfe, 0x71, 0x17, 0xb2, 0xc2 + } }, + {{ + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf0, 0x31, 0xd4, 0xd7, 0x4f, 0x5d, 0xcb, 0xf3, + 0x9d, 0xaa, 0xf8, 0xca, 0x3a, 0xf6, 0xe5, 0x27 + } }, + {{ + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x96, 0xd9, 0xfd, 0x5c, 0xc4, 0xf0, 0x74, 0x41, + 0x72, 0x7d, 0xf0, 0xf3, 0x3e, 0x40, 0x1a, 0x36 + } }, + {{ + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x30, 0xcc, 0xdb, 0x04, 0x46, 0x46, 0xd7, 0xe1, + 0xf3, 0xcc, 0xea, 0x3d, 0xca, 0x08, 0xb8, 0xc0 + } }, + {{ + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x16, 0xae, 0x4c, 0xe5, 0x04, 0x2a, 0x67, 0xee, + 0x8e, 0x17, 0x7b, 0x7c, 0x58, 0x7e, 0xcc, 0x82 + } }, + {{ + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb6, 0xda, 0x0b, 0xb1, 0x1a, 0x23, 0x85, 0x5d, + 0x9c, 0x5c, 0xb1, 0xb4, 0xc6, 0x41, 0x2e, 0x0a + } }, + {{ + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdb, 0x4f, 0x1a, 0xa5, 0x30, 0x96, 0x7d, 0x67, + 0x32, 0xce, 0x47, 0x15, 0xeb, 0x0e, 0xe2, 0x4b + } }, + {{ + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa8, 0x17, 0x38, 0x25, 0x26, 0x21, 0xdd, 0x18, + 0x0a, 0x34, 0xf3, 0x45, 0x5b, 0x4b, 0xaa, 0x2f + } }, + {{ + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x77, 0xe2, 0xb5, 0x08, 0xdb, 0x7f, 0xd8, 0x92, + 0x34, 0xca, 0xf7, 0x93, 0x9e, 0xe5, 0x62, 0x1a + } }, + {{ + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb8, 0x49, 0x9c, 0x25, 0x1f, 0x84, 0x42, 0xee, + 0x13, 0xf0, 0x93, 0x3b, 0x68, 0x8f, 0xcd, 0x19 + } }, + {{ + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x96, 0x51, 0x35, 0xf8, 0xa8, 0x1f, 0x25, 0xc9, + 0xd6, 0x30, 0xb1, 0x75, 0x02, 0xf6, 0x8e, 0x53 + } }, + {{ + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8b, 0x87, 0x14, 0x5a, 0x01, 0xad, 0x1c, 0x6c, + 0xed, 0xe9, 0x95, 0xea, 0x36, 0x70, 0x45, 0x4f + } }, + {{ + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0xae, 0x3b, 0x10, 0xa0, 0xc8, 0xca, 0x6d, + 0x1d, 0x3b, 0x0f, 0xa6, 0x1e, 0x56, 0xb0, 0xb2 + } }, + {{ + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x64, 0xb4, 0xd6, 0x29, 0x81, 0x0f, 0xda, 0x6b, + 0xaf, 0xdf, 0x08, 0xf3, 0xb0, 0xd8, 0xd2, 0xc5 + } }, + {{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd7, 0xe5, 0xdb, 0xd3, 0x32, 0x45, 0x95, 0xf8, + 0xfd, 0xc7, 0xd7, 0xc5, 0x71, 0xda, 0x6c, 0x2a + } }, + {{ + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf3, 0xf7, 0x23, 0x75, 0x26, 0x4e, 0x16, 0x7f, + 0xca, 0x9d, 0xe2, 0xc1, 0x52, 0x7d, 0x96, 0x06 + } }, + {{ + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0xe7, 0x9d, 0xd4, 0xf4, 0x01, 0xff, 0x9b, + 0x7e, 0xa9, 0x45, 0xd8, 0x66, 0x66, 0xc1, 0x3b + } }, + {{ + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdd, 0x35, 0xce, 0xa2, 0x79, 0x99, 0x40, 0xb4, + 0x0d, 0xb3, 0xf8, 0x19, 0xcb, 0x94, 0xc0, 0x8b + } }, + {{ + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x69, 0x41, 0xcb, 0x6b, 0x3e, 0x08, 0xc2, 0xb7, + 0xaf, 0xa5, 0x81, 0xeb, 0xdd, 0x60, 0x7b, 0x87 + } }, + {{ + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x2c, 0x20, 0xf4, 0x39, 0xf6, 0xbb, 0x09, 0x7b, + 0x29, 0xb8, 0xbd, 0x6d, 0x99, 0xaa, 0xd7, 0x99 + } }, + {{ + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x62, 0x5d, 0x01, 0xf0, 0x58, 0xe5, 0x65, 0xf7, + 0x7a, 0xe8, 0x63, 0x78, 0xbd, 0x2c, 0x49, 0xb3 + } }, + {{ + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc0, 0xb5, 0xfd, 0x98, 0x19, 0x0e, 0xf4, 0x5f, + 0xbb, 0x43, 0x01, 0x43, 0x8d, 0x09, 0x59, 0x50 + } }, + {{ + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x13, 0x00, 0x1f, 0xf5, 0xd9, 0x98, 0x06, 0xef, + 0xd2, 0x5d, 0xa3, 0x4f, 0x56, 0xbe, 0x85, 0x4b + } }, + {{ + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3b, 0x59, 0x4c, 0x60, 0xf5, 0xc8, 0x27, 0x7a, + 0x51, 0x13, 0x67, 0x7f, 0x94, 0x20, 0x8d, 0x82 + } }, + {{ + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe9, 0xc0, 0xfc, 0x18, 0x18, 0xe4, 0xaa, 0x46, + 0xbd, 0x2e, 0x39, 0xd6, 0x38, 0xf8, 0x9e, 0x05 + } }, + {{ + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf8, 0x02, 0x3e, 0xe9, 0xc3, 0xfd, 0xc4, 0x5a, + 0x01, 0x9b, 0x4e, 0x98, 0x5c, 0x7e, 0x1a, 0x54 + } }, + {{ + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x35, 0xf4, 0x01, 0x82, 0xab, 0x46, 0x62, 0xf3, + 0x02, 0x3b, 0xae, 0xc1, 0xee, 0x79, 0x6b, 0x57 + } }, + {{ + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3a, 0xeb, 0xba, 0xd7, 0x30, 0x36, 0x49, 0xb4, + 0x19, 0x4a, 0x69, 0x45, 0xc6, 0xcc, 0x36, 0x94 + } }, + {{ + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa2, 0x12, 0x4b, 0xea, 0x53, 0xec, 0x28, 0x34, + 0x27, 0x9b, 0xed, 0x7f, 0x7e, 0xb0, 0xf9, 0x38 + } }, + {{ + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb9, 0xfb, 0x43, 0x99, 0xfa, 0x4f, 0xac, 0xc7, + 0x30, 0x9e, 0x14, 0xec, 0x98, 0x36, 0x0b, 0x0a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc2, 0x62, 0x77, 0x43, 0x74, 0x20, 0xc5, 0xd6, + 0x34, 0xf7, 0x15, 0xae, 0xa8, 0x1a, 0x91, 0x32 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x17, 0x1a, 0x0e, 0x1b, 0x2d, 0xd4, 0x24, 0xf0, + 0xe0, 0x89, 0xaf, 0x2c, 0x4c, 0x10, 0xf3, 0x2f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7c, 0xad, 0xbe, 0x40, 0x2d, 0x1b, 0x20, 0x8f, + 0xe7, 0x35, 0xed, 0xce, 0x00, 0xae, 0xe7, 0xce + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x43, 0xb0, 0x2f, 0xf9, 0x29, 0xa1, 0x48, 0x5a, + 0xf6, 0xf5, 0xc6, 0xd6, 0x55, 0x8b, 0xaa, 0x0f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x09, 0x2f, 0xaa, 0xcc, 0x9b, 0xf4, 0x35, 0x08, + 0xbf, 0x8f, 0xa8, 0x61, 0x3c, 0xa7, 0x5d, 0xea + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xcb, 0x2b, 0xf8, 0x28, 0x0f, 0x3f, 0x97, 0x42, + 0xc7, 0xed, 0x51, 0x3f, 0xe8, 0x02, 0x62, 0x9c + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x21, 0x5a, 0x41, 0xee, 0x44, 0x2f, 0xa9, 0x92, + 0xa6, 0xe3, 0x23, 0x98, 0x6d, 0xed, 0x3f, 0x68 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf2, 0x1e, 0x99, 0xcf, 0x4f, 0x0f, 0x77, 0xce, + 0xa8, 0x36, 0xe1, 0x1a, 0x2f, 0xe7, 0x5f, 0xb1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x95, 0xe3, 0xa0, 0xca, 0x90, 0x79, 0xe6, 0x46, + 0x33, 0x1d, 0xf8, 0xb4, 0xe7, 0x0d, 0x2c, 0xd6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4a, 0xfe, 0x7f, 0x12, 0x0c, 0xe7, 0x61, 0x3f, + 0x74, 0xfc, 0x12, 0xa0, 0x1a, 0x82, 0x80, 0x73 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x82, 0x7f, 0x00, 0x0e, 0x75, 0xe2, 0xc8, 0xb9, + 0xd4, 0x79, 0xbe, 0xed, 0x91, 0x3f, 0xe6, 0x78 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x35, 0x83, 0x0c, 0x8e, 0x7a, 0xae, 0xfe, 0x2d, + 0x30, 0x31, 0x0e, 0xf3, 0x81, 0xcb, 0xf6, 0x91 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x19, 0x1a, 0xa0, 0xf2, 0xc8, 0x57, 0x01, 0x44, + 0xf3, 0x86, 0x57, 0xea, 0x40, 0x85, 0xeb, 0xe5 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x85, 0x06, 0x2c, 0x2c, 0x90, 0x9f, 0x15, 0xd9, + 0x26, 0x9b, 0x6c, 0x18, 0xce, 0x99, 0xc4, 0xf0 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x67, 0x80, 0x34, 0xdc, 0x9e, 0x41, 0xb5, 0xa5, + 0x60, 0xed, 0x23, 0x9e, 0xea, 0xb1, 0xbc, 0x78 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc2, 0xf9, 0x3a, 0x4c, 0xe5, 0xab, 0x6d, 0x5d, + 0x56, 0xf1, 0xb9, 0x3c, 0xf1, 0x99, 0x11, 0xc1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1c, 0x31, 0x12, 0xbc, 0xb0, 0xc1, 0xdc, 0xc7, + 0x49, 0xd7, 0x99, 0x74, 0x36, 0x91, 0xbf, 0x82 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x00, 0xc5, 0x5b, 0xd7, 0x5c, 0x7f, 0x9c, 0x88, + 0x19, 0x89, 0xd3, 0xec, 0x19, 0x11, 0xc0, 0xd4 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xea, 0x2e, 0x6b, 0x5e, 0xf1, 0x82, 0xb7, 0xdf, + 0xf3, 0x62, 0x9a, 0xbd, 0x6a, 0x12, 0x04, 0x5f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x22, 0x32, 0x23, 0x27, 0xe0, 0x17, 0x80, 0xb1, + 0x73, 0x97, 0xf2, 0x40, 0x87, 0xf8, 0xcc, 0x6f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc9, 0xca, 0xcb, 0x5c, 0xd1, 0x16, 0x92, 0xc3, + 0x73, 0xb2, 0x41, 0x17, 0x68, 0x14, 0x9e, 0xe7 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa1, 0x8e, 0x3d, 0xbb, 0xca, 0x57, 0x78, 0x60, + 0xda, 0xb6, 0xb8, 0x0d, 0xa3, 0x13, 0x92, 0x56 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x79, 0xb6, 0x1c, 0x37, 0xbf, 0x32, 0x8e, 0xcc, + 0xa8, 0xd7, 0x43, 0x26, 0x5a, 0x3d, 0x42, 0x5c + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd2, 0xd9, 0x9c, 0x6b, 0xcc, 0x1f, 0x06, 0xfd, + 0xa8, 0xe2, 0x7e, 0x8a, 0xe3, 0xf1, 0xcc, 0xc7 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1b, 0xfd, 0x4b, 0x91, 0xc7, 0x01, 0xfd, 0x6b, + 0x61, 0xb7, 0xf9, 0x97, 0x82, 0x9d, 0x66, 0x3b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x11, 0x00, 0x5d, 0x52, 0xf2, 0x5f, 0x16, 0xbd, + 0xc9, 0x54, 0x5a, 0x87, 0x6a, 0x63, 0x49, 0x0a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3a, 0x4d, 0x35, 0x4f, 0x02, 0xbb, 0x5a, 0x5e, + 0x47, 0xd3, 0x96, 0x66, 0x86, 0x7f, 0x24, 0x6a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd4, 0x51, 0xb8, 0xd6, 0xe1, 0xe1, 0xa0, 0xeb, + 0xb1, 0x55, 0xfb, 0xbf, 0x6e, 0x7b, 0x7d, 0xc3 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x68, 0x98, 0xd4, 0xf4, 0x2f, 0xa7, 0xba, 0x6a, + 0x10, 0xac, 0x05, 0xe8, 0x7b, 0x9f, 0x20, 0x80 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb6, 0x11, 0x29, 0x5e, 0x73, 0x9c, 0xa7, 0xd9, + 0xb5, 0x0f, 0x8e, 0x4c, 0x0e, 0x75, 0x4a, 0x3f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7d, 0x33, 0xfc, 0x7d, 0x8a, 0xbe, 0x3c, 0xa1, + 0x93, 0x67, 0x59, 0xf8, 0xf5, 0xde, 0xaf, 0x20 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3b, 0x5e, 0x0f, 0x56, 0x6d, 0xc9, 0x6c, 0x29, + 0x8f, 0x0c, 0x12, 0x63, 0x75, 0x39, 0xb2, 0x5c + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf8, 0x07, 0xc3, 0xe7, 0x98, 0x5f, 0xe0, 0xf5, + 0xa5, 0x0e, 0x2c, 0xdb, 0x25, 0xc5, 0x10, 0x9e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x41, 0xf9, 0x92, 0xa8, 0x56, 0xfb, 0x27, 0x8b, + 0x38, 0x9a, 0x62, 0xf5, 0xd2, 0x74, 0xd7, 0xe9 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x10, 0xd3, 0xed, 0x7a, 0x6f, 0xe1, 0x5a, 0xb4, + 0xd9, 0x1a, 0xcb, 0xc7, 0xd0, 0x76, 0x7a, 0xb1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x21, 0xfe, 0xec, 0xd4, 0x5b, 0x2e, 0x67, 0x59, + 0x73, 0xac, 0x33, 0xbf, 0x0c, 0x54, 0x24, 0xfc + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x14, 0x80, 0xcb, 0x39, 0x55, 0xba, 0x62, 0xd0, + 0x9e, 0xea, 0x66, 0x8f, 0x7c, 0x70, 0x88, 0x17 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x66, 0x40, 0x40, 0x33, 0xd6, 0xb7, 0x2b, 0x60, + 0x93, 0x54, 0xd5, 0x49, 0x6e, 0x7e, 0xb5, 0x11 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1c, 0x31, 0x7a, 0x22, 0x0a, 0x7d, 0x70, 0x0d, + 0xa2, 0xb1, 0xe0, 0x75, 0xb0, 0x02, 0x66, 0xe1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xab, 0x3b, 0x89, 0x54, 0x22, 0x33, 0xf1, 0x27, + 0x1b, 0xf8, 0xfd, 0x0c, 0x0f, 0x40, 0x35, 0x45 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd9, 0x3e, 0xae, 0x96, 0x6f, 0xac, 0x46, 0xdc, + 0xa9, 0x27, 0xd6, 0xb1, 0x14, 0xfa, 0x3f, 0x9e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1b, 0xde, 0xc5, 0x21, 0x31, 0x65, 0x03, 0xd9, + 0xd5, 0xee, 0x65, 0xdf, 0x3e, 0xa9, 0x4d, 0xdf + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xee, 0xf4, 0x56, 0x43, 0x1d, 0xea, 0x8b, 0x4a, + 0xcf, 0x83, 0xbd, 0xae, 0x37, 0x17, 0xf7, 0x5f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x06, 0xf2, 0x51, 0x9a, 0x2f, 0xaf, 0xaa, 0x59, + 0x6b, 0xfe, 0xf5, 0xcf, 0xa1, 0x5c, 0x21, 0xb9 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x25, 0x1a, 0x7e, 0xac, 0x7e, 0x2f, 0xe8, 0x09, + 0xe4, 0xaa, 0x8d, 0x0d, 0x70, 0x12, 0x53, 0x1a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x3b, 0xff, 0xc1, 0x6e, 0x4c, 0x49, 0xb2, 0x68, + 0xa2, 0x0f, 0x8d, 0x96, 0xa6, 0x0b, 0x40, 0x58 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe8, 0x86, 0xf9, 0x28, 0x19, 0x99, 0xc5, 0xbb, + 0x3b, 0x3e, 0x88, 0x62, 0xe2, 0xf7, 0xc9, 0x88 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x56, 0x3b, 0xf9, 0x0d, 0x61, 0xbe, 0xef, 0x39, + 0xf4, 0x8d, 0xd6, 0x25, 0xfc, 0xef, 0x13, 0x61 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4d, 0x37, 0xc8, 0x50, 0x64, 0x45, 0x63, 0xc6, + 0x9f, 0xd0, 0xac, 0xd9, 0xa0, 0x49, 0x32, 0x5b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb8, 0x7c, 0x92, 0x1b, 0x91, 0x82, 0x9e, 0xf3, + 0xb1, 0x3c, 0xa5, 0x41, 0xee, 0x11, 0x30, 0xa6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x2e, 0x65, 0xeb, 0x6b, 0x6e, 0xa3, 0x83, 0xe1, + 0x09, 0xac, 0xcc, 0xe8, 0x32, 0x6b, 0x03, 0x93 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9c, 0xa5, 0x47, 0xf7, 0x43, 0x9e, 0xdc, 0x3e, + 0x25, 0x5c, 0x0f, 0x4d, 0x49, 0xaa, 0x89, 0x90 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa5, 0xe6, 0x52, 0x61, 0x4c, 0x93, 0x00, 0xf3, + 0x78, 0x16, 0xb1, 0xf9, 0xfd, 0x0c, 0x87, 0xf9 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x14, 0x95, 0x4f, 0x0b, 0x46, 0x97, 0x77, 0x6f, + 0x44, 0x49, 0x4f, 0xe4, 0x58, 0xd8, 0x14, 0xed + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7c, 0x8d, 0x9a, 0xb6, 0xc2, 0x76, 0x17, 0x23, + 0xfe, 0x42, 0xf8, 0xbb, 0x50, 0x6c, 0xbc, 0xf7 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdb, 0x7e, 0x19, 0x32, 0x67, 0x9f, 0xdd, 0x99, + 0x74, 0x2a, 0xab, 0x04, 0xaa, 0x0d, 0x5a, 0x80 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4c, 0x6a, 0x1c, 0x83, 0xe5, 0x68, 0xcd, 0x10, + 0xf2, 0x7c, 0x2d, 0x73, 0xde, 0xd1, 0x9c, 0x28 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 + }, { + 0x90, 0xec, 0xbe, 0x61, 0x77, 0xe6, 0x74, 0xc9, + 0x8d, 0xe4, 0x12, 0x41, 0x3f, 0x7a, 0xc9, 0x15 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x90, 0x68, 0x4a, 0x2a, 0xc5, 0x5f, 0xe1, 0xec, + 0x2b, 0x8e, 0xbd, 0x56, 0x22, 0x52, 0x0b, 0x73 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x74, 0x72, 0xf9, 0xa7, 0x98, 0x86, 0x07, 0xca, + 0x79, 0x70, 0x77, 0x95, 0x99, 0x10, 0x35, 0xe6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x56, 0xaf, 0xf0, 0x89, 0x87, 0x8b, 0xf3, 0x35, + 0x2f, 0x8d, 0xf1, 0x72, 0xa3, 0xae, 0x47, 0xd8 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 + }, { + 0x65, 0xc0, 0x52, 0x6c, 0xbe, 0x40, 0x16, 0x1b, + 0x80, 0x19, 0xa2, 0xa3, 0x17, 0x1a, 0xbd, 0x23 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 + }, { + 0x37, 0x7b, 0xe0, 0xbe, 0x33, 0xb4, 0xe3, 0xe3, + 0x10, 0xb4, 0xaa, 0xbd, 0xa1, 0x73, 0xf8, 0x4f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 + }, { + 0x94, 0x02, 0xe9, 0xaa, 0x6f, 0x69, 0xde, 0x65, + 0x04, 0xda, 0x8d, 0x20, 0xc4, 0xfc, 0xaa, 0x2f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + }, { + 0x12, 0x3c, 0x1f, 0x4a, 0xf3, 0x13, 0xad, 0x8c, + 0x2c, 0xe6, 0x48, 0xb2, 0xe7, 0x1f, 0xb6, 0xe1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 + }, { + 0x1f, 0xfc, 0x62, 0x6d, 0x30, 0x20, 0x3d, 0xcd, + 0xb0, 0x01, 0x9f, 0xb8, 0x0f, 0x72, 0x6c, 0xf4 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 + }, { + 0x76, 0xda, 0x1f, 0xbe, 0x3a, 0x50, 0x72, 0x8c, + 0x50, 0xfd, 0x2e, 0x62, 0x1b, 0x5a, 0xd8, 0x85 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 + }, { + 0x08, 0x2e, 0xb8, 0xbe, 0x35, 0xf4, 0x42, 0xfb, + 0x52, 0x66, 0x8e, 0x16, 0xa5, 0x91, 0xd1, 0xd6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 + }, { + 0xe6, 0x56, 0xf9, 0xec, 0xf5, 0xfe, 0x27, 0xec, + 0x3e, 0x4a, 0x73, 0xd0, 0x0c, 0x28, 0x2f, 0xb3 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 + }, { + 0x2c, 0xa8, 0x20, 0x9d, 0x63, 0x27, 0x4c, 0xd9, + 0xa2, 0x9b, 0xb7, 0x4b, 0xcd, 0x77, 0x68, 0x3a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 + }, { + 0x79, 0xbf, 0x5d, 0xce, 0x14, 0xbb, 0x7d, 0xd7, + 0x3a, 0x8e, 0x36, 0x11, 0xde, 0x7c, 0xe0, 0x26 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 + }, { + 0x3c, 0x84, 0x99, 0x39, 0xa5, 0xd2, 0x93, 0x99, + 0xf3, 0x44, 0xc4, 0xa0, 0xec, 0xa8, 0xa5, 0x76 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 + }, { + 0xed, 0x3c, 0x0a, 0x94, 0xd5, 0x9b, 0xec, 0xe9, + 0x88, 0x35, 0xda, 0x7a, 0xa4, 0xf0, 0x7c, 0xa2 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 + }, { + 0x63, 0x91, 0x9e, 0xd4, 0xce, 0x10, 0x19, 0x64, + 0x38, 0xb6, 0xad, 0x09, 0xd9, 0x9c, 0xd7, 0x95 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 + }, { + 0x76, 0x78, 0xf3, 0xa8, 0x33, 0xf1, 0x9f, 0xea, + 0x95, 0xf3, 0xc6, 0x02, 0x9e, 0x2b, 0xc6, 0x10 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 + }, { + 0x3a, 0xa4, 0x26, 0x83, 0x10, 0x67, 0xd3, 0x6b, + 0x92, 0xbe, 0x7c, 0x5f, 0x81, 0xc1, 0x3c, 0x56 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 + }, { + 0x92, 0x72, 0xe2, 0xd2, 0xcd, 0xd1, 0x10, 0x50, + 0x99, 0x8c, 0x84, 0x50, 0x77, 0xa3, 0x0e, 0xa0 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 + }, { + 0x08, 0x8c, 0x4b, 0x53, 0xf5, 0xec, 0x0f, 0xf8, + 0x14, 0xc1, 0x9a, 0xda, 0xe7, 0xf6, 0x24, 0x6c + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 + }, { + 0x40, 0x10, 0xa5, 0xe4, 0x01, 0xfd, 0xf0, 0xa0, + 0x35, 0x4d, 0xdb, 0xcc, 0x0d, 0x01, 0x2b, 0x17 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 + }, { + 0xa8, 0x7a, 0x38, 0x57, 0x36, 0xc0, 0xa6, 0x18, + 0x9b, 0xd6, 0x58, 0x9b, 0xd8, 0x44, 0x5a, 0x93 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 + }, { + 0x54, 0x5f, 0x2b, 0x83, 0xd9, 0x61, 0x6d, 0xcc, + 0xf6, 0x0f, 0xa9, 0x83, 0x0e, 0x9c, 0xd2, 0x87 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 + }, { + 0x4b, 0x70, 0x6f, 0x7f, 0x92, 0x40, 0x63, 0x52, + 0x39, 0x40, 0x37, 0xa6, 0xd4, 0xf4, 0x68, 0x8d + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 + }, { + 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 0x4b, 0x90, + 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 + }, { + 0x6f, 0x45, 0x73, 0x2c, 0xf1, 0x08, 0x81, 0x54, + 0x6f, 0x0f, 0xd2, 0x38, 0x96, 0xd2, 0xbb, 0x60 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 + }, { + 0x2e, 0x35, 0x79, 0xca, 0x15, 0xaf, 0x27, 0xf6, + 0x4b, 0x3c, 0x95, 0x5a, 0x5b, 0xfc, 0x30, 0xba + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 + }, { + 0x34, 0xa2, 0xc5, 0xa9, 0x1a, 0xe2, 0xae, 0xc9, + 0x9b, 0x7d, 0x1b, 0x5f, 0xa6, 0x78, 0x04, 0x47 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 + }, { + 0xa4, 0xd6, 0x61, 0x6b, 0xd0, 0x4f, 0x87, 0x33, + 0x5b, 0x0e, 0x53, 0x35, 0x12, 0x27, 0xa9, 0xee + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 + }, { + 0x7f, 0x69, 0x2b, 0x03, 0x94, 0x58, 0x67, 0xd1, + 0x61, 0x79, 0xa8, 0xce, 0xfc, 0x83, 0xea, 0x3f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 + }, { + 0x3b, 0xd1, 0x41, 0xee, 0x84, 0xa0, 0xe6, 0x41, + 0x4a, 0x26, 0xe7, 0xa4, 0xf2, 0x81, 0xf8, 0xa2 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 + }, { + 0xd1, 0x78, 0x8f, 0x57, 0x2d, 0x98, 0xb2, 0xb1, + 0x6e, 0xc5, 0xd5, 0xf3, 0x92, 0x2b, 0x99, 0xbc + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 + }, { + 0x08, 0x33, 0xff, 0x6f, 0x61, 0xd9, 0x8a, 0x57, + 0xb2, 0x88, 0xe8, 0xc3, 0x58, 0x6b, 0x85, 0xa6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 + }, { + 0x85, 0x68, 0x26, 0x17, 0x97, 0xde, 0x17, 0x6b, + 0xf0, 0xb4, 0x3b, 0xec, 0xc6, 0x28, 0x5a, 0xfb + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 + }, { + 0xf9, 0xb0, 0xfd, 0xa0, 0xc4, 0xa8, 0x98, 0xf5, + 0xb9, 0xe6, 0xf6, 0x61, 0xc4, 0xce, 0x4d, 0x07 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 + }, { + 0x8a, 0xde, 0x89, 0x59, 0x13, 0x68, 0x5c, 0x67, + 0xc5, 0x26, 0x9f, 0x8a, 0xae, 0x42, 0x98, 0x3e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc + }, { + 0x39, 0xbd, 0xe6, 0x7d, 0x5c, 0x8e, 0xd8, 0xa8, + 0xb1, 0xc3, 0x7e, 0xb8, 0xfa, 0x9f, 0x5a, 0xc0 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe + }, { + 0x5c, 0x00, 0x5e, 0x72, 0xc1, 0x41, 0x8c, 0x44, + 0xf5, 0x69, 0xf2, 0xea, 0x33, 0xba, 0x54, 0xf3 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }, { + 0x3f, 0x5b, 0x8c, 0xc9, 0xea, 0x85, 0x5a, 0x0a, + 0xfa, 0x73, 0x47, 0xd2, 0x3e, 0x8d, 0x66, 0x4e + } } + }; + struct tc_aes_key_sched_struct s; + unsigned int i; + + TC_PRINT("AES128 %s (NIST fixed-key and variable-text):\n", __func__); + + (void)tc_aes128_set_encrypt_key(&s, key); + + for (i = 0; i < 128; ++i) { + result = var_text_test(i, kat_tbl[i].in, kat_tbl[i].out, &s); + if (result == TC_FAIL) { + break; + } + } + + TC_END_RESULT(result); + + return result; +} + +int var_key_test(unsigned int r, const uint8_t *in, const uint8_t *out) +{ + int result = TC_PASS; + + const uint8_t plaintext[NUM_OF_NIST_KEYS] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + uint8_t ciphertext[NUM_OF_NIST_KEYS]; + struct tc_aes_key_sched_struct s; + + (void)tc_aes128_set_encrypt_key(&s, in); + + (void)tc_aes_encrypt(ciphertext, plaintext, &s); + result = check_result(r, out, NUM_OF_NIST_KEYS, ciphertext, + sizeof(ciphertext)); + + return result; +} + +/* + * All NIST tests with variable key and fixed text. + */ +int test_4(void) +{ + int result = TC_PASS; + const struct kat_table kat_tbl[NUM_OF_FIXED_KEYS] = { + {{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x0e, 0xdd, 0x33, 0xd3, 0xc6, 0x21, 0xe5, 0x46, + 0x45, 0x5b, 0xd8, 0xba, 0x14, 0x18, 0xbe, 0xc8 + } }, + {{ + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4b, 0xc3, 0xf8, 0x83, 0x45, 0x0c, 0x11, 0x3c, + 0x64, 0xca, 0x42, 0xe1, 0x11, 0x2a, 0x9e, 0x87 + } }, + {{ + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x72, 0xa1, 0xda, 0x77, 0x0f, 0x5d, 0x7a, 0xc4, + 0xc9, 0xef, 0x94, 0xd8, 0x22, 0xaf, 0xfd, 0x97 + } }, + {{ + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x97, 0x00, 0x14, 0xd6, 0x34, 0xe2, 0xb7, 0x65, + 0x07, 0x77, 0xe8, 0xe8, 0x4d, 0x03, 0xcc, 0xd8 + } }, + {{ + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf1, 0x7e, 0x79, 0xae, 0xd0, 0xdb, 0x7e, 0x27, + 0x9e, 0x95, 0x5b, 0x5f, 0x49, 0x38, 0x75, 0xa7 + } }, + {{ + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9e, 0xd5, 0xa7, 0x51, 0x36, 0xa9, 0x40, 0xd0, + 0x96, 0x3d, 0xa3, 0x79, 0xdb, 0x4a, 0xf2, 0x6a + } }, + {{ + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc4, 0x29, 0x5f, 0x83, 0x46, 0x5c, 0x77, 0x55, + 0xe8, 0xfa, 0x36, 0x4b, 0xac, 0x6a, 0x7e, 0xa5 + } }, + {{ + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb1, 0xd7, 0x58, 0x25, 0x6b, 0x28, 0xfd, 0x85, + 0x0a, 0xd4, 0x94, 0x42, 0x08, 0xcf, 0x11, 0x55 + } }, + {{ + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x42, 0xff, 0xb3, 0x4c, 0x74, 0x3d, 0xe4, 0xd8, + 0x8c, 0xa3, 0x80, 0x11, 0xc9, 0x90, 0x89, 0x0b + } }, + {{ + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x99, 0x58, 0xf0, 0xec, 0xea, 0x8b, 0x21, 0x72, + 0xc0, 0xc1, 0x99, 0x5f, 0x91, 0x82, 0xc0, 0xf3 + } }, + {{ + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x95, 0x6d, 0x77, 0x98, 0xfa, 0xc2, 0x0f, 0x82, + 0xa8, 0x82, 0x3f, 0x98, 0x4d, 0x06, 0xf7, 0xf5 + } }, + {{ + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa0, 0x1b, 0xf4, 0x4f, 0x2d, 0x16, 0xbe, 0x92, + 0x8c, 0xa4, 0x4a, 0xaf, 0x7b, 0x9b, 0x10, 0x6b + } }, + {{ + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb5, 0xf1, 0xa3, 0x3e, 0x50, 0xd4, 0x0d, 0x10, + 0x37, 0x64, 0xc7, 0x6b, 0xd4, 0xc6, 0xb6, 0xf8 + } }, + {{ + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x26, 0x37, 0x05, 0x0c, 0x9f, 0xc0, 0xd4, 0x81, + 0x7e, 0x2d, 0x69, 0xde, 0x87, 0x8a, 0xee, 0x8d + } }, + {{ + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x11, 0x3e, 0xcb, 0xe4, 0xa4, 0x53, 0x26, 0x9a, + 0x0d, 0xd2, 0x60, 0x69, 0x46, 0x7f, 0xb5, 0xb5 + } }, + {{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x97, 0xd0, 0x75, 0x4f, 0xe6, 0x8f, 0x11, 0xb9, + 0xe3, 0x75, 0xd0, 0x70, 0xa6, 0x08, 0xc8, 0x84 + } }, + {{ + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc6, 0xa0, 0xb3, 0xe9, 0x98, 0xd0, 0x50, 0x68, + 0xa5, 0x39, 0x97, 0x78, 0x40, 0x52, 0x00, 0xb4 + } }, + {{ + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 0xb8, 0x7b, + 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 + } }, + {{ + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x90, 0xfb, 0x12, 0x8d, 0x3a, 0x1a, 0xf6, 0xe5, + 0x48, 0x52, 0x1b, 0xb9, 0x62, 0xbf, 0x1f, 0x05 + } }, + {{ + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x26, 0x29, 0x8e, 0x9c, 0x1d, 0xb5, 0x17, 0xc2, + 0x15, 0xfa, 0xdf, 0xb7, 0xd2, 0xa8, 0xd6, 0x91 + } }, + {{ + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa6, 0xcb, 0x76, 0x1d, 0x61, 0xf8, 0x29, 0x2d, + 0x0d, 0xf3, 0x93, 0xa2, 0x79, 0xad, 0x03, 0x80 + } }, + {{ + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x12, 0xac, 0xd8, 0x9b, 0x13, 0xcd, 0x5f, 0x87, + 0x26, 0xe3, 0x4d, 0x44, 0xfd, 0x48, 0x61, 0x08 + } }, + {{ + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x95, 0xb1, 0x70, 0x3f, 0xc5, 0x7b, 0xa0, 0x9f, + 0xe0, 0xc3, 0x58, 0x0f, 0xeb, 0xdd, 0x7e, 0xd4 + } }, + {{ + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xde, 0x11, 0x72, 0x2d, 0x89, 0x3e, 0x9f, 0x91, + 0x21, 0xc3, 0x81, 0xbe, 0xcc, 0x1d, 0xa5, 0x9a + } }, + {{ + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6d, 0x11, 0x4c, 0xcb, 0x27, 0xbf, 0x39, 0x10, + 0x12, 0xe8, 0x97, 0x4c, 0x54, 0x6d, 0x9b, 0xf2 + } }, + {{ + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x5c, 0xe3, 0x7e, 0x17, 0xeb, 0x46, 0x46, 0xec, + 0xfa, 0xc2, 0x9b, 0x9c, 0xc3, 0x8d, 0x93, 0x40 + } }, + {{ + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x18, 0xc1, 0xb6, 0xe2, 0x15, 0x71, 0x22, 0x05, + 0x6d, 0x02, 0x43, 0xd8, 0xa1, 0x65, 0xcd, 0xdb + } }, + {{ + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x99, 0x69, 0x3e, 0x6a, 0x59, 0xd1, 0x36, 0x6c, + 0x74, 0xd8, 0x23, 0x56, 0x2d, 0x7e, 0x14, 0x31 + } }, + {{ + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6c, 0x7c, 0x64, 0xdc, 0x84, 0xa8, 0xbb, 0xa7, + 0x58, 0xed, 0x17, 0xeb, 0x02, 0x5a, 0x57, 0xe3 + } }, + {{ + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe1, 0x7b, 0xc7, 0x9f, 0x30, 0xea, 0xab, 0x2f, + 0xac, 0x2c, 0xbb, 0xe3, 0x45, 0x8d, 0x68, 0x7a + } }, + {{ + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x11, 0x14, 0xbc, 0x20, 0x28, 0x00, 0x9b, 0x92, + 0x3f, 0x0b, 0x01, 0x91, 0x5c, 0xe5, 0xe7, 0xc4 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9c, 0x28, 0x52, 0x4a, 0x16, 0xa1, 0xe1, 0xc1, + 0x45, 0x29, 0x71, 0xca, 0xa8, 0xd1, 0x34, 0x76 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xed, 0x62, 0xe1, 0x63, 0x63, 0x63, 0x83, 0x60, + 0xfd, 0xd6, 0xad, 0x62, 0x11, 0x27, 0x94, 0xf0 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x5a, 0x86, 0x88, 0xf0, 0xb2, 0xa2, 0xc1, 0x62, + 0x24, 0xc1, 0x61, 0x65, 0x8f, 0xfd, 0x40, 0x44 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x23, 0xf7, 0x10, 0x84, 0x2b, 0x9b, 0xb9, 0xc3, + 0x2f, 0x26, 0x64, 0x8c, 0x78, 0x68, 0x07, 0xca + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x44, 0xa9, 0x8b, 0xf1, 0x1e, 0x16, 0x3f, 0x63, + 0x2c, 0x47, 0xec, 0x6a, 0x49, 0x68, 0x3a, 0x89 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x0f, 0x18, 0xaf, 0xf9, 0x42, 0x74, 0x69, 0x6d, + 0x9b, 0x61, 0x84, 0x8b, 0xd5, 0x0a, 0xc5, 0xe5 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x82, 0x40, 0x85, 0x71, 0xc3, 0xe2, 0x42, 0x45, + 0x40, 0x20, 0x7f, 0x83, 0x3b, 0x6d, 0xda, 0x69 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x30, 0x3f, 0xf9, 0x96, 0x94, 0x7f, 0x0c, 0x7d, + 0x1f, 0x43, 0xc8, 0xf3, 0x02, 0x7b, 0x9b, 0x75 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7d, 0xf4, 0xda, 0xf4, 0xad, 0x29, 0xa3, 0x61, + 0x5a, 0x9b, 0x6e, 0xce, 0x5c, 0x99, 0x51, 0x8a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc7, 0x29, 0x54, 0xa4, 0x8d, 0x07, 0x74, 0xdb, + 0x0b, 0x49, 0x71, 0xc5, 0x26, 0x26, 0x04, 0x15 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1d, 0xf9, 0xb7, 0x61, 0x12, 0xdc, 0x65, 0x31, + 0xe0, 0x7d, 0x2c, 0xfd, 0xa0, 0x44, 0x11, 0xf0 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0x4d, 0x8e, 0x69, 0x91, 0x19, 0xe1, 0xfc, + 0x87, 0x54, 0x5a, 0x64, 0x7f, 0xb1, 0xd3, 0x4f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xe6, 0xc4, 0x80, 0x7a, 0xe1, 0x1f, 0x36, 0xf0, + 0x91, 0xc5, 0x7d, 0x9f, 0xb6, 0x85, 0x48, 0xd1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8e, 0xbf, 0x73, 0xaa, 0xd4, 0x9c, 0x82, 0x00, + 0x7f, 0x77, 0xa5, 0xc1, 0xcc, 0xec, 0x6a, 0xb4 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x4f, 0xb2, 0x88, 0xcc, 0x20, 0x40, 0x04, 0x90, + 0x01, 0xd2, 0xc7, 0x58, 0x5a, 0xd1, 0x23, 0xfc + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x04, 0x49, 0x71, 0x10, 0xef, 0xb9, 0xdc, 0xeb, + 0x13, 0xe2, 0xb1, 0x3f, 0xb4, 0x46, 0x55, 0x64 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x75, 0x55, 0x0e, 0x6c, 0xb5, 0xa8, 0x8e, 0x49, + 0x63, 0x4c, 0x9a, 0xb6, 0x9e, 0xda, 0x04, 0x30 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb6, 0x76, 0x84, 0x73, 0xce, 0x98, 0x43, 0xea, + 0x66, 0xa8, 0x14, 0x05, 0xdd, 0x50, 0xb3, 0x45 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xcb, 0x2f, 0x43, 0x03, 0x83, 0xf9, 0x08, 0x4e, + 0x03, 0xa6, 0x53, 0x57, 0x1e, 0x06, 0x5d, 0xe6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xff, 0x4e, 0x66, 0xc0, 0x7b, 0xae, 0x3e, 0x79, + 0xfb, 0x7d, 0x21, 0x08, 0x47, 0xa3, 0xb0, 0xba + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7b, 0x90, 0x78, 0x51, 0x25, 0x50, 0x5f, 0xad, + 0x59, 0xb1, 0x3c, 0x18, 0x6d, 0xd6, 0x6c, 0xe3 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x8b, 0x52, 0x7a, 0x6a, 0xeb, 0xda, 0xec, 0x9e, + 0xae, 0xf8, 0xed, 0xa2, 0xcb, 0x77, 0x83, 0xe5 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x43, 0xfd, 0xaf, 0x53, 0xeb, 0xbc, 0x98, 0x80, + 0xc2, 0x28, 0x61, 0x7d, 0x6a, 0x9b, 0x54, 0x8b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x53, 0x78, 0x61, 0x04, 0xb9, 0x74, 0x4b, 0x98, + 0xf0, 0x52, 0xc4, 0x6f, 0x1c, 0x85, 0x0d, 0x0b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xb5, 0xab, 0x30, 0x13, 0xdd, 0x1e, 0x61, 0xdf, + 0x06, 0xcb, 0xaf, 0x34, 0xca, 0x2a, 0xee, 0x78 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x74, 0x70, 0x46, 0x9b, 0xe9, 0x72, 0x30, 0x30, + 0xfd, 0xcc, 0x73, 0xa8, 0xcd, 0x4f, 0xbb, 0x10 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xa3, 0x5a, 0x63, 0xf5, 0x34, 0x3e, 0xbe, 0x9e, + 0xf8, 0x16, 0x7b, 0xcb, 0x48, 0xad, 0x12, 0x2e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xfd, 0x86, 0x87, 0xf0, 0x75, 0x7a, 0x21, 0x0e, + 0x9f, 0xdf, 0x18, 0x12, 0x04, 0xc3, 0x08, 0x63 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x7a, 0x18, 0x1e, 0x84, 0xbd, 0x54, 0x57, 0xd2, + 0x6a, 0x88, 0xfb, 0xae, 0x96, 0x01, 0x8f, 0xb0 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x65, 0x33, 0x17, 0xb9, 0x36, 0x2b, 0x6f, 0x9b, + 0x9e, 0x1a, 0x58, 0x0e, 0x68, 0xd4, 0x94, 0xb5 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x99, 0x5c, 0x9d, 0xc0, 0xb6, 0x89, 0xf0, 0x3c, + 0x45, 0x86, 0x7b, 0x5f, 0xaa, 0x5c, 0x18, 0xd1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x77, 0xa4, 0xd9, 0x6d, 0x56, 0xdd, 0xa3, 0x98, + 0xb9, 0xaa, 0xbe, 0xcf, 0xc7, 0x57, 0x29, 0xfd + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x84, 0xbe, 0x19, 0xe0, 0x53, 0x63, 0x5f, 0x09, + 0xf2, 0x66, 0x5e, 0x7b, 0xae, 0x85, 0xb4, 0x2d + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x32, 0xcd, 0x65, 0x28, 0x42, 0x92, 0x6a, 0xea, + 0x4a, 0xa6, 0x13, 0x7b, 0xb2, 0xbe, 0x2b, 0x5e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x49, 0x3d, 0x4a, 0x4f, 0x38, 0xeb, 0xb3, 0x37, + 0xd1, 0x0a, 0xa8, 0x4e, 0x91, 0x71, 0xa5, 0x54 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd9, 0xbf, 0xf7, 0xff, 0x45, 0x4b, 0x0e, 0xc5, + 0xa4, 0xa2, 0xa6, 0x95, 0x66, 0xe2, 0xcb, 0x84 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x35, 0x35, 0xd5, 0x65, 0xac, 0xe3, 0xf3, 0x1e, + 0xb2, 0x49, 0xba, 0x2c, 0xc6, 0x76, 0x5d, 0x7a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf6, 0x0e, 0x91, 0xfc, 0x32, 0x69, 0xee, 0xcf, + 0x32, 0x31, 0xc6, 0xe9, 0x94, 0x56, 0x97, 0xc6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xab, 0x69, 0xcf, 0xad, 0xf5, 0x1f, 0x8e, 0x60, + 0x4d, 0x9c, 0xc3, 0x71, 0x82, 0xf6, 0x63, 0x5a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x78, 0x66, 0x37, 0x3f, 0x24, 0xa0, 0xb6, 0xed, + 0x56, 0xe0, 0xd9, 0x6f, 0xcd, 0xaf, 0xb8, 0x77 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1e, 0xa4, 0x48, 0xc2, 0xaa, 0xc9, 0x54, 0xf5, + 0xd8, 0x12, 0xe9, 0xd7, 0x84, 0x94, 0x44, 0x6a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xac, 0xc5, 0x59, 0x9d, 0xd8, 0xac, 0x02, 0x23, + 0x9a, 0x0f, 0xef, 0x4a, 0x36, 0xdd, 0x16, 0x68 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd8, 0x76, 0x44, 0x68, 0xbb, 0x10, 0x38, 0x28, + 0xcf, 0x7e, 0x14, 0x73, 0xce, 0x89, 0x50, 0x73 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x1b, 0x0d, 0x02, 0x89, 0x36, 0x83, 0xb9, 0xf1, + 0x80, 0x45, 0x8e, 0x4a, 0xa6, 0xb7, 0x39, 0x82 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x96, 0xd9, 0xb0, 0x17, 0xd3, 0x02, 0xdf, 0x41, + 0x0a, 0x93, 0x7d, 0xcd, 0xb8, 0xbb, 0x6e, 0x43 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xef, 0x16, 0x23, 0xcc, 0x44, 0x31, 0x3c, 0xff, + 0x44, 0x0b, 0x15, 0x94, 0xa7, 0xe2, 0x1c, 0xc6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x28, 0x4c, 0xa2, 0xfa, 0x35, 0x80, 0x7b, 0x8b, + 0x0a, 0xe4, 0xd1, 0x9e, 0x11, 0xd7, 0xdb, 0xd7 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf2, 0xe9, 0x76, 0x87, 0x57, 0x55, 0xf9, 0x40, + 0x1d, 0x54, 0xf3, 0x6e, 0x2a, 0x23, 0xa5, 0x94 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xec, 0x19, 0x8a, 0x18, 0xe1, 0x0e, 0x53, 0x24, + 0x03, 0xb7, 0xe2, 0x08, 0x87, 0xc8, 0xdd, 0x80 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x54, 0x5d, 0x50, 0xeb, 0xd9, 0x19, 0xe4, 0xa6, + 0x94, 0x9d, 0x96, 0xad, 0x47, 0xe4, 0x6a, 0x80 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xdb, 0xdf, 0xb5, 0x27, 0x06, 0x0e, 0x0a, 0x71, + 0x00, 0x9c, 0x7b, 0xb0, 0xc6, 0x8f, 0x1d, 0x44 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x9c, 0xfa, 0x13, 0x22, 0xea, 0x33, 0xda, 0x21, + 0x73, 0xa0, 0x24, 0xf2, 0xff, 0x0d, 0x89, 0x6d + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x87, 0x85, 0xb1, 0xa7, 0x5b, 0x0f, 0x3b, 0xd9, + 0x58, 0xdc, 0xd0, 0xe2, 0x93, 0x18, 0xc5, 0x21 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x38, 0xf6, 0x7b, 0x9e, 0x98, 0xe4, 0xa9, 0x7b, + 0x6d, 0xf0, 0x30, 0xa9, 0xfc, 0xdd, 0x01, 0x04 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x19, 0x2a, 0xff, 0xfb, 0x2c, 0x88, 0x0e, 0x82, + 0xb0, 0x59, 0x26, 0xd0, 0xfc, 0x6c, 0x44, 0x8b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6a, 0x79, 0x80, 0xce, 0x7b, 0x10, 0x5c, 0xf5, + 0x30, 0x95, 0x2d, 0x74, 0xda, 0xaf, 0x79, 0x8c + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 + }, { + 0xea, 0x36, 0x95, 0xe1, 0x35, 0x1b, 0x9d, 0x68, + 0x58, 0xbd, 0x95, 0x8c, 0xf5, 0x13, 0xef, 0x6c + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 + }, { + 0x6d, 0xa0, 0x49, 0x0b, 0xa0, 0xba, 0x03, 0x43, + 0xb9, 0x35, 0x68, 0x1d, 0x2c, 0xce, 0x5b, 0xa1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf0, 0xea, 0x23, 0xaf, 0x08, 0x53, 0x40, 0x11, + 0xc6, 0x00, 0x09, 0xab, 0x29, 0xad, 0xa2, 0xf1 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 + }, { + 0xff, 0x13, 0x80, 0x6c, 0xf1, 0x9c, 0xc3, 0x87, + 0x21, 0x55, 0x4d, 0x7c, 0x0f, 0xcd, 0xcd, 0x4b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 + }, { + 0x68, 0x38, 0xaf, 0x1f, 0x4f, 0x69, 0xba, 0xe9, + 0xd8, 0x5d, 0xd1, 0x88, 0xdc, 0xdf, 0x06, 0x88 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 + }, { + 0x36, 0xcf, 0x44, 0xc9, 0x2d, 0x55, 0x0b, 0xfb, + 0x1e, 0xd2, 0x8e, 0xf5, 0x83, 0xdd, 0xf5, 0xd7 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 + }, { + 0xd0, 0x6e, 0x31, 0x95, 0xb5, 0x37, 0x6f, 0x10, + 0x9d, 0x5c, 0x4e, 0xc6, 0xc5, 0xd6, 0x2c, 0xed + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 + }, { + 0xc4, 0x40, 0xde, 0x01, 0x4d, 0x3d, 0x61, 0x07, + 0x07, 0x27, 0x9b, 0x13, 0x24, 0x2a, 0x5c, 0x36 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + }, { + 0xf0, 0xc5, 0xc6, 0xff, 0xa5, 0xe0, 0xbd, 0x3a, + 0x94, 0xc8, 0x8f, 0x6b, 0x6f, 0x7c, 0x16, 0xb9 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 + }, { + 0x3e, 0x40, 0xc3, 0x90, 0x1c, 0xd7, 0xef, 0xfc, + 0x22, 0xbf, 0xfc, 0x35, 0xde, 0xe0, 0xb4, 0xd9 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 + }, { + 0xb6, 0x33, 0x05, 0xc7, 0x2b, 0xed, 0xfa, 0xb9, + 0x73, 0x82, 0xc4, 0x06, 0xd0, 0xc4, 0x9b, 0xc6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 + }, { + 0x36, 0xbb, 0xaa, 0xb2, 0x2a, 0x6b, 0xd4, 0x92, + 0x5a, 0x99, 0xa2, 0xb4, 0x08, 0xd2, 0xdb, 0xae + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 + }, { + 0x30, 0x7c, 0x5b, 0x8f, 0xcd, 0x05, 0x33, 0xab, + 0x98, 0xbc, 0x51, 0xe2, 0x7a, 0x6c, 0xe4, 0x61 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 + }, { + 0x82, 0x9c, 0x04, 0xff, 0x4c, 0x07, 0x51, 0x3c, + 0x0b, 0x3e, 0xf0, 0x5c, 0x03, 0xe3, 0x37, 0xb5 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 + }, { + 0xf1, 0x7a, 0xf0, 0xe8, 0x95, 0xdd, 0xa5, 0xeb, + 0x98, 0xef, 0xc6, 0x80, 0x66, 0xe8, 0x4c, 0x54 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 + }, { + 0x27, 0x71, 0x67, 0xf3, 0x81, 0x2a, 0xff, 0xf1, + 0xff, 0xac, 0xb4, 0xa9, 0x34, 0x37, 0x9f, 0xc3 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 + }, { + 0x2c, 0xb1, 0xdc, 0x3a, 0x9c, 0x72, 0x97, 0x2e, + 0x42, 0x5a, 0xe2, 0xef, 0x3e, 0xb5, 0x97, 0xcd + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 + }, { + 0x36, 0xae, 0xaa, 0x3a, 0x21, 0x3e, 0x96, 0x8d, + 0x4b, 0x5b, 0x67, 0x9d, 0x3a, 0x2c, 0x97, 0xfe + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 + }, { + 0x92, 0x41, 0xda, 0xca, 0x4f, 0xdd, 0x03, 0x4a, + 0x82, 0x37, 0x2d, 0xb5, 0x0e, 0x1a, 0x0f, 0x3f + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 + }, { + 0xc1, 0x45, 0x74, 0xd9, 0xcd, 0x00, 0xcf, 0x2b, + 0x5a, 0x7f, 0x77, 0xe5, 0x3c, 0xd5, 0x78, 0x85 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 + }, { + 0x79, 0x3d, 0xe3, 0x92, 0x36, 0x57, 0x0a, 0xba, + 0x83, 0xab, 0x9b, 0x73, 0x7c, 0xb5, 0x21, 0xc9 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 + }, { + 0x16, 0x59, 0x1c, 0x0f, 0x27, 0xd6, 0x0e, 0x29, + 0xb8, 0x5a, 0x96, 0xc3, 0x38, 0x61, 0xa7, 0xef + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 + }, { + 0x44, 0xfb, 0x5c, 0x4d, 0x4f, 0x5c, 0xb7, 0x9b, + 0xe5, 0xc1, 0x74, 0xa3, 0xb1, 0xc9, 0x73, 0x48 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 + }, { + 0x67, 0x4d, 0x2b, 0x61, 0x63, 0x3d, 0x16, 0x2b, + 0xe5, 0x9d, 0xde, 0x04, 0x22, 0x2f, 0x47, 0x40 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 + }, { + 0xb4, 0x75, 0x0f, 0xf2, 0x63, 0xa6, 0x5e, 0x1f, + 0x9e, 0x92, 0x4c, 0xcf, 0xd9, 0x8f, 0x3e, 0x37 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 + }, { + 0x62, 0xd0, 0x66, 0x2d, 0x6e, 0xae, 0xdd, 0xed, + 0xeb, 0xae, 0x7f, 0x7e, 0xa3, 0xa4, 0xf6, 0xb6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 + }, { + 0x70, 0xc4, 0x6b, 0xb3, 0x06, 0x92, 0xbe, 0x65, + 0x7f, 0x7e, 0xaa, 0x93, 0xeb, 0xad, 0x98, 0x97 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 + }, { + 0x32, 0x39, 0x94, 0xcf, 0xb9, 0xda, 0x28, 0x5a, + 0x5d, 0x96, 0x42, 0xe1, 0x75, 0x9b, 0x22, 0x4a + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 + }, { + 0x1d, 0xbf, 0x57, 0x87, 0x7b, 0x7b, 0x17, 0x38, + 0x5c, 0x85, 0xd0, 0xb5, 0x48, 0x51, 0xe3, 0x71 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 + }, { + 0xdf, 0xa5, 0xc0, 0x97, 0xcd, 0xc1, 0x53, 0x2a, + 0xc0, 0x71, 0xd5, 0x7b, 0x1d, 0x28, 0xd1, 0xbd + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 + }, { + 0x3a, 0x0c, 0x53, 0xfa, 0x37, 0x31, 0x1f, 0xc1, + 0x0b, 0xd2, 0xa9, 0x98, 0x1f, 0x51, 0x31, 0x74 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 + }, { + 0xba, 0x4f, 0x97, 0x0c, 0x0a, 0x25, 0xc4, 0x18, + 0x14, 0xbd, 0xae, 0x2e, 0x50, 0x6b, 0xe3, 0xb4 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 + }, { + 0x2d, 0xce, 0x3a, 0xcb, 0x72, 0x7c, 0xd1, 0x3c, + 0xcd, 0x76, 0xd4, 0x25, 0xea, 0x56, 0xe4, 0xf6 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 + }, { + 0x51, 0x60, 0x47, 0x4d, 0x50, 0x4b, 0x9b, 0x3e, + 0xef, 0xb6, 0x8d, 0x35, 0xf2, 0x45, 0xf4, 0xb3 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 + }, { + 0x41, 0xa8, 0xa9, 0x47, 0x76, 0x66, 0x35, 0xde, + 0xc3, 0x75, 0x53, 0xd9, 0xa6, 0xc0, 0xcb, 0xb7 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 + }, { + 0x25, 0xd6, 0xcf, 0xe6, 0x88, 0x1f, 0x2b, 0xf4, + 0x97, 0xdd, 0x14, 0xcd, 0x4d, 0xdf, 0x44, 0x5b + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 + }, { + 0x41, 0xc7, 0x8c, 0x13, 0x5e, 0xd9, 0xe9, 0x8c, + 0x09, 0x66, 0x40, 0x64, 0x72, 0x65, 0xda, 0x1e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 + }, { + 0x5a, 0x4d, 0x40, 0x4d, 0x89, 0x17, 0xe3, 0x53, + 0xe9, 0x2a, 0x21, 0x07, 0x2c, 0x3b, 0x23, 0x05 + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc + }, { + 0x02, 0xbc, 0x96, 0x84, 0x6b, 0x3f, 0xdc, 0x71, + 0x64, 0x3f, 0x38, 0x4c, 0xd3, 0xcc, 0x3e, 0xaf + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe + }, { + 0x9b, 0xa4, 0xa9, 0x14, 0x3f, 0x4e, 0x5d, 0x40, + 0x48, 0x52, 0x1c, 0x4f, 0x88, 0x77, 0xd8, 0x8e + } }, + {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }, { + 0xa1, 0xf6, 0x25, 0x8c, 0x87, 0x7d, 0x5f, 0xcd, + 0x89, 0x64, 0x48, 0x45, 0x38, 0xbf, 0xc9, 0x2c + } } + }; + unsigned int i; + + TC_PRINT("AES128 test #4 (NIST variable-key and fixed-text):\n"); + + for (i = 0; i < NUM_OF_FIXED_KEYS; ++i) { + result = var_key_test(i, kat_tbl[i].in, kat_tbl[i].out); + if (result == TC_FAIL) { + break; + } + + } + + TC_END_RESULT(result); + + return result; +} + +/* + * Main task to test AES + */ +int main(void) +{ + int result = TC_PASS; + + TC_START("Performing AES128 tests:"); + + result = test_1(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("AES128 test #1 (NIST key schedule test) failed.\n"); + goto exitTest; + } + result = test_2(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("AES128 test #2 (NIST encryption test) failed.\n"); + goto exitTest; + } + result = test_3(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("AES128 test #3 (NIST fixed-key and variable-text) " + "failed.\n"); + goto exitTest; + } + result = test_4(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("AES128 test #4 (NIST variable-key and fixed-text) " + "failed.\n"); + goto exitTest; + } + + TC_PRINT("All AES128 tests succeeded!\n"); + + exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + + return result; +} diff --git a/tinycrypt/tests/test_cbc_mode.c b/tinycrypt/tests/test_cbc_mode.c new file mode 100644 index 00000000..2e9f3254 --- /dev/null +++ b/tinycrypt/tests/test_cbc_mode.c @@ -0,0 +1,176 @@ +/* test_cbc_mode.c - TinyCrypt implementation of some AES-CBC tests */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +/* + * DESCRIPTION + * This module tests the following AES-CBC Mode routines: + * + * Scenarios tested include: + * - AES128 CBC mode encryption SP 800-38a tests + */ + +#include +#include +#include + +#include +#include +#include + +/* + * NIST test vectors from SP 800-38a: + * + * Block #1 + * Plaintext 6bc1bee22e409f96e93d7e117393172a + * Input Block 6bc0bce12a459991e134741a7f9e1925 + * Output Block 7649abac8119b246cee98e9b12e9197d + * Ciphertext 7649abac8119b246cee98e9b12e9197d + * Block #2 + * Plaintext ae2d8a571e03ac9c9eb76fac45af8e51 + * Input Block d86421fb9f1a1eda505ee1375746972c + * Output Block 5086cb9b507219ee95db113a917678b2 + * Ciphertext 5086cb9b507219ee95db113a917678b2 + * Block #3 + * Plaintext 30c81c46a35ce411e5fbc1191a0a52ef + * Input Block 604ed7ddf32efdff7020d0238b7c2a5d + * Output Block 73bed6b8e3c1743b7116e69e22229516 + * Ciphertext 73bed6b8e3c1743b7116e69e22229516 + * Block #4 + * Plaintext f69f2445df4f9b17ad2b417be66c3710 + * Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206 + * Output Block 3ff1caa1681fac09120eca307586e1a7 + * Ciphertext 3ff1caa1681fac09120eca307586e1a7 + */ +const uint8_t key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, + 0x09, 0xcf, 0x4f, 0x3c +}; + +const uint8_t iv[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f +}; + +const uint8_t plaintext[64] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, + 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, + 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, + 0xe6, 0x6c, 0x37, 0x10 +}; + +const uint8_t ciphertext[80] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, + 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 0x50, 0x86, 0xcb, 0x9b, + 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, + 0x22, 0x22, 0x95, 0x16, 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, + 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 +}; + +/* + * NIST SP 800-38a CBC Test for encryption and decryption. + */ +int test_1_and_2(void) +{ + struct tc_aes_key_sched_struct a; + uint8_t iv_buffer[16]; + uint8_t encrypted[80]; + uint8_t decrypted[64]; + uint8_t *p; + unsigned int length; + int result = TC_PASS; + + (void)tc_aes128_set_encrypt_key(&a, key); + + (void)memcpy(iv_buffer, iv, TC_AES_BLOCK_SIZE); + + TC_PRINT("CBC test #1 (encryption SP 800-38a tests):\n"); + if (tc_cbc_mode_encrypt(encrypted, sizeof(plaintext) + TC_AES_BLOCK_SIZE, + plaintext, sizeof(plaintext), iv_buffer, &a) == 0) { + TC_ERROR("CBC test #1 (encryption SP 800-38a tests) failed in " + "%s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(1, ciphertext, sizeof(encrypted), encrypted, + sizeof(encrypted)); + TC_END_RESULT(result); + + TC_PRINT("CBC test #2 (decryption SP 800-38a tests):\n"); + (void)tc_aes128_set_decrypt_key(&a, key); + + p = &encrypted[TC_AES_BLOCK_SIZE]; + length = ((unsigned int) sizeof(encrypted)); + + if (tc_cbc_mode_decrypt(decrypted, length, p, length, encrypted, &a) == 0) { + TC_ERROR("CBC test #2 (decryption SP 800-38a tests) failed in. " + "%s\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(2, plaintext, sizeof(decrypted), decrypted, + sizeof(decrypted)); + +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + * Main task to test AES + */ +int main(void) +{ + int result = TC_PASS; + + TC_START("Performing AES128 tests:"); + + TC_PRINT("Performing CBC tests:\n"); + result = test_1_and_2(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("CBC test #1 failed.\n"); + goto exitTest; + } + + TC_PRINT("All CBC tests succeeded!\n"); + +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + + return result; +} diff --git a/tinycrypt/tests/test_ccm_mode.c b/tinycrypt/tests/test_ccm_mode.c new file mode 100644 index 00000000..878edb3d --- /dev/null +++ b/tinycrypt/tests/test_ccm_mode.c @@ -0,0 +1,545 @@ +/* test_ccm_mode.c - TinyCrypt AES-CCM tests (RFC 3610 tests) */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + * DESCRIPTION + * This module tests the following AES-CCM Mode routines: + * + * Scenarios tested include: + * - AES128 CCM mode encryption RFC 3610 test vector #1 + * - AES128 CCM mode encryption RFC 3610 test vector #2 + * - AES128 CCM mode encryption RFC 3610 test vector #3 + * - AES128 CCM mode encryption RFC 3610 test vector #7 + * - AES128 CCM mode encryption RFC 3610 test vector #8 + * - AES128 CCM mode encryption RFC 3610 test vector #9 + * - AES128 CCM mode encryption No associated data + * - AES128 CCM mode encryption No payload data + */ + +#include +#include +#include + +#include + +#define TC_CCM_MAX_CT_SIZE 50 +#define TC_CCM_MAX_PT_SIZE 25 +#define NUM_NIST_KEYS 16 +#define NONCE_LEN 13 +#define HEADER_LEN 8 +#define M_LEN8 8 +#define M_LEN10 10 +#define DATA_BUF_LEN23 23 +#define DATA_BUF_LEN24 24 +#define DATA_BUF_LEN25 25 +#define EXPECTED_BUF_LEN31 31 +#define EXPECTED_BUF_LEN32 32 +#define EXPECTED_BUF_LEN33 33 +#define EXPECTED_BUF_LEN34 34 +#define EXPECTED_BUF_LEN35 35 + +int do_test(const uint8_t *key, uint8_t *nonce, + size_t nlen, const uint8_t *hdr, + size_t hlen, const uint8_t *data, + size_t dlen, const uint8_t *expected, + size_t elen, const int mlen) +{ + + int result = TC_PASS; + + uint8_t ciphertext[TC_CCM_MAX_CT_SIZE]; + uint8_t decrypted[TC_CCM_MAX_PT_SIZE]; + struct tc_ccm_mode_struct c; + struct tc_aes_key_sched_struct sched; + + tc_aes128_set_encrypt_key(&sched, key); + + result = tc_ccm_config(&c, &sched, nonce, nlen, mlen); + if (result == 0) { + TC_ERROR("CCM config failed in %s.\n", __func__); + + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_generation_encryption(ciphertext, TC_CCM_MAX_CT_SIZE, hdr, + hlen, data, dlen, &c); + if (result == 0) { + TC_ERROR("ccm_encrypt failed in %s.\n", __func__); + + result = TC_FAIL; + goto exitTest1; + } + + + if (memcmp(expected, ciphertext, elen) != 0) { + TC_ERROR("ccm_encrypt produced wrong ciphertext in %s.\n", + __func__); + show_str("\t\tExpected", expected, elen); + show_str("\t\tComputed", ciphertext, elen); + + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_decryption_verification(decrypted, TC_CCM_MAX_PT_SIZE, hdr, + hlen, ciphertext, dlen+mlen, &c); + if (result == 0) { + TC_ERROR("ccm_decrypt failed in %s.\n", __func__); + show_str("\t\tExpected", data, dlen); + show_str("\t\tComputed", decrypted, sizeof(decrypted)); + + result = TC_FAIL; + goto exitTest1; + } + + result = TC_PASS; + +exitTest1: + TC_END_RESULT(result); + return result; +} + +int test_vector_1(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #1 */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN23] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e + }; + const uint8_t expected[EXPECTED_BUF_LEN31] = { + 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, + 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, + 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 + }; + uint16_t mlen = M_LEN8; + + TC_PRINT("%s: Performing CCM test #1 (RFC 3610 test vector #1):\n", + __func__); + + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + + return result; +} + +int test_vector_2(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #2 */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN24] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + const uint8_t expected[EXPECTED_BUF_LEN32] = { + 0x72, 0xc9, 0x1a, 0x36, 0xe1, 0x35, 0xf8, 0xcf, + 0x29, 0x1c, 0xa8, 0x94, 0x08, 0x5c, 0x87, 0xe3, + 0xcc, 0x15, 0xc4, 0x39, 0xc9, 0xe4, 0x3a, 0x3b, + 0xa0, 0x91, 0xd5, 0x6e, 0x10, 0x40, 0x09, 0x16 + }; + uint16_t mlen = M_LEN8; + + TC_PRINT("%s: Performing CCM test #2 (RFC 3610 test vector #2):\n", + __func__); + + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + + return result; +} + +int test_vector_3(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #3 */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x02, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN25] = { + 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 + }; + const uint8_t expected[EXPECTED_BUF_LEN33] = { + 0x51, 0xb1, 0xe5, 0xf4, 0x4a, 0x19, 0x7d, 0x1d, + 0xa4, 0x6b, 0x0f, 0x8e, 0x2d, 0x28, 0x2a, 0xe8, + 0x71, 0xe8, 0x38, 0xbb, 0x64, 0xda, 0x85, 0x96, + 0x57, 0x4a, 0xda, 0xa7, 0x6f, 0xbd, 0x9f, 0xb0, + 0xc5 + }; + uint16_t mlen = M_LEN8; + + TC_PRINT("%s: Performing CCM test #3 (RFC 3610 test vector #3):\n", + __func__); + + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), data, + sizeof(data), expected, sizeof(expected), mlen); + + return result; +} + +int test_vector_4(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #7 */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x09, 0x08, 0x07, 0x06, 0xa0, + 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 + }; + const uint8_t hdr[HEADER_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN23] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e + }; + const uint8_t expected[EXPECTED_BUF_LEN33] = { + 0x01, 0x35, 0xD1, 0xB2, 0xC9, 0x5F, 0x41, 0xD5, + 0xD1, 0xD4, 0xFE, 0xC1, 0x85, 0xD1, 0x66, 0xB8, + 0x09, 0x4E, 0x99, 0x9D, 0xFE, 0xD9, 0x6C, 0x04, + 0x8C, 0x56, 0x60, 0x2C, 0x97, 0xAC, 0xBB, 0x74, + 0x90 + }; + uint16_t mlen = M_LEN10; + + TC_PRINT("%s: Performing CCM test #4 (RFC 3610 test vector #7):\n", + __func__); + + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + + return result; +} + +int test_vector_5(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #8 */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x0A, 0x09, 0x08, 0x07, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + const uint8_t hdr[HEADER_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN24] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + const uint8_t expected[EXPECTED_BUF_LEN34] = { + 0x7B, 0x75, 0x39, 0x9A, 0xC0, 0x83, 0x1D, 0xD2, + 0xF0, 0xBB, 0xD7, 0x58, 0x79, 0xA2, 0xFD, 0x8F, + 0x6C, 0xAE, 0x6B, 0x6C, 0xD9, 0xB7, 0xDB, 0x24, + 0xC1, 0x7B, 0x44, 0x33, 0xF4, 0x34, 0x96, 0x3F, + 0x34, 0xB4 + }; + uint16_t mlen = M_LEN10; + + TC_PRINT("%s: Performing CCM test #5 (RFC 3610 test vector #8):\n", + __func__); + + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + + return result; +} + +int test_vector_6(void) +{ + int result = TC_PASS; + /* RFC 3610 test vector #9 */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + const uint8_t hdr[HEADER_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + const uint8_t data[DATA_BUF_LEN25] = { + 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 + }; + const uint8_t expected[EXPECTED_BUF_LEN35] = { + 0x82, 0x53, 0x1a, 0x60, 0xCC, 0x24, 0x94, 0x5a, + 0x4b, 0x82, 0x79, 0x18, 0x1a, 0xb5, 0xc8, 0x4d, + 0xf2, 0x1c, 0xe7, 0xf9, 0xb7, 0x3f, 0x42, 0xe1, + 0x97, 0xea, 0x9c, 0x07, 0xe5, 0x6b, 0x5e, 0xb1, + 0x7e, 0x5f, 0x4e + }; + uint16_t mlen = M_LEN10; + + TC_PRINT("%s: Performing CCM test #6 (RFC 3610 test vector #9):\n", + __func__); + + result = do_test(key, nonce, sizeof(nonce), hdr, sizeof(hdr), + data, sizeof(data), expected, sizeof(expected), mlen); + + return result; +} + +int test_vector_7(void) +{ + int result = TC_PASS; + /* Test based on RFC 3610 test vector #9 but with no associated data */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + uint8_t *hdr = NULL; + + uint8_t data[DATA_BUF_LEN25] = { + 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 + }; + struct tc_ccm_mode_struct c; + struct tc_aes_key_sched_struct sched; + uint8_t decrypted[TC_CCM_MAX_PT_SIZE]; + uint8_t ciphertext[TC_CCM_MAX_CT_SIZE]; + uint16_t mlen = M_LEN10; + + TC_PRINT("%s: Performing CCM test #7 (no associated data):\n", + __func__); + + tc_aes128_set_encrypt_key(&sched, key); + if (tc_ccm_config(&c, &sched, nonce, sizeof(nonce), mlen) == 0) { + TC_ERROR("ccm_config failed in %s.\n", __func__); + + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_generation_encryption(ciphertext, TC_CCM_MAX_CT_SIZE, hdr, + 0, data, sizeof(data), &c); + if (result == 0) { + TC_ERROR("ccm_encryption failed in %s.\n", __func__); + + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_decryption_verification (decrypted, TC_CCM_MAX_PT_SIZE, hdr, + 0, ciphertext, sizeof(data)+mlen, &c); + if (result == 0) { + TC_ERROR("ccm_decrypt failed in %s.\n", __func__); + show_str("\t\tExpected", data, sizeof(data)); + show_str("\t\tComputed", decrypted, sizeof(decrypted)); + + result = TC_FAIL; + goto exitTest1; + } + + result = TC_PASS; + +exitTest1: + TC_END_RESULT(result); + return result; + +} + +int test_vector_8(void) +{ + int result = TC_PASS; + /* Test based on RFC 3610 test vector #9 but with no payload data */ + const uint8_t key[NUM_NIST_KEYS] = { + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF + }; + uint8_t nonce[NONCE_LEN] = { + 0x00, 0x00, 0x00, 0x0B, 0x0A, 0x09, 0x08, 0xA0, + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 + }; + const uint8_t hdr[8] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + + uint8_t *data = NULL; + + struct tc_ccm_mode_struct c; + struct tc_aes_key_sched_struct sched; + + uint8_t decrypted[TC_CCM_MAX_PT_SIZE]; + uint8_t ciphertext[TC_CCM_MAX_CT_SIZE]; + + uint16_t mlen = M_LEN10; + + TC_PRINT("%s: Performing CCM test #8 (no payload data):\n", __func__); + + tc_aes128_set_encrypt_key(&sched, key); + if (tc_ccm_config(&c, &sched, nonce, sizeof(nonce), mlen) == 0) { + TC_ERROR("CCM config failed in %s.\n", __func__); + + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_generation_encryption(ciphertext, TC_CCM_MAX_CT_SIZE, hdr, + sizeof(hdr), data, 0, &c); + if (result == 0) { + TC_ERROR("ccm_encrypt failed in %s.\n", __func__); + + result = TC_FAIL; + goto exitTest1; + } + + result = tc_ccm_decryption_verification(decrypted, TC_CCM_MAX_PT_SIZE, hdr, + sizeof(hdr), ciphertext, mlen, &c); + if (result == 0) { + TC_ERROR("ccm_decrypt failed in %s.\n", __func__); + show_str("\t\tExpected", data, sizeof(data)); + show_str("\t\tComputed", decrypted, sizeof(decrypted)); + + result = TC_FAIL; + goto exitTest1; + } + + result = TC_PASS; + +exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + * Main task to test CCM + */ +int main(void) +{ + int result = TC_PASS; + + TC_START("Performing CCM tests:"); + + result = test_vector_1(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #1 (RFC 3610 test vector #1) failed.\n"); + goto exitTest; + } + result = test_vector_2(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #2 failed.\n"); + goto exitTest; + } + result = test_vector_3(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #3 failed.\n"); + goto exitTest; + } + result = test_vector_4(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #4 failed.\n"); + goto exitTest; + } + result = test_vector_5(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #5 failed.\n"); + goto exitTest; + } + result = test_vector_6(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #6 failed.\n"); + goto exitTest; + } + result = test_vector_7(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #7 failed.\n"); + goto exitTest; + } + result = test_vector_8(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CCM test #8 (no payload data) failed.\n"); + goto exitTest; + } + + TC_PRINT("All CCM tests succeeded!\n"); + +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + + return result; +} diff --git a/tinycrypt/tests/test_client_server b/tinycrypt/tests/test_client_server new file mode 100755 index 0000000000000000000000000000000000000000..1d09b6e58387a9d8c7ab85998e2f59af5d1a92e9 GIT binary patch literal 31400 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int test_key_exchange_and_encrypt(void) +{ + const struct uECC_Curve_t *curve = uECC_secp256r1(); + + /* Client key pair */ + uint8_t client_private[NUM_ECC_BYTES]; + uint8_t client_public[2 * NUM_ECC_BYTES]; + + /* Server key pair */ + uint8_t server_private[NUM_ECC_BYTES]; + uint8_t server_public[2 * NUM_ECC_BYTES]; + + /* Shared secrets */ + uint8_t client_secret[NUM_ECC_BYTES]; + uint8_t server_secret[NUM_ECC_BYTES]; + + TC_PRINT("Generating client key pair...\n"); + if (!uECC_make_key(client_public, client_private, curve)) { + TC_ERROR("Failed to generate client key pair\n"); + return TC_FAIL; + } + + TC_PRINT("Generating server key pair...\n"); + if (!uECC_make_key(server_public, server_private, curve)) { + TC_ERROR("Failed to generate server key pair\n"); + return TC_FAIL; + } + + /* Compute shared secret on client side */ + TC_PRINT("Computing shared secret on client side...\n"); + if (!uECC_shared_secret(server_public, client_private, client_secret, curve)) { + TC_ERROR("Failed to compute client shared secret\n"); + return TC_FAIL; + } + + /* Compute shared secret on server side */ + TC_PRINT("Computing shared secret on server side...\n"); + if (!uECC_shared_secret(client_public, server_private, server_secret, curve)) { + TC_ERROR("Failed to compute server shared secret\n"); + return TC_FAIL; + } + + /* Verify that both shared secrets match */ + if (memcmp(client_secret, server_secret, NUM_ECC_BYTES) != 0) { + TC_ERROR("Shared secrets do not match\n"); + show_str("Client secret", client_secret, NUM_ECC_BYTES); + show_str("Server secret", server_secret, NUM_ECC_BYTES); + return TC_FAIL; + } + TC_PRINT("Shared secrets match.\n"); + + /* Derive AES key from shared secret (first 16 bytes) */ + uint8_t aes_key[TC_AES_KEY_SIZE]; + memcpy(aes_key, client_secret, TC_AES_KEY_SIZE); + + /* Prepare test data */ + const char *plaintext = "Hello, secure world!"; + size_t plaintext_len = strlen(plaintext) + 1; /* include null terminator */ + uint8_t ciphertext[plaintext_len]; + uint8_t decrypted[plaintext_len]; + + /* Initialize AES key schedule */ + struct tc_aes_key_sched_struct sched; + if (tc_aes128_set_encrypt_key(&sched, aes_key) != TC_CRYPTO_SUCCESS) { + TC_ERROR("Failed to set AES encryption key\n"); + return TC_FAIL; + } + + /* Initialize counter (little-endian 32-bit) */ + uint8_t ctr[TC_AES_BLOCK_SIZE] = {0}; /* zero-initialized counter */ + + TC_PRINT("Encrypting plaintext...\n"); + if (tc_ctr_mode(ciphertext, plaintext_len, (const uint8_t *)plaintext, + plaintext_len, ctr, &sched) != TC_CRYPTO_SUCCESS) { + TC_ERROR("Encryption failed\n"); + return TC_FAIL; + } + + /* Reset counter for decryption (CTR mode uses same counter sequence) */ + memset(ctr, 0, TC_AES_BLOCK_SIZE); + + TC_PRINT("Decrypting ciphertext...\n"); + if (tc_ctr_mode(decrypted, plaintext_len, ciphertext, + plaintext_len, ctr, &sched) != TC_CRYPTO_SUCCESS) { + TC_ERROR("Decryption failed\n"); + return TC_FAIL; + } + + /* Verify decrypted matches original */ + if (memcmp(plaintext, decrypted, plaintext_len) != 0) { + TC_ERROR("Decrypted text does not match original\n"); + show_str("Original", (const uint8_t *)plaintext, plaintext_len); + show_str("Decrypted", decrypted, plaintext_len); + return TC_FAIL; + } + TC_PRINT("Decryption successful. Test passed.\n"); + + return TC_PASS; +} + +int main(void) +{ + unsigned int result = TC_PASS; + + TC_START("Performing client-server key exchange and encryption test:"); + + /* Setup cryptographically secure PRNG */ + uECC_set_rng(&default_CSPRNG); + + result = test_key_exchange_and_encrypt(); + + TC_END_RESULT(result); + TC_END_REPORT(result); + + return result; +} \ No newline at end of file diff --git a/tinycrypt/tests/test_cmac_mode.c b/tinycrypt/tests/test_cmac_mode.c new file mode 100644 index 00000000..dc757fea --- /dev/null +++ b/tinycrypt/tests/test_cmac_mode.c @@ -0,0 +1,314 @@ +/* test_cmac_mode.c - TinyCrypt AES-CMAC tests (including SP 800-38B tests) */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +/* + * DESCRIPTION + * This module tests the following AES-CMAC test (including SP 800-38B): + * + * Scenarios tested include: + * - CMAC test #1 (GF(2^128) double)) + * - CMAC test #2 null msg (SP 800-38B test vector #1) + * - CMAC test #3 1 block msg (SP 800-38B test vector #2) + * - CMAC test #4 320 bit msg (SP 800-38B test vector #3) + * - CMAC test #5 512 bit msg (SP 800-38B test vector #4) + */ + +#include +#include +#include +#include + +#include +#include + +#define BUF_LEN 16 + +static void show(const char *label, const uint8_t *s, size_t slen) +{ + unsigned int i; + + TC_PRINT("%s\t", label); + for (i = 0; i < slen; ++i) { + TC_PRINT("%02x", s[i]); + } + TC_PRINT("\n"); +} + +extern void gf_double(uint8_t *out, uint8_t *in); + +static int verify_gf_2_128_double(uint8_t *K1, uint8_t *K2, + struct tc_cmac_struct s) +{ + int result = TC_PASS; + + TC_PRINT("Performing CMAC test #1 (GF(2^128) double):\n"); + + uint8_t zero[BUF_LEN]; + uint8_t L[BUF_LEN]; + const uint8_t l[BUF_LEN] = { + 0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3, + 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f + }; + const uint8_t k1[BUF_LEN] = { + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }; + const uint8_t k2[BUF_LEN] = { + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + }; + + (void) memset(zero, '\0', sizeof(zero)); + tc_aes_encrypt(L, zero, s.sched); + if (memcmp(L, l, BUF_LEN) != 0) { + TC_ERROR("%s: AES encryption failed\n", __func__); + show("expected L =", l, sizeof(l)); + show("computed L =", L, sizeof(L)); + return TC_FAIL; + } + + gf_double(K1, L); + if (memcmp(K1, k1, BUF_LEN) != 0) { + TC_ERROR("%s: gf_2_128_double failed when msb = 0\n", __func__); + show("expected K1 =", k1, sizeof(k1)); + show("computed K1 =", K1, sizeof(k1)); + return TC_FAIL; + } + + gf_double(K2, K1); + if (memcmp(K2, k2, BUF_LEN) != 0) { + TC_ERROR("%s: gf_2_128_double failed when msb = 1\n", __func__); + show("expected K2 =", k2, sizeof(k2)); + show("computed K2 =", K2, sizeof(k2)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_null_msg(TCCmacState_t s) +{ + int result = TC_PASS; + + TC_PRINT("Performing CMAC test #2 (SP 800-38B test vector #1):\n"); + + const uint8_t tag[BUF_LEN] = { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }; + uint8_t Tag[BUF_LEN]; + + (void) tc_cmac_init(s); + (void) tc_cmac_update(s, (const uint8_t *) 0, 0); + (void) tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) { + TC_ERROR("%s: aes_cmac failed with null msg = 1\n", __func__); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_1_block_msg(TCCmacState_t s) +{ + int result = TC_PASS; + + TC_PRINT("Performing CMAC test #3 (SP 800-38B test vector #2):\n"); + + const uint8_t msg[BUF_LEN] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }; + const uint8_t tag[BUF_LEN] = { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }; + uint8_t Tag[BUF_LEN]; + + (void) tc_cmac_init(s); + (void) tc_cmac_update(s, msg, sizeof(msg)); + (void) tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) { + TC_ERROR("%s: aes_cmac failed with 1 block msg\n", __func__); + show("aes_cmac failed with 1 block msg =", msg, sizeof(msg)); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_320_bit_msg(TCCmacState_t s) +{ + int result = TC_PASS; + + TC_PRINT("Performing CMAC test #4 (SP 800-38B test vector #3):\n"); + + const uint8_t msg[40] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 + }; + const uint8_t tag[BUF_LEN] = { + 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 + }; + uint8_t Tag[BUF_LEN]; + + (void) tc_cmac_init(s); + (void) tc_cmac_update(s, msg, sizeof(msg)); + (void) tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) { + TC_ERROR("%s: aes_cmac failed with 320 bit msg\n", __func__); + show("aes_cmac failed with 320 bit msg =", msg, sizeof(msg)); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +static int verify_cmac_512_bit_msg(TCCmacState_t s) +{ + int result = TC_PASS; + + TC_PRINT("Performing CMAC test #5 (SP 800-38B test vector #4)\n"); + + const uint8_t msg[64] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }; + const uint8_t tag[BUF_LEN] = { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + }; + uint8_t Tag[BUF_LEN]; + + (void)tc_cmac_init(s); + (void)tc_cmac_update(s, msg, sizeof(msg)); + (void)tc_cmac_final(Tag, s); + + if (memcmp(Tag, tag, BUF_LEN) != 0) { + TC_ERROR("%s: aes_cmac failed with 512 bit msg\n", __func__); + show("aes_cmac failed with 512 bit msg =", msg, sizeof(msg)); + show("expected Tag =", tag, sizeof(tag)); + show("computed Tag =", Tag, sizeof(Tag)); + return TC_FAIL; + } + + TC_END_RESULT(result); + return result; +} + +/* + * Main task to test CMAC + * effects: returns 1 if all tests pass + * exceptions: returns a negative value if some test fails + */ +int main(void) +{ + + int result = TC_PASS; + + struct tc_cmac_struct state; + struct tc_aes_key_sched_struct sched; + + const uint8_t key[BUF_LEN] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }; + uint8_t K1[BUF_LEN], K2[BUF_LEN]; + + TC_START("Performing CMAC tests:"); + + (void) tc_cmac_setup(&state, key, &sched); + result = verify_gf_2_128_double(K1, K2, state); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("CMAC test #1 (128 double) failed.\n"); + goto exitTest; + } + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_null_msg(&state); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("CMAC test #2 (null msg) failed.\n"); + goto exitTest; + } + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_1_block_msg(&state); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("CMAC test #3 (1 block msg)failed.\n"); + goto exitTest; + } + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_320_bit_msg(&state); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("CMAC test #4 (320 bit msg) failed.\n"); + goto exitTest; + } + (void) tc_cmac_setup(&state, key, &sched); + result = verify_cmac_512_bit_msg(&state); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("CMAC test #5 (512 bit msg)failed.\n"); + goto exitTest; + } + + TC_PRINT("All CMAC tests succeeded!\n"); + +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); + + return result; +} diff --git a/tinycrypt/tests/test_ctr_mode.c b/tinycrypt/tests/test_ctr_mode.c new file mode 100644 index 00000000..daf37878 --- /dev/null +++ b/tinycrypt/tests/test_ctr_mode.c @@ -0,0 +1,138 @@ +/* test_ctr_mode.c - TinyCrypt implementation of some AES-CTR tests */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + DESCRIPTION + This module tests the following AES-CTR Mode routines: + + Scenarios tested include: + - AES128 CTR mode encryption SP 800-38a tests +*/ + +#include +#include +#include +#include + +#include +#include +#include + +/* + * NIST SP 800-38a CTR Test for encryption and decryption. + */ +unsigned int test_1_and_2(void) +{ + const uint8_t key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, + 0x09, 0xcf, 0x4f, 0x3c + }; + uint8_t ctr[16] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff + }; + const uint8_t plaintext[64] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, + 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, + 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, + 0xe6, 0x6c, 0x37, 0x10 + }; + const uint8_t ciphertext[80] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff, 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x98, 0x06, 0xf6, 0x6b, + 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff, + 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, + 0x0d, 0xb0, 0x3e, 0xab, 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, + 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee + }; + struct tc_aes_key_sched_struct sched; + uint8_t out[80]; + uint8_t decrypted[64]; + unsigned int result = TC_PASS; + + TC_PRINT("CTR test #1 (encryption SP 800-38a tests):\n"); + (void)tc_aes128_set_encrypt_key(&sched, key); + + (void)memcpy(out, ctr, sizeof(ctr)); + if (tc_ctr_mode(&out[TC_AES_BLOCK_SIZE], sizeof(plaintext), plaintext, + sizeof(plaintext), ctr, &sched) == 0) { + TC_ERROR("CTR test #1 (encryption SP 800-38a tests) failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(1, ciphertext, sizeof(out), out, sizeof(out)); + TC_END_RESULT(result); + + TC_PRINT("CTR test #2 (decryption SP 800-38a tests):\n"); + (void) memcpy(ctr, out, sizeof(ctr)); + if (tc_ctr_mode(decrypted, sizeof(decrypted), &out[TC_AES_BLOCK_SIZE], + sizeof(decrypted), ctr, &sched) == 0) { + TC_ERROR("CTR test #2 (decryption SP 800-38a tests) failed in %s.\n", __func__); + result = TC_FAIL; + goto exitTest1; + } + + result = check_result(2, plaintext, sizeof(plaintext), + decrypted, sizeof(plaintext)); + + exitTest1: + TC_END_RESULT(result); + return result; +} + +/* + * Main task to test AES + */ + +int main(void) +{ + unsigned int result = TC_PASS; + + TC_START("Performing AES128-CTR mode tests:"); + + TC_PRINT("Performing CTR tests:\n"); + result = test_1_and_2(); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("CBC test #1 failed.\n"); + goto exitTest; + } + + TC_PRINT("All CTR tests succeeded!\n"); + + exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/tinycrypt/tests/test_ctr_prng.c b/tinycrypt/tests/test_ctr_prng.c new file mode 100644 index 00000000..e95f7f1a --- /dev/null +++ b/tinycrypt/tests/test_ctr_prng.c @@ -0,0 +1,565 @@ +/* test_ctr_prng.c - TinyCrypt implementation of some CTR-PRNG tests */ + +/* + * Copyright (c) 2016, Chris Morrison, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + DESCRIPTION + This module tests the CTR-PRNG routines +*/ + +#include +#include +#include +#include + + +#include +#include +#include + +/* utility function to convert hex character representation to their nibble (4 bit) values */ +static uint8_t nibbleFromChar(char c) +{ + if(c >= '0' && c <= '9') return c - '0'; + if(c >= 'a' && c <= 'f') return c - 'a' + 10U; + if(c >= 'A' && c <= 'F') return c - 'A' + 10U; + return 255U; +} + +/* + * Convert a string of characters representing a hex buffer into a series of + * bytes of that real value + */ +uint8_t *hexStringToBytes(char *inhex) +{ + uint8_t *retval; + uint8_t *p; + int len, i; + + len = strlen(inhex) / 2; + retval = (uint8_t *)malloc(len+1); + for(i=0, p = (uint8_t *) inhex; i +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +int ecdh_vectors(char **qx_vec, char **qy_vec, char **d_vec, char **z_vec, + int tests, int verbose) +{ + + unsigned int pub[2*NUM_ECC_WORDS]; + unsigned int prv[NUM_ECC_WORDS]; + unsigned int z[NUM_ECC_WORDS]; + unsigned int result = TC_PASS; + + int rc; + unsigned int exp_z[NUM_ECC_WORDS]; + + const struct uECC_Curve_t * curve = uECC_secp256r1(); + + for (int i = 0; i < tests; i++) { + + string2scalar(pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(pub, NUM_ECC_WORDS, qy_vec[i]); + string2scalar(exp_z, NUM_ECC_WORDS, z_vec[i]); + string2scalar(prv, NUM_ECC_WORDS, d_vec[i]); + + uint8_t pub_bytes[2*NUM_ECC_BYTES]; + uECC_vli_nativeToBytes(pub_bytes, 2*NUM_ECC_BYTES, pub); + uint8_t private_bytes[NUM_ECC_BYTES]; + uECC_vli_nativeToBytes(private_bytes, NUM_ECC_BYTES, prv); + uint8_t z_bytes[NUM_ECC_BYTES]; + uECC_vli_nativeToBytes(z_bytes, NUM_ECC_BYTES, exp_z); + + rc = uECC_shared_secret(pub_bytes, private_bytes, z_bytes, curve); + + if (rc == TC_CRYPTO_FAIL) { + TC_ERROR("ECDH failure, exit.\n"); + result = TC_FAIL; + return result;; + } + + uECC_vli_bytesToNative(z, z_bytes, NUM_ECC_BYTES); + + result = check_ecc_result(i, "Z", exp_z, z, NUM_ECC_WORDS, verbose); + if (result == TC_FAIL) { + return result; + } + } + return result; +} + +int cavp_ecdh(bool verbose) +{ + unsigned int result = TC_PASS; + /* + * P-256 + */ + char *d[] = { + "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534", + "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5", + "1accfaf1b97712b85a6f54b148985a1bdc4c9bec0bd258cad4b3d603f49f32c8", + "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d", + "59137e38152350b195c9718d39673d519838055ad908dd4757152fd8255c09bf", + "f5f8e0174610a661277979b58ce5c90fee6c9b3bb346a90a7196255e40b132ef", + "3b589af7db03459c23068b64f63f28d3c3c6bc25b5bf76ac05f35482888b5190", + "d8bf929a20ea7436b2461b541a11c80e61d826c0a4c9d322b31dd54e7f58b9c8", + "0f9883ba0ef32ee75ded0d8bda39a5146a29f1f2507b3bd458dbea0b2bb05b4d", + "2beedb04b05c6988f6a67500bb813faf2cae0d580c9253b6339e4a3337bb6c08", + "77c15dcf44610e41696bab758943eff1409333e4d5a11bbe72c8f6c395e9f848", + "42a83b985011d12303db1a800f2610f74aa71cdf19c67d54ce6c9ed951e9093e", + "ceed35507b5c93ead5989119b9ba342cfe38e6e638ba6eea343a55475de2800b", + "43e0e9d95af4dc36483cdd1968d2b7eeb8611fcce77f3a4e7d059ae43e509604", + "b2f3600df3368ef8a0bb85ab22f41fc0e5f4fdd54be8167a5c3cd4b08db04903", + "4002534307f8b62a9bf67ff641ddc60fef593b17c3341239e95bdb3e579bfdc8", + "4dfa12defc60319021b681b3ff84a10a511958c850939ed45635934ba4979147", + "1331f6d874a4ed3bc4a2c6e9c74331d3039796314beee3b7152fcdba5556304e", + "dd5e9f70ae740073ca0204df60763fb6036c45709bf4a7bb4e671412fad65da3", + "5ae026cfc060d55600717e55b8a12e116d1d0df34af831979057607c2d9c2f76", + "b601ac425d5dbf9e1735c5e2d5bdb79ca98b3d5be4a2cfd6f2273f150e064d9d", + "fefb1dda1845312b5fce6b81b2be205af2f3a274f5a212f66c0d9fc33d7ae535", + "334ae0c4693d23935a7e8e043ebbde21e168a7cba3fa507c9be41d7681e049ce", + "2c4bde40214fcc3bfc47d4cf434b629acbe9157f8fd0282540331de7942cf09d", + "85a268f9d7772f990c36b42b0a331adc92b5941de0b862d5d89a347cbf8faab0", + }; + + char *x[] = { + "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287", + "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae", + "a2339c12d4a03c33546de533268b4ad667debf458b464d77443636440ee7fec3", + "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed", + "41192d2813e79561e6a1d6f53c8bc1a433a199c835e141b05a74a97b0faeb922", + "33e82092a0f1fb38f5649d5867fba28b503172b7035574bf8e5b7100a3052792", + "6a9e0c3f916e4e315c91147be571686d90464e8bf981d34a90b6353bca6eeba7", + "a9c0acade55c2a73ead1a86fb0a9713223c82475791cd0e210b046412ce224bb", + "94e94f16a98255fff2b9ac0c9598aac35487b3232d3231bd93b7db7df36f9eb9", + "e099bf2a4d557460b5544430bbf6da11004d127cb5d67f64ab07c94fcdf5274f", + "f75a5fe56bda34f3c1396296626ef012dc07e4825838778a645c8248cff01658", + "2db4540d50230756158abf61d9835712b6486c74312183ccefcaef2797b7674d", + "cd94fc9497e8990750309e9a8534fd114b0a6e54da89c4796101897041d14ecb", + "15b9e467af4d290c417402e040426fe4cf236bae72baa392ed89780dfccdb471", + "49c503ba6c4fa605182e186b5e81113f075bc11dcfd51c932fb21e951eee2fa1", + "19b38de39fdd2f70f7091631a4f75d1993740ba9429162c2a45312401636b29c", + "2c91c61f33adfe9311c942fdbff6ba47020feff416b7bb63cec13faf9b099954", + "a28a2edf58025668f724aaf83a50956b7ac1cfbbff79b08c3bf87dfd2828d767", + "a2ef857a081f9d6eb206a81c4cf78a802bdf598ae380c8886ecd85fdc1ed7644", + "ccd8a2d86bc92f2e01bce4d6922cf7fe1626aed044685e95e2eebd464505f01f", + "c188ffc8947f7301fb7b53e36746097c2134bf9cc981ba74b4e9c4361f595e4e", + "317e1020ff53fccef18bf47bb7f2dd7707fb7b7a7578e04f35b3beed222a0eb6", + "45fb02b2ceb9d7c79d9c2fa93e9c7967c2fa4df5789f9640b24264b1e524fcb1", + "a19ef7bff98ada781842fbfc51a47aff39b5935a1c7d9625c8d323d511c92de6", + "356c5a444c049a52fee0adeb7e5d82ae5aa83030bfff31bbf8ce2096cf161c4b", + }; + + char *y[] = { + "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac", + "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3", + "ef48a3ab26e20220bcda2c1851076839dae88eae962869a497bf73cb66faf536", + "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4", + "1af98cc45e98a7e041b01cf35f462b7562281351c8ebf3ffa02e33a0722a1328", + "f2cf6b601e0a05945e335550bf648d782f46186c772c0f20d3cd0d6b8ca14b2f", + "40f9bead39c2f2bcc2602f75b8a73ec7bdffcbcead159d0174c6c4d3c5357f05", + "f6de0afa20e93e078467c053d241903edad734c6b403ba758c2b5ff04c9d4229", + "d8049a43579cfa90b8093a94416cbefbf93386f15b3f6e190b6e3455fedfe69a", + "d9c50dbe70d714edb5e221f4e020610eeb6270517e688ca64fb0e98c7ef8c1c5", + "33bbdf1b1772d8059df568b061f3f1122f28a8d819167c97be448e3dc3fb0c3c", + "62f57f314e3f3495dc4e099012f5e0ba71770f9660a1eada54104cdfde77243e", + "c3def4b5fe04faee0a11932229fff563637bfdee0e79c6deeaf449f85401c5c4", + "cdf4e9170fb904302b8fd93a820ba8cc7ed4efd3a6f2d6b05b80b2ff2aee4e77", + "8af706ff0922d87b3f0c5e4e31d8b259aeb260a9269643ed520a13bb25da5924", + "09aed7232b28e060941741b6828bcdfa2bc49cc844f3773611504f82a390a5ae", + "6cab31b06419e5221fca014fb84ec870622a1b12bab5ae43682aa7ea73ea08d0", + "dfa7bfffd4c766b86abeaf5c99b6e50cb9ccc9d9d00b7ffc7804b0491b67bc03", + "563c4c20419f07bc17d0539fade1855e34839515b892c0f5d26561f97fa04d1a", + "e9ddd583a9635a667777d5b8a8f31b0f79eba12c75023410b54b8567dddc0f38", + "bf7d2f2056e72421ef393f0c0f2b0e00130e3cac4abbcc00286168e85ec55051", + "09420ce5a19d77c6fe1ee587e6a49fbaf8f280e8df033d75403302e5a27db2ae", + "5c6e8ecf1f7d3023893b7b1ca1e4d178972ee2a230757ddc564ffe37f5c5a321", + "e9c184df75c955e02e02e400ffe45f78f339e1afe6d056fb3245f4700ce606ef", + "57d128de8b2a57a094d1a001e572173f96e8866ae352bf29cddaf92fc85b2f92", + }; + + char *Z[] = { + "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b", + "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67", + "2d457b78b4614132477618a5b077965ec90730a8c81a1c75d6d4ec68005d67ec", + "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024", + "19d44c8d63e8e8dd12c22a87b8cd4ece27acdde04dbf47f7f27537a6999a8e62", + "664e45d5bba4ac931cd65d52017e4be9b19a515f669bea4703542a2c525cd3d3", + "ca342daa50dc09d61be7c196c85e60a80c5cb04931746820be548cdde055679d", + "35aa9b52536a461bfde4e85fc756be928c7de97923f0416c7a3ac8f88b3d4489", + "605c16178a9bc875dcbff54d63fe00df699c03e8a888e9e94dfbab90b25f39b4", + "f96e40a1b72840854bb62bc13c40cc2795e373d4e715980b261476835a092e0b", + "8388fa79c4babdca02a8e8a34f9e43554976e420a4ad273c81b26e4228e9d3a3", + "72877cea33ccc4715038d4bcbdfe0e43f42a9e2c0c3b017fc2370f4b9acbda4a", + "e4e7408d85ff0e0e9c838003f28cdbd5247cdce31f32f62494b70e5f1bc36307", + "ed56bcf695b734142c24ecb1fc1bb64d08f175eb243a31f37b3d9bb4407f3b96", + "bc5c7055089fc9d6c89f83c1ea1ada879d9934b2ea28fcf4e4a7e984b28ad2cf", + "9a4e8e657f6b0e097f47954a63c75d74fcba71a30d83651e3e5a91aa7ccd8343", + "3ca1fc7ad858fb1a6aba232542f3e2a749ffc7203a2374a3f3d3267f1fc97b78", + "1aaabe7ee6e4a6fa732291202433a237df1b49bc53866bfbe00db96a0f58224f", + "430e6a4fba4449d700d2733e557f66a3bf3d50517c1271b1ddae1161b7ac798c", + "1ce9e6740529499f98d1f1d71329147a33df1d05e4765b539b11cf615d6974d3", + "4690e3743c07d643f1bc183636ab2a9cb936a60a802113c49bb1b3f2d0661660", + "30c2261bd0004e61feda2c16aa5e21ffa8d7e7f7dbf6ec379a43b48e4b36aeb0", + "2adae4a138a239dcd93c243a3803c3e4cf96e37fe14e6a9b717be9599959b11c", + "2e277ec30f5ea07d6ce513149b9479b96e07f4b6913b1b5c11305c1444a1bc0b", + "1e51373bd2c6044c129c436e742a55be2a668a85ae08441b6756445df5493857", + }; + + TC_PRINT("Test #1: ECDH"); + TC_PRINT("NIST-p256\n"); + + result = ecdh_vectors(x, y, d, Z, 25, verbose); + if(result == TC_FAIL) { + goto exitTest1; + } + + exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_keygen(bool verbose) +{ + unsigned int result = TC_PASS; + /* + * [P-256, B.4.2 Key Pair Generation by Testing Candidates] + */ + char *d[] = { + "c9806898a0334916c860748880a541f093b579a9b1f32934d86c363c39800357", + "710735c8388f48c684a97bd66751cc5f5a122d6b9a96a2dbe73662f78217446d", + "78d5d8b7b3e2c16b3e37e7e63becd8ceff61e2ce618757f514620ada8a11f6e4", + "2a61a0703860585fe17420c244e1de5a6ac8c25146b208ef88ad51ae34c8cb8c", + "01b965b45ff386f28c121c077f1d7b2710acc6b0cb58d8662d549391dcf5a883", + "fac92c13d374c53a085376fe4101618e1e181b5a63816a84a0648f3bdc24e519", + "f257a192dde44227b3568008ff73bcf599a5c45b32ab523b5b21ca582fef5a0a", + "add67e57c42a3d28708f0235eb86885a4ea68e0d8cfd76eb46134c596522abfd", + "4494860fd2c805c5c0d277e58f802cff6d731f76314eb1554142a637a9bc5538", + "d40b07b1ea7b86d4709ef9dc634c61229feb71abd63dc7fc85ef46711a87b210", + }; + + char *x[] = { + "d0720dc691aa80096ba32fed1cb97c2b620690d06de0317b8618d5ce65eb728f", + "f6836a8add91cb182d8d258dda6680690eb724a66dc3bb60d2322565c39e4ab9", + "76711126cbb2af4f6a5fe5665dad4c88d27b6cb018879e03e54f779f203a854e", + "e1aa7196ceeac088aaddeeba037abb18f67e1b55c0a5c4e71ec70ad666fcddc8", + "1f038c5422e88eec9e88b815e8f6b3e50852333fc423134348fc7d79ef8e8a10", + "7258f2ab96fc84ef6ccb33e308cd392d8b568ea635730ceb4ebd72fa870583b9", + "d2e01411817b5512b79bbbe14d606040a4c90deb09e827d25b9f2fc068997872", + "55bed2d9c029b7f230bde934c7124ed52b1330856f13cbac65a746f9175f85d7", + "5190277a0c14d8a3d289292f8a544ce6ea9183200e51aec08440e0c1a463a4e4", + "fbcea7c2827e0e8085d7707b23a3728823ea6f4878b24747fb4fd2842d406c73", + }; + + char *y[] = { + "9681b517b1cda17d0d83d335d9c4a8a9a9b0b1b3c7106d8f3c72bc5093dc275f", + "1f837aa32864870cb8e8d0ac2ff31f824e7beddc4bb7ad72c173ad974b289dc2", + "a26df39960ab5248fd3620fd018398e788bd89a3cea509b352452b69811e6856", + "d7d35bdce6dedc5de98a7ecb27a9cd066a08f586a733b59f5a2cdb54f971d5c8", + "43a047cb20e94b4ffb361ef68952b004c0700b2962e0c0635a70269bc789b849", + "489807ca55bdc29ca5c8fe69b94f227b0345cccdbe89975e75d385cc2f6bb1e2", + "503f138f8bab1df2c4507ff663a1fdf7f710e7adb8e7841eaa902703e314e793", + "32805e311d583b4e007c40668185e85323948e21912b6b0d2cda8557389ae7b0", + "ecd98514821bd5aaf3419ab79b71780569470e4fed3da3c1353b28fe137f36eb", + "2393c85f1f710c5afc115a39ba7e18abe03f19c9d4bb3d47d19468b818efa535", + }; + + TC_PRINT("Test #2: ECC KeyGen "); + TC_PRINT("NIST-p256\n"); + + result = keygen_vectors(d, x, y, 10, verbose); + if(result == TC_FAIL) { + goto exitTest1; + } + + exitTest1: + TC_END_RESULT(result); + return result; +} + +/* Test ecc_make_keys, and also as keygen part of other tests */ +int pkv_vectors(char **qx_vec, char **qy_vec, char **res_vec, int tests, + bool verbose) +{ + + unsigned int pub[2 * NUM_ECC_WORDS]; + uint8_t _public[2 * NUM_ECC_BYTES]; + int rc; + int exp_rc; + char tmp; + unsigned int result = TC_PASS; + const struct uECC_Curve_t * curve = uECC_secp256r1(); + + for (int i = 0; i < tests; i++) { + + if (2 != sscanf(res_vec[i], "%c (%d ", &tmp, &exp_rc)) { + TC_ERROR("Error: failed to parse CAVP response.\n"); + result = TC_FAIL; + goto exitTest1; + } + + if (strlen(qx_vec[i]) > 2 * NUM_ECC_BYTES || + strlen(qy_vec[i]) > 2 * NUM_ECC_BYTES) { + /* invalid input to ECC digit conversion (string2native()) */ + rc = -2; + } else { + string2scalar(pub, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qy_vec[i]); + + uECC_vli_nativeToBytes(_public, NUM_ECC_BYTES, pub); + uECC_vli_nativeToBytes(_public + NUM_ECC_BYTES, NUM_ECC_BYTES, pub+NUM_ECC_WORDS); + + rc = uECC_valid_public_key(_public, curve); + } + + /* + * map to CAVP error codes + * 0 => 0 - success + * -1 => ? - (x,y) = (0,0) (not covered) + * -2 => 1 - out of bounds (pubverify or ecc import) + * -3 => 2 - not on curve + * -4 => ? - public key is the group generator + */ + + if (rc == -3) rc = 2; + if (rc == -2) rc = 1; + + result = check_code(i, res_vec[i], exp_rc, rc, verbose); + if(result == TC_FAIL) { + goto exitTest1; + } + } + + exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_pkv(bool verbose) +{ + /* + * [P-256] + */ + char *x[] = { + "e0f7449c5588f24492c338f2bc8f7865f755b958d48edb0f2d0056e50c3fd5b7", + "d17c446237d9df87266ba3a91ff27f45abfdcb77bfd83536e92903efb861a9a9", + "17875397ae87369365656d490e8ce956911bd97607f2aff41b56f6f3a61989826", + "f2d1c0dc0852c3d8a2a2500a23a44813ccce1ac4e58444175b440469ffc12273", + "10b0ca230fff7c04768f4b3d5c75fa9f6c539bea644dffbec5dc796a213061b58", + "2c1052f25360a15062d204a056274e93cbe8fc4c4e9b9561134ad5c15ce525da", + "a40d077a87dae157d93dcccf3fe3aca9c6479a75aa2669509d2ef05c7de6782f", + "2633d398a3807b1895548adbb0ea2495ef4b930f91054891030817df87d4ac0a", + "14bf57f76c260b51ec6bbc72dbd49f02a56eaed070b774dc4bad75a54653c3d56", + "2fa74931ae816b426f484180e517f5050c92decfc8daf756cd91f54d51b302f1", + "f8c6dd3181a76aa0e36c2790bba47041acbe7b1e473ff71eee39a824dc595ff0", + "7a81a7e0b015252928d8b36e4ca37e92fdc328eb25c774b4f872693028c4be38", + }; + + char *y[] = { + "86d7e9255d0f4b6f44fa2cd6f8ba3c0aa828321d6d8cc430ca6284ce1d5b43a0", + "1eabb6a349ce2cd447d777b6739c5fc066add2002d2029052c408d0701066231c", + "980a3c4f61b9692633fbba5ef04c9cb546dd05cdec9fa8428b8849670e2fba92", + "32bfe992831b305d8c37b9672df5d29fcb5c29b4a40534683e3ace23d24647dd", + "f5edf37c11052b75f771b7f9fa050e353e464221fec916684ed45b6fead38205", + "ced9783713a8a2a09eff366987639c625753295d9a85d0f5325e32dedbcada0b", + "503d86b87d743ba20804fd7e7884aa017414a7b5b5963e0d46e3a9611419ddf3", + "d6b2f738e3873cc8364a2d364038ce7d0798bb092e3dd77cbdae7c263ba618d2", + "7a231a23bf8b3aa31d9600d888a0678677a30e573decd3dc56b33f365cc11236", + "5b994346137988c58c14ae2152ac2f6ad96d97decb33099bd8a0210114cd1141", + "9c965f227f281b3072b95b8daf29e88b35284f3574462e268e529bbdc50e9e52", + "08862f7335147261e7b1c3d055f9a316e4cab7daf99cc09d1c647f5dd6e7d5bb", + }; + + char *Result[] = { + "P (0 )", "F (1 - Q_x or Q_y out of range)", + "F (1 - Q_x or Q_y out of range)", "F (2 - Point not on curve)", + "F (1 - Q_x or Q_y out of range)", "P (0 )", + "F (2 - Point not on curve)", "P (0 )", + "F (1 - Q_x or Q_y out of range)", "P (0 )", + "F (2 - Point not on curve)", "F (2 - Point not on curve)", + }; + + TC_PRINT("Test #3: PubKeyVerify "); + TC_PRINT("NIST-p256-SHA2-256\n"); + + return pkv_vectors(x, y, Result, 12, verbose); +} + +int montecarlo_ecdh(int num_tests, bool verbose) +{ + int i; + uint8_t private1[NUM_ECC_BYTES] = {0}; + uint8_t private2[NUM_ECC_BYTES] = {0}; + uint8_t public1[2*NUM_ECC_BYTES] = {0}; + uint8_t public2[2*NUM_ECC_BYTES] = {0}; + uint8_t secret1[NUM_ECC_BYTES] = {0}; + uint8_t secret2[NUM_ECC_BYTES] = {0}; + unsigned int result = TC_PASS; + + const struct uECC_Curve_t * curve = uECC_secp256r1(); + + TC_PRINT("Test #4: Monte Carlo (%d Randomized EC-DH key-exchange) ", num_tests); + TC_PRINT("NIST-p256\n "); + + for (i = 0; i < num_tests; ++i) { + if (verbose) { + TC_PRINT("."); + fflush(stdout); + } + + if (!uECC_make_key(public1, private1, curve) || + !uECC_make_key(public2, private2, curve)) { + TC_ERROR("uECC_make_key() failed\n"); + result = TC_FAIL; + goto exitTest1; + } + + if (!uECC_shared_secret(public2, private1, secret1, curve)) { + TC_ERROR("shared_secret() failed (1)\n"); + result = TC_FAIL; + goto exitTest1;; + } + + if (!uECC_shared_secret(public1, private2, secret2, curve)) { + TC_ERROR("shared_secret() failed (2)\n"); + result = TC_FAIL; + goto exitTest1; + } + + if (memcmp(secret1, secret2, sizeof(secret1)) != 0) { + TC_PRINT("Shared secrets are not identical!\n"); + TC_PRINT("Private key 1 = "); + vli_print_bytes(private1, 32); + TC_PRINT("\nPrivate key 2 = "); + vli_print_bytes(private2, 32); + TC_PRINT("\nPublic key 1 = "); + vli_print_bytes(public1, 64); + TC_PRINT("\nPublic key 2 = "); + vli_print_bytes(public2, 64); + TC_PRINT("\nShared secret 1 = "); + vli_print_bytes(secret1, 32); + TC_PRINT("\nShared secret 2 = "); + vli_print_bytes(secret2, 32); + TC_PRINT("\n"); + } + } + + TC_PRINT("\n"); + + exitTest1: + TC_END_RESULT(result); + return result; +} + +int main() +{ + unsigned int result = TC_PASS; + + TC_START("Performing ECC-DH tests:"); + + /* Setup of the Cryptographically Secure PRNG. */ + uECC_set_rng(&default_CSPRNG); + + bool verbose = true; + + TC_PRINT("Performing cavp_ecdh test:\n"); + result = cavp_ecdh(verbose); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("cavp_ecdh test failed.\n"); + goto exitTest; + } + TC_PRINT("Performing cavp_keygen test:\n"); + result = cavp_keygen(verbose); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("cavp_keygen test failed.\n"); + goto exitTest; + } + TC_PRINT("Performing cavp_pkv test:\n"); + result = cavp_pkv(verbose); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("cavp_pkv failed.\n"); + goto exitTest; + } + TC_PRINT("Performing montecarlo_ecdh test:\n"); + result = montecarlo_ecdh(10, verbose); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("montecarlo_ecdh test failed.\n"); + goto exitTest; + } + + TC_PRINT("All EC-DH tests succeeded!\n"); + + exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/tinycrypt/tests/test_ecc_dsa.c b/tinycrypt/tests/test_ecc_dsa.c new file mode 100644 index 00000000..d1e933cd --- /dev/null +++ b/tinycrypt/tests/test_ecc_dsa.c @@ -0,0 +1,669 @@ +/* test_ecc_ecdsa.c - TinyCrypt implementation of some EC-DSA tests */ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.*/ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * test_ecc_ecdsa.c -- Implementation of some EC-DSA tests + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* Maximum size of message to be signed. */ +#define BUF_SIZE 256 + +int sign_vectors(TCSha256State_t hash, char **d_vec, char **k_vec, + char **msg_vec, char **qx_vec, char **qy_vec, char **r_vec, + char **s_vec, int tests, bool verbose) +{ + + unsigned int k[NUM_ECC_WORDS]; + unsigned int private[NUM_ECC_WORDS]; + uint8_t private_bytes[NUM_ECC_BYTES]; + unsigned int sig[2 * NUM_ECC_WORDS]; + uint8_t sig_bytes[2 * NUM_ECC_BYTES]; + unsigned int digest[TC_SHA256_DIGEST_SIZE / 4]; + uint8_t digest_bytes[TC_SHA256_DIGEST_SIZE]; + unsigned int result = TC_PASS; + + /* expected outputs (converted input vectors) */ + unsigned int exp_r[NUM_ECC_WORDS]; + unsigned int exp_s[NUM_ECC_WORDS]; + + uint8_t msg[BUF_SIZE]; + size_t msglen; + + for (int i = 0; i < tests; i++) { + + /* use keygen test to generate and validate pubkey */ + keygen_vectors(d_vec+i, qx_vec+i, qy_vec+i, 1, false); + string2scalar(private, NUM_ECC_WORDS, d_vec[i]); + uECC_vli_nativeToBytes(private_bytes, NUM_ECC_BYTES, private); + + /* validate ECDSA: hash message, sign digest, check r+s */ + memset(k, 0, NUM_ECC_BYTES); + string2scalar(k, NUM_ECC_WORDS, k_vec[i]); + string2scalar(exp_r, NUM_ECC_WORDS, r_vec[i]); + string2scalar(exp_s, NUM_ECC_WORDS, s_vec[i]); + + msglen = hex2bin(msg, BUF_SIZE, msg_vec[i], strlen(msg_vec[i])); + + if (msglen == false) { + TC_ERROR("failed to import message!\n"); + result = TC_FAIL; + goto exitTest1; + } + + tc_sha256_init(hash); + tc_sha256_update(hash, msg, msglen); + tc_sha256_final(digest_bytes, hash); + + /* if digest larger than ECC scalar, drop the end + * if digest smaller than ECC scalar, zero-pad front */ + int hash_dwords = TC_SHA256_DIGEST_SIZE / 4; + if (NUM_ECC_WORDS < hash_dwords) { + hash_dwords = NUM_ECC_WORDS; + } + + memset(digest, 0, NUM_ECC_BYTES - 4 * hash_dwords); + uECC_vli_bytesToNative(digest + (NUM_ECC_WORDS-hash_dwords), + digest_bytes, TC_SHA256_DIGEST_SIZE); + + if (uECC_sign_with_k(private_bytes, digest_bytes, + sizeof(digest_bytes), k, sig_bytes, uECC_secp256r1()) == 0) { + TC_ERROR("ECDSA_sign failed!\n"); + result = TC_FAIL; + goto exitTest1; + } + + uECC_vli_bytesToNative(sig, sig_bytes, NUM_ECC_BYTES); + uECC_vli_bytesToNative(sig + NUM_ECC_WORDS, sig_bytes+NUM_ECC_BYTES, NUM_ECC_BYTES); + + result = check_ecc_result(i, "sig.r", exp_r, sig, NUM_ECC_WORDS, verbose); + if(result == TC_FAIL) { + goto exitTest1; + } + result = check_ecc_result(i, "sig.s", exp_s, sig + NUM_ECC_WORDS, NUM_ECC_WORDS, verbose); + if(result == TC_FAIL) { + goto exitTest1; + } + } + + exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_sign(bool verbose) +{ + + /* + * [P-256,SHA-256] + */ + char *d[] = { + "519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464", + "0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813", + "e283871239837e13b95f789e6e1af63bf61c918c992e62bca040d64cad1fc2ef", + "a3d2d3b7596f6592ce98b4bfe10d41837f10027a90d7bb75349490018cf72d07", + "53a0e8a8fe93db01e7ae94e1a9882a102ebd079b3a535827d583626c272d280d", + "4af107e8e2194c830ffb712a65511bc9186a133007855b49ab4b3833aefc4a1d", + "78dfaa09f1076850b3e206e477494cddcfb822aaa0128475053592c48ebaf4ab", + "80e692e3eb9fcd8c7d44e7de9f7a5952686407f90025a1d87e52c7096a62618a", + "5e666c0db0214c3b627a8e48541cc84a8b6fd15f300da4dff5d18aec6c55b881", + "f73f455271c877c4d5334627e37c278f68d143014b0a05aa62f308b2101c5308", + "b20d705d9bd7c2b8dc60393a5357f632990e599a0975573ac67fd89b49187906", + "d4234bebfbc821050341a37e1240efe5e33763cbbb2ef76a1c79e24724e5a5e7", + "b58f5211dff440626bb56d0ad483193d606cf21f36d9830543327292f4d25d8c", + "54c066711cdb061eda07e5275f7e95a9962c6764b84f6f1f3ab5a588e0a2afb1", + "34fa4682bf6cb5b16783adcd18f0e6879b92185f76d7c920409f904f522db4b1", + }; + + char *k[] = { + "94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de", + "6d3e71882c3b83b156bb14e0ab184aa9fb728068d3ae9fac421187ae0b2f34c6", + "ad5e887eb2b380b8d8280ad6e5ff8a60f4d26243e0124c2f31a297b5d0835de2", + "24fc90e1da13f17ef9fe84cc96b9471ed1aaac17e3a4bae33a115df4e5834f18", + "5d833e8d24cc7a402d7ee7ec852a3587cddeb48358cea71b0bedb8fabe84e0c4", + "e18f96f84dfa2fd3cdfaec9159d4c338cd54ad314134f0b31e20591fc238d0ab", + "295544dbb2da3da170741c9b2c6551d40af7ed4e891445f11a02b66a5c258a77", + "7c80fd66d62cc076cef2d030c17c0a69c99611549cb32c4ff662475adbe84b22", + "2e7625a48874d86c9e467f890aaa7cd6ebdf71c0102bfdcfa24565d6af3fdce9", + "62f8665fd6e26b3fa069e85281777a9b1f0dfd2c0b9f54a086d0c109ff9fd615", + "72b656f6b35b9ccbc712c9f1f3b1a14cbbebaec41c4bca8da18f492a062d6f6f", + "d926fe10f1bfd9855610f4f5a3d666b1a149344057e35537373372ead8b1a778", + "e158bf4a2d19a99149d9cdb879294ccb7aaeae03d75ddd616ef8ae51a6dc1071", + "646fe933e96c3b8f9f507498e907fdd201f08478d0202c752a7c2cfebf4d061a", + "a6f463ee72c9492bc792fe98163112837aebd07bab7a84aaed05be64db3086f4", + }; + + char *Msg[] = { + "5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe16" + "5b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd280" + "65b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d0379979" + "0fe2d308d16146d5c9b0d0debd97d79ce8", + "c35e2f092553c55772926bdbe87c9796827d17024dbb9233a545366e2e5987dd344deb72df" + "987144b8c6c43bc41b654b94cc856e16b96d7a821c8ec039b503e3d86728c494a967d83011" + "a0e090b5d54cd47f4e366c0912bc808fbb2ea96efac88fb3ebec9342738e225f7c7c2b011c" + "e375b56621a20642b4d36e060db4524af1", + "3c054e333a94259c36af09ab5b4ff9beb3492f8d5b4282d16801daccb29f70fe61a0b37ffe" + "f5c04cd1b70e85b1f549a1c4dc672985e50f43ea037efa9964f096b5f62f7ffdf8d6bfb2cc" + "859558f5a393cb949dbd48f269343b5263dcdb9c556eca074f2e98e6d94c2c29a677afaf80" + "6edf79b15a3fcd46e7067b7669f83188ee", + "0989122410d522af64ceb07da2c865219046b4c3d9d99b01278c07ff63eaf1039cb787ae9e" + "2dd46436cc0415f280c562bebb83a23e639e476a02ec8cff7ea06cd12c86dcc3adefbf1a9e" + "9a9b6646c7599ec631b0da9a60debeb9b3e19324977f3b4f36892c8a38671c8e1cc8e50fcd" + "50f9e51deaf98272f9266fc702e4e57c30", + "dc66e39f9bbfd9865318531ffe9207f934fa615a5b285708a5e9c46b7775150e818d7f24d2" + "a123df3672fff2094e3fd3df6fbe259e3989dd5edfcccbe7d45e26a775a5c4329a084f057c" + "42c13f3248e3fd6f0c76678f890f513c32292dd306eaa84a59abe34b16cb5e38d0e885525d" + "10336ca443e1682aa04a7af832b0eee4e7", + "600974e7d8c5508e2c1aab0783ad0d7c4494ab2b4da265c2fe496421c4df238b0be25f2565" + "9157c8a225fb03953607f7df996acfd402f147e37aee2f1693e3bf1c35eab3ae360a2bd91d" + "04622ea47f83d863d2dfecb618e8b8bdc39e17d15d672eee03bb4ce2cc5cf6b217e5faf3f3" + "36fdd87d972d3a8b8a593ba85955cc9d71", + "dfa6cb9b39adda6c74cc8b2a8b53a12c499ab9dee01b4123642b4f11af336a91a5c9ce0520" + "eb2395a6190ecbf6169c4cba81941de8e76c9c908eb843b98ce95e0da29c5d4388040264e0" + "5e07030a577cc5d176387154eabae2af52a83e85c61c7c61da930c9b19e45d7e34c8516dc3" + "c238fddd6e450a77455d534c48a152010b", + "51d2547cbff92431174aa7fc7302139519d98071c755ff1c92e4694b58587ea560f72f32fc" + "6dd4dee7d22bb7387381d0256e2862d0644cdf2c277c5d740fa089830eb52bf79d1e75b859" + "6ecf0ea58a0b9df61e0c9754bfcd62efab6ea1bd216bf181c5593da79f10135a9bc6e164f1" + "854bc8859734341aad237ba29a81a3fc8b", + "558c2ac13026402bad4a0a83ebc9468e50f7ffab06d6f981e5db1d082098065bcff6f21a7a" + "74558b1e8612914b8b5a0aa28ed5b574c36ac4ea5868432a62bb8ef0695d27c1e3ceaf75c7" + "b251c65ddb268696f07c16d2767973d85beb443f211e6445e7fe5d46f0dce70d58a4cd9fe7" + "0688c035688ea8c6baec65a5fc7e2c93e8", + "4d55c99ef6bd54621662c3d110c3cb627c03d6311393b264ab97b90a4b15214a5593ba2510" + "a53d63fb34be251facb697c973e11b665cb7920f1684b0031b4dd370cb927ca7168b0bf8ad" + "285e05e9e31e34bc24024739fdc10b78586f29eff94412034e3b606ed850ec2c1900e8e681" + "51fc4aee5adebb066eb6da4eaa5681378e", + "f8248ad47d97c18c984f1f5c10950dc1404713c56b6ea397e01e6dd925e903b4fadfe2c9e8" + "77169e71ce3c7fe5ce70ee4255d9cdc26f6943bf48687874de64f6cf30a012512e787b8805" + "9bbf561162bdcc23a3742c835ac144cc14167b1bd6727e940540a9c99f3cbb41fb1dcb00d7" + "6dda04995847c657f4c19d303eb09eb48a", + "3b6ee2425940b3d240d35b97b6dcd61ed3423d8e71a0ada35d47b322d17b35ea0472f35edd" + "1d252f87b8b65ef4b716669fc9ac28b00d34a9d66ad118c9d94e7f46d0b4f6c2b2d339fd6b" + "cd351241a387cc82609057048c12c4ec3d85c661975c45b300cb96930d89370a327c98b67d" + "efaa89497aa8ef994c77f1130f752f94a4", + "c5204b81ec0a4df5b7e9fda3dc245f98082ae7f4efe81998dcaa286bd4507ca840a53d21b0" + "1e904f55e38f78c3757d5a5a4a44b1d5d4e480be3afb5b394a5d2840af42b1b4083d40afbf" + "e22d702f370d32dbfd392e128ea4724d66a3701da41ae2f03bb4d91bb946c7969404cb544f" + "71eb7a49eb4c4ec55799bda1eb545143a7", + "72e81fe221fb402148d8b7ab03549f1180bcc03d41ca59d7653801f0ba853add1f6d29edd7" + "f9abc621b2d548f8dbf8979bd16608d2d8fc3260b4ebc0dd42482481d548c7075711b57596" + "49c41f439fad69954956c9326841ea6492956829f9e0dc789f73633b40f6ac77bcae6dfc79" + "30cfe89e526d1684365c5b0be2437fdb01", + "21188c3edd5de088dacc1076b9e1bcecd79de1003c2414c3866173054dc82dde85169baa77" + "993adb20c269f60a5226111828578bcc7c29e6e8d2dae81806152c8ba0c6ada1986a1983eb" + "eec1473a73a04795b6319d48662d40881c1723a706f516fe75300f92408aa1dc6ae4288d20" + "46f23c1aa2e54b7fb6448a0da922bd7f34", + }; + + char *Qx[] = { + "1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83", + "e266ddfdc12668db30d4ca3e8f7749432c416044f2d2b8c10bf3d4012aeffa8a", + "74ccd8a62fba0e667c50929a53f78c21b8ff0c3c737b0b40b1750b2302b0bde8", + "322f80371bf6e044bc49391d97c1714ab87f990b949bc178cb7c43b7c22d89e1", + "1bcec4570e1ec2436596b8ded58f60c3b1ebc6a403bc5543040ba82963057244", + "a32e50be3dae2c8ba3f5e4bdae14cf7645420d425ead94036c22dd6c4fc59e00", + "8bcfe2a721ca6d753968f564ec4315be4857e28bef1908f61a366b1f03c97479", + "a88bc8430279c8c0400a77d751f26c0abc93e5de4ad9a4166357952fe041e767", + "1bc487570f040dc94196c9befe8ab2b6de77208b1f38bdaae28f9645c4d2bc3a", + "b8188bd68701fc396dab53125d4d28ea33a91daf6d21485f4770f6ea8c565dde", + "51f99d2d52d4a6e734484a018b7ca2f895c2929b6754a3a03224d07ae61166ce", + "8fb287f0202ad57ae841aea35f29b2e1d53e196d0ddd9aec24813d64c0922fb7", + "68229b48c2fe19d3db034e4c15077eb7471a66031f28a980821873915298ba76", + "0a7dbb8bf50cb605eb2268b081f26d6b08e012f952c4b70a5a1e6e7d46af98bb", + "105d22d9c626520faca13e7ced382dcbe93498315f00cc0ac39c4821d0d73737", + }; + + char *Qy[] = { + "ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9", + "bfa86404a2e9ffe67d47c587ef7a97a7f456b863b4d02cfc6928973ab5b1cb39", + "29074e21f3a0ef88b9efdf10d06aa4c295cc1671f758ca0e4cd108803d0f2614", + "3c15d54a5cc6b9f09de8457e873eb3deb1fceb54b0b295da6050294fae7fd999", + "8af62a4c683f096b28558320737bf83b9959a46ad2521004ef74cf85e67494e1", + "d623bf641160c289d6742c6257ae6ba574446dd1d0e74db3aaa80900b78d4ae9", + "0f67576a30b8e20d4232d8530b52fb4c89cbc589ede291e499ddd15fe870ab96", + "2d365a1eef25ead579cc9a069b6abc1b16b81c35f18785ce26a10ba6d1381185", + "ec81602abd8345e71867c8210313737865b8aa186851e1b48eaca140320f5d8f", + "423f058810f277f8fe076f6db56e9285a1bf2c2a1dae145095edd9c04970bc4a", + "4737da963c6ef7247fb88d19f9b0c667cac7fe12837fdab88c66f10d3c14cad1", + "1f6daff1aa2dd2d6d3741623eecb5e7b612997a1039aab2e5cf2de969cfea573", + "303e8ee3742a893f78b810991da697083dd8f11128c47651c27a56740a80c24c", + "f26dd7d799930062480849962ccf5004edcfd307c044f4e8f667c9baa834eeae", + "6c47f3cbbfa97dfcebe16270b8c7d5d3a5900b888c42520d751e8faf3b401ef4", + }; + + char *R[] = { + "f3ac8061b514795b8843e3d6629527ed2afd6b1f6a555a7acabb5e6f79c8c2ac", + "976d3a4e9d23326dc0baa9fa560b7c4e53f42864f508483a6473b6a11079b2db", + "35fb60f5ca0f3ca08542fb3cc641c8263a2cab7a90ee6a5e1583fac2bb6f6bd1", + "d7c562370af617b581c84a2468cc8bd50bb1cbf322de41b7887ce07c0e5884ca", + "18caaf7b663507a8bcd992b836dec9dc5703c080af5e51dfa3a9a7c387182604", + "8524c5024e2d9a73bde8c72d9129f57873bbad0ed05215a372a84fdbc78f2e68", + "c5a186d72df452015480f7f338970bfe825087f05c0088d95305f87aacc9b254", + "9d0c6afb6df3bced455b459cc21387e14929392664bb8741a3693a1795ca6902", + "2f9e2b4e9f747c657f705bffd124ee178bbc5391c86d056717b140c153570fd9", + "1cc628533d0004b2b20e7f4baad0b8bb5e0673db159bbccf92491aef61fc9620", + "9886ae46c1415c3bc959e82b760ad760aab66885a84e620aa339fdf102465c42", + "490efd106be11fc365c7467eb89b8d39e15d65175356775deab211163c2504cb", + "e67a9717ccf96841489d6541f4f6adb12d17b59a6bef847b6183b8fcf16a32eb", + "b53ce4da1aa7c0dc77a1896ab716b921499aed78df725b1504aba1597ba0c64b", + "542c40a18140a6266d6f0286e24e9a7bad7650e72ef0e2131e629c076d962663", + }; + + char *S[] = { + "8bf77819ca05a6b2786c76262bf7371cef97b218e96f175a3ccdda2acc058903", + "1b766e9ceb71ba6c01dcd46e0af462cd4cfa652ae5017d4555b8eeefe36e1932", + "ee59d81bc9db1055cc0ed97b159d8784af04e98511d0a9a407b99bb292572e96", + "b46d9f2d8c4bf83546ff178f1d78937c008d64e8ecc5cbb825cb21d94d670d89", + "77c68928ac3b88d985fb43fb615fb7ff45c18ba5c81af796c613dfa98352d29c", + "d18c2caf3b1072f87064ec5e8953f51301cada03469c640244760328eb5a05cb", + "84a58f9e9d9e735344b316b1aa1ab5185665b85147dc82d92e969d7bee31ca30", + "d7f9ddd191f1f412869429209ee3814c75c72fa46a9cccf804a2f5cc0b7e739f", + "f5413bfd85949da8d83de83ab0d19b2986613e224d1901d76919de23ccd03199", + "880e0bbf82a8cf818ed46ba03cf0fc6c898e36fca36cc7fdb1d2db7503634430", + "2bf3a80bc04faa35ebecc0f4864ac02d349f6f126e0f988501b8d3075409a26c", + "644300fc0da4d40fb8c6ead510d14f0bd4e1321a469e9c0a581464c7186b7aa7", + "9ae6ba6d637706849a6a9fc388cf0232d85c26ea0d1fe7437adb48de58364333", + "d7c246dc7ad0e67700c373edcfdd1c0a0495fc954549ad579df6ed1438840851", + "4f7f65305e24a6bbb5cff714ba8f5a2cee5bdc89ba8d75dcbf21966ce38eb66f", + }; + + struct tc_sha256_state_struct sha256_ctx; + + TC_PRINT("Test #1: ECDSAsign "); + TC_PRINT("NIST-p256, SHA2-256\n"); + + return sign_vectors(&sha256_ctx, d, k, Msg, Qx, Qy, R, S, 15, verbose); +} + +int vrfy_vectors(TCSha256State_t hash, char **msg_vec, char **qx_vec, char **qy_vec, + char **r_vec, char **s_vec, char **res_vec, int tests, bool verbose) +{ + + const struct uECC_Curve_t * curve = uECC_secp256r1(); + unsigned int pub[2 * NUM_ECC_WORDS]; + uint8_t pub_bytes[2 * NUM_ECC_BYTES]; + unsigned int sig[2 * NUM_ECC_WORDS]; + uint8_t sig_bytes[2 * NUM_ECC_BYTES]; + uint8_t digest_bytes[TC_SHA256_DIGEST_SIZE]; + unsigned int digest[TC_SHA256_DIGEST_SIZE / 4]; + unsigned int result = TC_PASS; + + int rc; + int exp_rc; + char tmp; + + uint8_t msg[BUF_SIZE]; + size_t msglen; + + for (int i = 0; i < tests; i++) { + + string2scalar(pub, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qy_vec[i]); + string2scalar(sig, NUM_ECC_WORDS, r_vec[i]); + string2scalar(sig + NUM_ECC_WORDS, NUM_ECC_WORDS, s_vec[i]); + + if (2 != sscanf(res_vec[i], "%c (%d ", &tmp, &exp_rc)) { + TC_ERROR("Error: failed to parse CAVP response.\n"); + result = TC_FAIL; + goto exitTest1; + } + + /* validate ECDSA: hash message, verify r+s */ + msglen = hex2bin(msg, BUF_SIZE, msg_vec[i], strlen(msg_vec[i])); + + if (msglen == false) { + TC_ERROR("failed to import message!\n"); + result = TC_FAIL; + goto exitTest1; + } + + tc_sha256_init(hash); + tc_sha256_update(hash, msg, msglen); + tc_sha256_final(digest_bytes, hash); + + /* if digest larger than ECC scalar, drop the end + * if digest smaller than ECC scalar, zero-pad front */ + int hash_dwords = TC_SHA256_DIGEST_SIZE / 4; + if (NUM_ECC_WORDS < hash_dwords) { + hash_dwords = NUM_ECC_WORDS; + } + + memset(digest, 0, NUM_ECC_BYTES - 4 * hash_dwords); + uECC_vli_bytesToNative(digest + (NUM_ECC_WORDS-hash_dwords), digest_bytes, + TC_SHA256_DIGEST_SIZE); + + uECC_vli_nativeToBytes(pub_bytes, NUM_ECC_BYTES, pub); + uECC_vli_nativeToBytes(pub_bytes + NUM_ECC_BYTES, NUM_ECC_BYTES, + pub + NUM_ECC_WORDS); + + /* adapt return codes to match CAVP error: */ + if (0 != uECC_valid_public_key(pub_bytes, curve)) { + /* error 4 - Q changed */ + rc = 4; + } else { + uECC_vli_nativeToBytes(sig_bytes, NUM_ECC_BYTES, sig); + uECC_vli_nativeToBytes(sig_bytes + NUM_ECC_BYTES, NUM_ECC_BYTES, + sig + NUM_ECC_WORDS); + + rc = uECC_verify(pub_bytes, digest_bytes, sizeof(digest_bytes), sig_bytes, + uECC_secp256r1()); + /* CAVP expects 0 for success, others for fail */ + rc = !rc; + if (exp_rc != 0 && rc != 0) { + /* mimic CAVP code on errors. */ + rc = exp_rc; + } + } + + result = check_code(i, res_vec[i], exp_rc, rc, verbose); + if(result == TC_FAIL) { + goto exitTest1; + } + } + exitTest1: + TC_END_RESULT(result); + return result; +} + +int cavp_verify(bool verbose) +{ + + /* + * [P-256,SHA-256] + */ + char *Msg[] = { + "e4796db5f785f207aa30d311693b3702821dff1168fd2e04c0836825aefd850d9aa60326d8" + "8cde1a23c7745351392ca2288d632c264f197d05cd424a30336c19fd09bb229654f0222fcb" + "881a4b35c290a093ac159ce13409111ff0358411133c24f5b8e2090d6db6558afc36f06ca1" + "f6ef779785adba68db27a409859fc4c4a0", + "069a6e6b93dfee6df6ef6997cd80dd2182c36653cef10c655d524585655462d683877f95ec" + "c6d6c81623d8fac4e900ed0019964094e7de91f1481989ae1873004565789cbf5dc56c62ae" + "dc63f62f3b894c9c6f7788c8ecaadc9bd0e81ad91b2b3569ea12260e93924fdddd3972af52" + "73198f5efda0746219475017557616170e", + "df04a346cf4d0e331a6db78cca2d456d31b0a000aa51441defdb97bbeb20b94d8d746429a3" + "93ba88840d661615e07def615a342abedfa4ce912e562af714959896858af817317a840dcf" + "f85a057bb91a3c2bf90105500362754a6dd321cdd86128cfc5f04667b57aa78c112411e42d" + "a304f1012d48cd6a7052d7de44ebcc01de", + "e1130af6a38ccb412a9c8d13e15dbfc9e69a16385af3c3f1e5da954fd5e7c45fd75e2b8c36" + "699228e92840c0562fbf3772f07e17f1add56588dd45f7450e1217ad239922dd9c32695dc7" + "1ff2424ca0dec1321aa47064a044b7fe3c2b97d03ce470a592304c5ef21eed9f93da56bb23" + "2d1eeb0035f9bf0dfafdcc4606272b20a3", + "73c5f6a67456ae48209b5f85d1e7de7758bf235300c6ae2bdceb1dcb27a7730fb68c950b7f" + "cada0ecc4661d3578230f225a875e69aaa17f1e71c6be5c831f22663bac63d0c7a9635edb0" + "043ff8c6f26470f02a7bc56556f1437f06dfa27b487a6c4290d8bad38d4879b334e341ba09" + "2dde4e4ae694a9c09302e2dbf443581c08", + "666036d9b4a2426ed6585a4e0fd931a8761451d29ab04bd7dc6d0c5b9e38e6c2b263ff6cb8" + "37bd04399de3d757c6c7005f6d7a987063cf6d7e8cb38a4bf0d74a282572bd01d0f41e3fd0" + "66e3021575f0fa04f27b700d5b7ddddf50965993c3f9c7118ed78888da7cb221849b326059" + "2b8e632d7c51e935a0ceae15207bedd548", + "7e80436bce57339ce8da1b5660149a20240b146d108deef3ec5da4ae256f8f894edcbbc57b" + "34ce37089c0daa17f0c46cd82b5a1599314fd79d2fd2f446bd5a25b8e32fcf05b76d644573" + "a6df4ad1dfea707b479d97237a346f1ec632ea5660efb57e8717a8628d7f82af50a4e84b11" + "f21bdff6839196a880ae20b2a0918d58cd", + "1669bfb657fdc62c3ddd63269787fc1c969f1850fb04c933dda063ef74a56ce13e3a649700" + "820f0061efabf849a85d474326c8a541d99830eea8131eaea584f22d88c353965dabcdc4bf" + "6b55949fd529507dfb803ab6b480cd73ca0ba00ca19c438849e2cea262a1c57d8f81cd257f" + "b58e19dec7904da97d8386e87b84948169", + "3fe60dd9ad6caccf5a6f583b3ae65953563446c4510b70da115ffaa0ba04c076115c7043ab" + "8733403cd69c7d14c212c655c07b43a7c71b9a4cffe22c2684788ec6870dc2013f269172c8" + "22256f9e7cc674791bf2d8486c0f5684283e1649576efc982ede17c7b74b214754d70402fb" + "4bb45ad086cf2cf76b3d63f7fce39ac970", + "983a71b9994d95e876d84d28946a041f8f0a3f544cfcc055496580f1dfd4e312a2ad418fe6" + "9dbc61db230cc0c0ed97e360abab7d6ff4b81ee970a7e97466acfd9644f828ffec538abc38" + "3d0e92326d1c88c55e1f46a668a039beaa1be631a89129938c00a81a3ae46d4aecbf9707f7" + "64dbaccea3ef7665e4c4307fa0b0a3075c", + "4a8c071ac4fd0d52faa407b0fe5dab759f7394a5832127f2a3498f34aac287339e043b4ffa" + "79528faf199dc917f7b066ad65505dab0e11e6948515052ce20cfdb892ffb8aa9bf3f1aa5b" + "e30a5bbe85823bddf70b39fd7ebd4a93a2f75472c1d4f606247a9821f1a8c45a6cb80545de" + "2e0c6c0174e2392088c754e9c8443eb5af", + "0a3a12c3084c865daf1d302c78215d39bfe0b8bf28272b3c0b74beb4b7409db0718239de70" + "0785581514321c6440a4bbaea4c76fa47401e151e68cb6c29017f0bce4631290af5ea5e2bf" + "3ed742ae110b04ade83a5dbd7358f29a85938e23d87ac8233072b79c94670ff0959f9c7f45" + "17862ff829452096c78f5f2e9a7e4e9216", + "785d07a3c54f63dca11f5d1a5f496ee2c2f9288e55007e666c78b007d95cc28581dce51f49" + "0b30fa73dc9e2d45d075d7e3a95fb8a9e1465ad191904124160b7c60fa720ef4ef1c5d2998" + "f40570ae2a870ef3e894c2bc617d8a1dc85c3c55774928c38789b4e661349d3f84d2441a3b" + "856a76949b9f1f80bc161648a1cad5588e", + "76f987ec5448dd72219bd30bf6b66b0775c80b394851a43ff1f537f140a6e7229ef8cd72ad" + "58b1d2d20298539d6347dd5598812bc65323aceaf05228f738b5ad3e8d9fe4100fd767c2f0" + "98c77cb99c2992843ba3eed91d32444f3b6db6cd212dd4e5609548f4bb62812a920f6e2bf1" + "581be1ebeebdd06ec4e971862cc42055ca", + "60cd64b2cd2be6c33859b94875120361a24085f3765cb8b2bf11e026fa9d8855dbe435acf7" + "882e84f3c7857f96e2baab4d9afe4588e4a82e17a78827bfdb5ddbd1c211fbc2e6d884cddd" + "7cb9d90d5bf4a7311b83f352508033812c776a0e00c003c7e0d628e50736c7512df0acfa9f" + "2320bd102229f46495ae6d0857cc452a84", + }; + + char *Qx[] = { + "87f8f2b218f49845f6f10eec3877136269f5c1a54736dbdf69f89940cad41555", + "5cf02a00d205bdfee2016f7421807fc38ae69e6b7ccd064ee689fc1a94a9f7d2", + "2ddfd145767883ffbb0ac003ab4a44346d08fa2570b3120dcce94562422244cb", + "e424dc61d4bb3cb7ef4344a7f8957a0c5134e16f7a67c074f82e6e12f49abf3c", + "e0fc6a6f50e1c57475673ee54e3a57f9a49f3328e743bf52f335e3eeaa3d2864", + "a849bef575cac3c6920fbce675c3b787136209f855de19ffe2e8d29b31a5ad86", + "3dfb6f40f2471b29b77fdccba72d37c21bba019efa40c1c8f91ec405d7dcc5df", + "69b7667056e1e11d6caf6e45643f8b21e7a4bebda463c7fdbc13bc98efbd0214", + "bf02cbcf6d8cc26e91766d8af0b164fc5968535e84c158eb3bc4e2d79c3cc682", + "224a4d65b958f6d6afb2904863efd2a734b31798884801fcab5a590f4d6da9de", + "43691c7795a57ead8c5c68536fe934538d46f12889680a9cb6d055a066228369", + "9157dbfcf8cf385f5bb1568ad5c6e2a8652ba6dfc63bc1753edf5268cb7eb596", + "072b10c081a4c1713a294f248aef850e297991aca47fa96a7470abe3b8acfdda", + "09308ea5bfad6e5adf408634b3d5ce9240d35442f7fe116452aaec0d25be8c24", + "2d98ea01f754d34bbc3003df5050200abf445ec728556d7ed7d5c54c55552b6d", + }; + + char *Qy[] = { + "e15f369036f49842fac7a86c8a2b0557609776814448b8f5e84aa9f4395205e9", + "ec530ce3cc5c9d1af463f264d685afe2b4db4b5828d7e61b748930f3ce622a85", + "5f70c7d11ac2b7a435ccfbbae02c3df1ea6b532cc0e9db74f93fffca7c6f9a64", + "970eed7aa2bc48651545949de1dddaf0127e5965ac85d1243d6f60e7dfaee927", + "7f59d689c91e463607d9194d99faf316e25432870816dde63f5d4b373f12f22a", + "bf5fe4f7858f9b805bd8dcc05ad5e7fb889de2f822f3d8b41694e6c55c16b471", + "f22f953f1e395a52ead7f3ae3fc47451b438117b1e04d613bc8555b7d6e6d1bb", + "d3f9b12eb46c7c6fda0da3fc85bc1fd831557f9abc902a3be3cb3e8be7d1aa2f", + "069ba6cb06b49d60812066afa16ecf7b51352f2c03bd93ec220822b1f3dfba03", + "178d51fddada62806f097aa615d33b8f2404e6b1479f5fd4859d595734d6d2b9", + "f8790110b3c3b281aa1eae037d4f1234aff587d903d93ba3af225c27ddc9ccac", + "972570f4313d47fc96f7c02d5594d77d46f91e949808825b3d31f029e8296405", + "9581145cca04a0fb94cedce752c8f0370861916d2a94e7c647c5373ce6a4c8f5", + "f40c93e023ef494b1c3079b2d10ef67f3170740495ce2cc57f8ee4b0618b8ee5", + "9b52672742d637a32add056dfd6d8792f2a33c2e69dafabea09b960bc61e230a", + }; + + char *R[] = { + "d19ff48b324915576416097d2544f7cbdf8768b1454ad20e0baac50e211f23b0", + "dc23d130c6117fb5751201455e99f36f59aba1a6a21cf2d0e7481a97451d6693", + "9913111cff6f20c5bf453a99cd2c2019a4e749a49724a08774d14e4c113edda8", + "bf96b99aa49c705c910be33142017c642ff540c76349b9dab72f981fd9347f4f", + "1d75830cd36f4c9aa181b2c4221e87f176b7f05b7c87824e82e396c88315c407", + "25acc3aa9d9e84c7abf08f73fa4195acc506491d6fc37cb9074528a7db87b9d6", + "548886278e5ec26bed811dbb72db1e154b6f17be70deb1b210107decb1ec2a5a", + "288f7a1cd391842cce21f00e6f15471c04dc182fe4b14d92dc18910879799790", + "f5acb06c59c2b4927fb852faa07faf4b1852bbb5d06840935e849c4d293d1bad", + "87b93ee2fecfda54deb8dff8e426f3c72c8864991f8ec2b3205bb3b416de93d2", + "8acd62e8c262fa50dd9840480969f4ef70f218ebf8ef9584f199031132c6b1ce", + "dfaea6f297fa320b707866125c2a7d5d515b51a503bee817de9faa343cc48eeb", + "09f5483eccec80f9d104815a1be9cc1a8e5b12b6eb482a65c6907b7480cf4f19", + "5cc8aa7c35743ec0c23dde88dabd5e4fcd0192d2116f6926fef788cddb754e73", + "06108e525f845d0155bf60193222b3219c98e3d49424c2fb2a0987f825c17959", + }; + + char *Result[] = { + "F (3 - S changed)", "F (2 - R changed)", "F (4 - Q changed)", + "P (0 )", "P (0 )", "F (2 - R changed)", + "F (4 - Q changed)", "F (1 - Message changed)", "F (3 - S changed)", + "F (2 - R changed)", "F (3 - S changed)", "F (1 - Message changed)", + "F (4 - Q changed)", "F (1 - Message changed)", "P (0 )", + }; + + char *S[] = { + "a3e81e59311cdfff2d4784949f7a2cb50ba6c3a91fa54710568e61aca3e847c6", + "d6ce7708c18dbf35d4f8aa7240922dc6823f2e7058cbc1484fcad1599db5018c", + "9467cd4cd21ecb56b0cab0a9a453b43386845459127a952421f5c6382866c5cc", + "17c55095819089c2e03b9cd415abdf12444e323075d98f31920b9e0f57ec871c", + "cb2acb01dac96efc53a32d4a0d85d0c2e48955214783ecf50a4f0414a319c05a", + "9b21d5b5259ed3f2ef07dfec6cc90d3a37855d1ce122a85ba6a333f307d31537", + "e93bfebd2f14f3d827ca32b464be6e69187f5edbd52def4f96599c37d58eee75", + "247b3c4e89a3bcadfea73c7bfd361def43715fa382b8c3edf4ae15d6e55e9979", + "049dab79c89cc02f1484c437f523e080a75f134917fda752f2d5ca397addfe5d", + "4044a24df85be0cc76f21a4430b75b8e77b932a87f51e4eccbc45c263ebf8f66", + "cfca7ed3d4347fb2a29e526b43c348ae1ce6c60d44f3191b6d8ea3a2d9c92154", + "8f780ad713f9c3e5a4f7fa4c519833dfefc6a7432389b1e4af463961f09764f2", + "a4f90e560c5e4eb8696cb276e5165b6a9d486345dedfb094a76e8442d026378d", + "9c9c045ebaa1b828c32f82ace0d18daebf5e156eb7cbfdc1eff4399a8a900ae7", + "62b5cdd591e5b507e560167ba8f6f7cda74673eb315680cb89ccbc4eec477dce", + }; + + struct tc_sha256_state_struct sha256_ctx; + + printf("Test #2: ECDSAvrfy "); + printf("NIST-p256, SHA2-256\n"); + + return vrfy_vectors(&sha256_ctx, Msg, Qx, Qy, R, S, Result, 15, verbose); +} + +int montecarlo_signverify(int num_tests, bool verbose) +{ + printf("Test #3: Monte Carlo (%d Randomized EC-DSA signatures) ", num_tests); + printf("NIST-p256, SHA2-256\n "); + int i; + uint8_t private[NUM_ECC_BYTES]; + uint8_t public[2*NUM_ECC_BYTES]; + uint8_t hash[NUM_ECC_BYTES]; + unsigned int hash_words[NUM_ECC_WORDS]; + uint8_t sig[2*NUM_ECC_BYTES]; + + const struct uECC_Curve_t * curve = uECC_secp256r1(); + + for (i = 0; i < num_tests; ++i) { + if (verbose) { + TC_PRINT("."); + fflush(stdout); + } + + uECC_generate_random_int(hash_words, curve->n, BITS_TO_WORDS(curve->num_n_bits)); + uECC_vli_nativeToBytes(hash, NUM_ECC_BYTES, hash_words); + + if (!uECC_make_key(public, private, curve)) { + TC_ERROR("uECC_make_key() failed\n"); + return TC_FAIL; + } + + if (!uECC_sign(private, hash, sizeof(hash), sig, curve)) { + TC_ERROR("uECC_sign() failed\n"); + return TC_FAIL; + } + + if (!uECC_verify(public, hash, sizeof(hash), sig, curve)) { + TC_ERROR("uECC_verify() failed\n"); + return TC_FAIL; + } + if (verbose) { + fflush(stdout); + printf("."); + } + } + TC_PRINT("\n"); + return TC_PASS; +} + +int main() +{ + unsigned int result = TC_PASS; + + TC_START("Performing ECC-DSA tests:"); + /* Setup of the Cryptographically Secure PRNG. */ + uECC_set_rng(&default_CSPRNG); + + bool verbose = true; + + TC_PRINT("Performing cavp_sign test:\n"); + result = cavp_sign(verbose); + if (result == TC_FAIL) { /* terminate test */ + TC_ERROR("cavp_sign test failed.\n"); + goto exitTest; + } + TC_PRINT("Performing cavp_verify test:\n"); + result = cavp_verify(verbose); + if (result == TC_FAIL) { + TC_ERROR("cavp_verify test failed.\n"); + goto exitTest; + } + TC_PRINT("Performing montecarlo_signverify test:\n"); + result = montecarlo_signverify(10, verbose); + if (result == TC_FAIL) { + TC_ERROR("montecarlo_signverify test failed.\n"); + goto exitTest; + } + + TC_PRINT("\nAll ECC-DSA tests succeeded.\n"); + + exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/tinycrypt/tests/test_ecc_utils.c b/tinycrypt/tests/test_ecc_utils.c new file mode 100644 index 00000000..35003312 --- /dev/null +++ b/tinycrypt/tests/test_ecc_utils.c @@ -0,0 +1,271 @@ +/* test_ecc_utils.c - TinyCrypt common functions for ECC tests */ + +/* Copyright (c) 2014, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.*/ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + * test_ecc_utils.c -- Implementation of some common functions for ECC tests. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +int hex2int (char hex) +{ + uint8_t dec; + + if ('0' <= hex && hex <= '9') dec = hex - '0'; + else if ('a' <= hex && hex <= 'f') dec = hex - 'a' + 10; + else if ('A' <= hex && hex <= 'F') dec = hex - 'A' + 10; + else return -1; + + return dec; +} + +/* + * Convert hex string to byte string + * Return number of bytes written to buf, or 0 on error + */ +int hex2bin(uint8_t *buf, const size_t buflen, const char *hex, + const size_t hexlen) +{ + + int dec; + + if (buflen < hexlen / 2 + hexlen % 2) + { + return false; + } + + /* if hexlen is uneven, insert leading zero nibble */ + if (hexlen % 2) + { + dec = hex2int(hex[0]); + if (dec == -1) + return false; + buf[0] = dec; + buf++; + hex++; + } + + /* regular hex conversion */ + for (size_t i = 0; i < hexlen / 2; i++) + { + dec = hex2int(hex[2 * i]); + if (dec == -1) + { + return false; + } + buf[i] = dec << 4; + + dec = hex2int(hex[ 2 * i + 1]); + if (dec == -1) + { + return false; + } + buf[i] += dec; + } + return hexlen / 2 + hexlen % 2; +} + +/* + * Convert hex string to zero-padded nanoECC scalar + */ +void string2scalar(unsigned int *scalar, unsigned int num_word32, char *str) +{ + + unsigned int num_bytes = 4 * num_word32; + uint8_t tmp[num_bytes]; + size_t hexlen = strlen(str); + + int padding; + + if (0 > (padding = 2 * num_bytes - strlen(str))) + { + printf("Error: 2 * num_bytes(%d) < strlen(hex) (%zu)\n", + 2 * num_bytes, strlen(str)); + exit(-1); + } + + memset(tmp, 0, padding / 2); + + if (false == hex2bin(tmp + padding / 2, num_bytes, str, hexlen)) + { + exit(-1); + } + uECC_vli_bytesToNative(scalar, tmp, num_bytes); + +} + +void vli_print_bytes(uint8_t *vli, unsigned int size) +{ + for(unsigned i = 0; i < size; ++i) + { + printf("%02X ", (unsigned)vli[i]); + } +} + +void print_ecc_scalar(const char *label, const unsigned int * p_vli, + unsigned int num_word32) +{ + unsigned int i; + + if (label) { + printf("%s = { ", label); + } + + for(i = 0; i < num_word32 - 1; ++i) { + printf("0x%08lX, ", (unsigned long)p_vli[i]); + } + printf("0x%08lX", (unsigned long)p_vli[i]); + + if (label) { + printf(" };\n"); + } +} + +int check_ecc_result(const int num, const char *name, + const unsigned int *expected, + const unsigned int *computed, + const unsigned int num_word32, const bool verbose) +{ + uint32_t num_bytes = 4 * num_word32; + if (memcmp(computed, expected, num_bytes)) { + TC_PRINT("\n Vector #%02d check %s - FAILURE:\n\n", num, name); + print_ecc_scalar("Expected", expected, num_word32); + print_ecc_scalar("Computed", computed, num_word32); + TC_PRINT("\n"); + return TC_FAIL; + } + if (verbose) { + TC_PRINT(" Vector #%02d check %s - success\n", num, name); + } + return TC_PASS; +} + +int check_code(const int num, const char *name, const int expected, + const int computed, const int verbose) +{ + + if (expected != computed) { + TC_ERROR("\n Vector #%02d check %s - FAILURE:\n", num, name); + TC_ERROR("\n Expected: %d, computed: %d\n\n", expected, computed); + return TC_FAIL; + } + + if (verbose) { + TC_PRINT(" Vector #%02d check %s - success (%d=%d)\n", num, name, + expected, computed); + } + + return TC_PASS; +} + +/* Test ecc_make_keys, and also as keygen part of other tests */ +int keygen_vectors(char **d_vec, char **qx_vec, char **qy_vec, int tests, + bool verbose) +{ + + unsigned int pub[2 * NUM_ECC_WORDS]; + unsigned int d[NUM_ECC_WORDS]; + unsigned int prv[NUM_ECC_WORDS]; + unsigned int result = TC_PASS; + + /* expected outputs (converted input vectors) */ + unsigned int exp_pub[2 * NUM_ECC_WORDS]; + unsigned int exp_prv[NUM_ECC_WORDS]; + + for (int i = 0; i < tests; i++) { + string2scalar(exp_prv, NUM_ECC_WORDS, d_vec[i]); + string2scalar(exp_pub, NUM_ECC_WORDS, qx_vec[i]); + string2scalar(exp_pub + NUM_ECC_WORDS, NUM_ECC_WORDS, qy_vec[i]); + + /* + * Feed prvkey vector as padded random seed into ecc_make_key. + * Internal mod-reduction will be zero-op and generate correct prv/pub + */ + memset(d, 0, sizeof(d)); + string2scalar(d, NUM_ECC_WORDS, d_vec[i]); + + uint8_t pub_bytes[2*NUM_ECC_BYTES]; + uint8_t prv_bytes[NUM_ECC_BYTES]; + + uECC_make_key_with_d(pub_bytes, prv_bytes, d, uECC_secp256r1()); + + uECC_vli_bytesToNative(prv, prv_bytes, NUM_ECC_BYTES); + uECC_vli_bytesToNative(pub, pub_bytes, NUM_ECC_BYTES); + uECC_vli_bytesToNative(pub + NUM_ECC_WORDS, pub_bytes + NUM_ECC_BYTES, NUM_ECC_BYTES); + + /* validate correctness of vector conversion and make_key() */ + result = check_ecc_result(i, "prv ", exp_prv, prv, NUM_ECC_WORDS, verbose); + if (result == TC_FAIL) { + return result; + } + result = check_ecc_result(i, "pub.x", exp_pub, pub, NUM_ECC_WORDS, verbose); + if (result == TC_FAIL) { + return result; + } + result = check_ecc_result(i, "pub.y", exp_pub + NUM_ECC_WORDS, pub + NUM_ECC_WORDS, NUM_ECC_WORDS, verbose); + if (result == TC_FAIL) { + return result; + } + } + return result; +} diff --git a/tinycrypt/tests/test_hmac.c b/tinycrypt/tests/test_hmac.c new file mode 100644 index 00000000..a41275e6 --- /dev/null +++ b/tinycrypt/tests/test_hmac.c @@ -0,0 +1,362 @@ +/* test_hmac.c - TinyCrypt implementation of some HMAC tests */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + DESCRIPTION + This module tests the following HMAC routines: + + Scenarios tested include: + - HMAC tests (RFC 4231 test vectors) +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +unsigned int do_hmac_test(TCHmacState_t h, unsigned int testnum, const uint8_t *data, + size_t datalen, const uint8_t *expected, + size_t expectedlen) +{ + uint8_t digest[32]; + unsigned int result = TC_PASS; + + (void)tc_hmac_init(h); + (void)tc_hmac_update(h, data, datalen); + (void)tc_hmac_final(digest, TC_SHA256_DIGEST_SIZE, h); + result = check_result(testnum, expected, expectedlen, + digest, sizeof(digest)); + return result; +} + +/* + * NIST test vectors for encryption. + */ +unsigned int test_1(void) +{ + unsigned int result = TC_PASS; + + TC_PRINT("HMAC %s:\n", __func__); + + const uint8_t key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b + }; + const uint8_t data[8] = { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 + }; + const uint8_t expected[32] = { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, + 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + result = do_hmac_test(&h, 1, data, sizeof(data),expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_2(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[4] = { + 0x4a, 0x65, 0x66, 0x65 + }; + const uint8_t data[28] = { + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, + 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f + }; + const uint8_t expected[32] = { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, + 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + + result = do_hmac_test(&h, 2, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_3(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[20] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }; + const uint8_t data[50] = { + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd + }; + const uint8_t expected[32] = { + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, + 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, + 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + + result = do_hmac_test(&h, 3, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_4(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + + const uint8_t key[25] = { + 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 + }; + const uint8_t data[50] = { + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd + }; + const uint8_t expected[32] = { + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, + 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, + 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + + result = do_hmac_test(&h, 4, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_5(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[20] = { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c + }; + const uint8_t data[20] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, 0x68, 0x20, 0x54, 0x72, + 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e + }; + const uint8_t expected[32] = { + 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, 0x6e, 0x0c, 0x79, 0x6c, + 0x29, 0x55, 0x55, 0x2b, 0xfa, 0x6f, 0x7c, 0x0a, 0x6a, 0x8a, 0xef, 0x8b, + 0x93, 0xf8, 0x60, 0xaa, 0xb0, 0xcd, 0x20, 0xc5 + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + + result = do_hmac_test(&h, 5, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_6(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[131] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }; + const uint8_t data[54] = { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, + 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 + }; + const uint8_t expected[32] = { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, + 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + + result = do_hmac_test(&h, 6, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_7(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("HMAC %s:\n", __func__); + const uint8_t key[131] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa + }; + const uint8_t data[152] = { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e + }; + const uint8_t expected[32] = { + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, + 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 + }; + struct tc_hmac_state_struct h; + + (void)memset(&h, 0x00, sizeof(h)); + (void)tc_hmac_set_key(&h, key, sizeof(key)); + + result = do_hmac_test(&h, 7, data, sizeof(data), expected, + sizeof(expected)); + TC_END_RESULT(result); + return result; +} + +/* + * Main task to test AES + */ +int main(void) +{ + unsigned int result = TC_PASS; + + TC_START("Performing HMAC tests (RFC4231 test vectors):"); + + result = test_1(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #1 failed.\n"); + goto exitTest; + } + result = test_2(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #2 failed.\n"); + goto exitTest; + } + result = test_3(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #3 failed.\n"); + goto exitTest; + } + result = test_4(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #4 failed.\n"); + goto exitTest; + } + result = test_5(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #5 failed.\n"); + goto exitTest; + } + result = test_6(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC #6 test failed.\n"); + goto exitTest; + } + result = test_7(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #7 failed.\n"); + goto exitTest; + } + + TC_PRINT("All HMAC tests succeeded!\n"); + +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/tinycrypt/tests/test_hmac_prng.c b/tinycrypt/tests/test_hmac_prng.c new file mode 100644 index 00000000..a2533426 --- /dev/null +++ b/tinycrypt/tests/test_hmac_prng.c @@ -0,0 +1,7434 @@ +/* test_hmac_prng.c - TinyCrypt implementation of some HMAC-PRNG tests */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + DESCRIPTION + This module tests the following PRNG routines: + + Scenarios tested include: + - HMAC-PRNG init + - HMAC-PRNG reseed + - HMAC-PRNG generate) +*/ + +#include +#include +#include + +#include + +struct hmac_prng_test_vector { + uint8_t entropyinputlen; + uint8_t noncelen; + uint8_t personalizationstringlen; + uint8_t additionalinputlen; + uint8_t returnedbitslen; + uint8_t entropyinput[32]; + uint8_t nonce[16]; + uint8_t personalizationstring[32]; + uint8_t entropyinputreseed[32]; + uint8_t additionalinputreseed[32]; + uint8_t returnedbits[128]; +}; + +unsigned int do_hmac_prng_pr_false_test(unsigned int testnum, const struct + hmac_prng_test_vector *vec) +{ + struct tc_hmac_prng_struct h; + uint8_t random[128]; + uint32_t seed_material_size; + uint8_t seed_material[32 + 16 + 32]; /*entropyinput || nonce || personalizationstring */ + unsigned int result = TC_PASS; + + uint8_t *p = seed_material; + + memset(&h, 0x0, sizeof(h)); + + if (vec->entropyinputlen > 0) { + memcpy(p, vec->entropyinput, vec->entropyinputlen); + p += vec->entropyinputlen; + } + + if (vec->noncelen > 0) { + memcpy(p, vec->nonce, vec->noncelen); + p += vec->noncelen; + } + + if (vec->personalizationstringlen > 0) { + memcpy(p, vec->personalizationstring, vec->personalizationstringlen); + } + + seed_material_size = vec->entropyinputlen + vec->noncelen + vec->personalizationstringlen; + (void)tc_hmac_prng_init(&h, seed_material, seed_material_size); + (void)tc_hmac_prng_reseed(&h, vec->entropyinputreseed, vec->entropyinputlen, 0, 0); + (void)tc_hmac_prng_generate(random, vec->returnedbitslen, &h); + (void)tc_hmac_prng_generate(random, vec->returnedbitslen, &h); + result = check_result(testnum, vec->returnedbits, vec->returnedbitslen, random, vec->returnedbitslen); + return result; +} + +unsigned int test_1(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x06, 0x03, 0x2c, 0xd5, 0xee, 0xd3, 0x3f, 0x39, 0x26, 0x5f, 0x49, 0xec, + 0xb1, 0x42, 0xc5, 0x11, 0xda, 0x9a, 0xff, 0x2a, 0xf7, 0x12, 0x03, 0xbf, + 0xfa, 0xf3, 0x4a, 0x9c, 0xa5, 0xbd, 0x9c, 0x0d, + }, + { + 0x0e, 0x66, 0xf7, 0x1e, 0xdc, 0x43, 0xe4, 0x2a, 0x45, 0xad, 0x3c, 0x6f, + 0xc6, 0xcd, 0xc4, 0xdf, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x01, 0x92, 0x0a, 0x4e, 0x66, 0x9e, 0xd3, 0xa8, 0x5a, 0xe8, 0xa3, 0x3b, + 0x35, 0xa7, 0x4a, 0xd7, 0xfb, 0x2a, 0x6b, 0xb4, 0xcf, 0x39, 0x5c, 0xe0, + 0x03, 0x34, 0xa9, 0xc9, 0xa5, 0xa5, 0xd5, 0x52, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x76, 0xfc, 0x79, 0xfe, 0x9b, 0x50, 0xbe, 0xcc, 0xc9, 0x91, 0xa1, 0x1b, + 0x56, 0x35, 0x78, 0x3a, 0x83, 0x53, 0x6a, 0xdd, 0x03, 0xc1, 0x57, 0xfb, + 0x30, 0x64, 0x5e, 0x61, 0x1c, 0x28, 0x98, 0xbb, 0x2b, 0x1b, 0xc2, 0x15, + 0x00, 0x02, 0x09, 0x20, 0x8c, 0xd5, 0x06, 0xcb, 0x28, 0xda, 0x2a, 0x51, + 0xbd, 0xb0, 0x38, 0x26, 0xaa, 0xf2, 0xbd, 0x23, 0x35, 0xd5, 0x76, 0xd5, + 0x19, 0x16, 0x08, 0x42, 0xe7, 0x15, 0x8a, 0xd0, 0x94, 0x9d, 0x1a, 0x9e, + 0xc3, 0xe6, 0x6e, 0xa1, 0xb1, 0xa0, 0x64, 0xb0, 0x05, 0xde, 0x91, 0x4e, + 0xac, 0x2e, 0x9d, 0x4f, 0x2d, 0x72, 0xa8, 0x61, 0x6a, 0x80, 0x22, 0x54, + 0x22, 0x91, 0x82, 0x50, 0xff, 0x66, 0xa4, 0x1b, 0xd2, 0xf8, 0x64, 0xa6, + 0xa3, 0x8c, 0xc5, 0xb6, 0x49, 0x9d, 0xc4, 0x3f, 0x7f, 0x2b, 0xd0, 0x9e, + 0x1e, 0x0f, 0x8f, 0x58, 0x85, 0x93, 0x51, 0x24, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(1, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_2(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xaa, 0xdc, 0xf3, 0x37, 0x78, 0x8b, 0xb8, 0xac, 0x01, 0x97, 0x66, 0x40, + 0x72, 0x6b, 0xc5, 0x16, 0x35, 0xd4, 0x17, 0x77, 0x7f, 0xe6, 0x93, 0x9e, + 0xde, 0xd9, 0xcc, 0xc8, 0xa3, 0x78, 0xc7, 0x6a, + }, + { + 0x9c, 0xcc, 0x9d, 0x80, 0xc8, 0x9a, 0xc5, 0x5a, 0x8c, 0xfe, 0x0f, 0x99, + 0x94, 0x2f, 0x5a, 0x4d, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x03, 0xa5, 0x77, 0x92, 0x54, 0x7e, 0x0c, 0x98, 0xea, 0x17, 0x76, 0xe4, + 0xba, 0x80, 0xc0, 0x07, 0x34, 0x62, 0x96, 0xa5, 0x6a, 0x27, 0x0a, 0x35, + 0xfd, 0x9e, 0xa2, 0x84, 0x5c, 0x7e, 0x81, 0xe2, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x17, 0xd0, 0x9f, 0x40, 0xa4, 0x37, 0x71, 0xf4, 0xa2, 0xf0, 0xdb, 0x32, + 0x7d, 0xf6, 0x37, 0xde, 0xa9, 0x72, 0xbf, 0xff, 0x30, 0xc9, 0x8e, 0xbc, + 0x88, 0x42, 0xdc, 0x7a, 0x9e, 0x3d, 0x68, 0x1c, 0x61, 0x90, 0x2f, 0x71, + 0xbf, 0xfa, 0xf5, 0x09, 0x36, 0x07, 0xfb, 0xfb, 0xa9, 0x67, 0x4a, 0x70, + 0xd0, 0x48, 0xe5, 0x62, 0xee, 0x88, 0xf0, 0x27, 0xf6, 0x30, 0xa7, 0x85, + 0x22, 0xec, 0x6f, 0x70, 0x6b, 0xb4, 0x4a, 0xe1, 0x30, 0xe0, 0x5c, 0x8d, + 0x7e, 0xac, 0x66, 0x8b, 0xf6, 0x98, 0x0d, 0x99, 0xb4, 0xc0, 0x24, 0x29, + 0x46, 0x45, 0x23, 0x99, 0xcb, 0x03, 0x2c, 0xc6, 0xf9, 0xfd, 0x96, 0x28, + 0x47, 0x09, 0xbd, 0x2f, 0xa5, 0x65, 0xb9, 0xeb, 0x9f, 0x20, 0x04, 0xbe, + 0x6c, 0x9e, 0xa9, 0xff, 0x91, 0x28, 0xc3, 0xf9, 0x3b, 0x60, 0xdc, 0x30, + 0xc5, 0xfc, 0x85, 0x87, 0xa1, 0x0d, 0xe6, 0x8c, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(2, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_3(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x62, 0xcd, 0xa4, 0x41, 0xdd, 0x80, 0x2c, 0x76, 0x52, 0xc0, 0x0b, 0x99, + 0xca, 0xc3, 0x65, 0x2a, 0x64, 0xfc, 0x75, 0x38, 0x8d, 0xc9, 0xad, 0xcf, + 0x76, 0x35, 0x30, 0xac, 0x31, 0xdf, 0x92, 0x14, + }, + { + 0x5f, 0xdc, 0x89, 0x7a, 0x0c, 0x1c, 0x48, 0x22, 0x04, 0xef, 0x07, 0xe0, + 0x80, 0x5c, 0x01, 0x4b, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xbd, 0x9b, 0xbf, 0x71, 0x74, 0x67, 0xbf, 0x4b, 0x5d, 0xb2, 0xaa, 0x34, + 0x4d, 0xd0, 0xd9, 0x09, 0x97, 0xc8, 0x20, 0x1b, 0x22, 0x65, 0xf4, 0x45, + 0x12, 0x70, 0x12, 0x8f, 0x5a, 0xc0, 0x5a, 0x1a, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x7e, 0x41, 0xf9, 0x64, 0x7a, 0x5e, 0x67, 0x50, 0xeb, 0x8a, 0xcf, 0x13, + 0xa0, 0x2f, 0x23, 0xf3, 0xbe, 0x77, 0x61, 0x1e, 0x51, 0x99, 0x2c, 0xed, + 0xb6, 0x60, 0x2c, 0x31, 0x45, 0x31, 0xaf, 0xf2, 0xa6, 0xe4, 0xc5, 0x57, + 0xda, 0x07, 0x77, 0xd4, 0xe8, 0x5f, 0xae, 0xfc, 0xb1, 0x43, 0xf1, 0xa9, + 0x2e, 0x0d, 0xba, 0xc8, 0xde, 0x8b, 0x88, 0x5c, 0xed, 0x62, 0xa1, 0x24, + 0xf0, 0xb1, 0x06, 0x20, 0xf1, 0x40, 0x9a, 0xe8, 0x7e, 0x22, 0x89, 0x94, + 0xb8, 0x30, 0xec, 0xa6, 0x38, 0xcc, 0xdc, 0xee, 0xdd, 0x3f, 0xcd, 0x07, + 0xd0, 0x24, 0xb6, 0x46, 0x70, 0x4f, 0x44, 0xd5, 0xd9, 0xc4, 0xc3, 0xa7, + 0xb7, 0x05, 0xf3, 0x71, 0x04, 0xb4, 0x5b, 0x9c, 0xfc, 0x2d, 0x93, 0x3a, + 0xe4, 0x3c, 0x12, 0xf5, 0x3e, 0x3e, 0x6f, 0x79, 0x8c, 0x51, 0xbe, 0x5f, + 0x64, 0x01, 0x15, 0xd4, 0x5c, 0xf9, 0x19, 0xa4, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(3, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_4(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x6b, 0xdc, 0x6c, 0xa8, 0xee, 0xf0, 0xe3, 0x53, 0x3a, 0xbd, 0x02, 0x58, + 0x0e, 0xbb, 0xc8, 0xa9, 0x2f, 0x38, 0x2c, 0x5b, 0x1c, 0x8e, 0x3e, 0xaa, + 0x12, 0x56, 0x6e, 0xcf, 0xb9, 0x03, 0x89, 0xa3, + }, + { + 0x8f, 0x84, 0x81, 0xcc, 0x77, 0x35, 0x82, 0x74, 0x77, 0xe0, 0xe4, 0xac, + 0xb7, 0xf4, 0xa0, 0xfa, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x72, 0xec, 0xa6, 0xf1, 0x56, 0x07, 0x20, 0xe6, 0xbd, 0x1f, 0xf0, 0x15, + 0x2c, 0x12, 0xee, 0xff, 0x1f, 0x95, 0x94, 0x62, 0xfd, 0x62, 0xc7, 0x2b, + 0x7d, 0xde, 0x96, 0xab, 0xcb, 0x7f, 0x79, 0xfb, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd5, 0xa2, 0xe2, 0xf2, 0x54, 0xb5, 0xae, 0x65, 0x59, 0x0d, 0x4f, 0xd1, + 0xff, 0x5c, 0x75, 0x8e, 0x42, 0x5b, 0xe4, 0xba, 0xcd, 0xee, 0xde, 0x79, + 0x89, 0x66, 0x9f, 0x0a, 0x22, 0xd3, 0x42, 0x74, 0xfd, 0xfc, 0x2b, 0xf8, + 0x71, 0x35, 0xe3, 0x0a, 0xbd, 0xae, 0x26, 0x91, 0x62, 0x9c, 0x2f, 0x6f, + 0x42, 0x5b, 0xd4, 0xe1, 0x19, 0x90, 0x4d, 0x47, 0x85, 0xec, 0xd9, 0x32, + 0x8f, 0x15, 0x25, 0x95, 0x63, 0xe5, 0xa7, 0x1f, 0x91, 0x5e, 0xc0, 0xc0, + 0x2b, 0x66, 0x65, 0x54, 0x71, 0x06, 0x7b, 0x01, 0x01, 0x6f, 0xdf, 0x93, + 0x4a, 0x47, 0xb0, 0x17, 0xe0, 0x7c, 0x21, 0x33, 0x26, 0x41, 0x40, 0x0b, + 0xbe, 0x57, 0x19, 0x05, 0x0d, 0xba, 0x22, 0xc0, 0x20, 0xb9, 0xb2, 0xd2, + 0xcd, 0xb9, 0x33, 0xdb, 0xc7, 0x0f, 0x76, 0xfe, 0xc4, 0xb1, 0xd8, 0x39, + 0x80, 0xfd, 0x1a, 0x13, 0xc4, 0x56, 0x58, 0x36, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(4, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_5(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x09, 0x6e, 0xf3, 0x72, 0x94, 0xd3, 0x69, 0xfa, 0xce, 0x1a, 0xdd, 0x3e, + 0xb8, 0xb4, 0x25, 0x89, 0x5e, 0x92, 0x16, 0x26, 0x49, 0x57, 0x05, 0xc5, + 0xa0, 0x3e, 0xe5, 0x66, 0xb3, 0x41, 0x58, 0xec, + }, + { + 0x6e, 0x2e, 0x08, 0x25, 0x53, 0x4d, 0x29, 0x89, 0x71, 0x5c, 0xc8, 0x59, + 0x56, 0xe0, 0x14, 0x8d, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x1b, 0x4f, 0x71, 0x25, 0xf4, 0x72, 0xc2, 0x53, 0x83, 0x7f, 0xa7, 0x87, + 0xd5, 0xac, 0xf0, 0x38, 0x2a, 0x3b, 0x89, 0xc3, 0xf4, 0x1c, 0x21, 0x1d, + 0x26, 0x30, 0x52, 0x40, 0x2d, 0xcc, 0x62, 0xc5, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x45, 0x41, 0xf2, 0x4f, 0x75, 0x9b, 0x5f, 0x2a, 0xc2, 0xb5, 0x7b, 0x51, + 0x12, 0x50, 0x77, 0xcc, 0x74, 0x0b, 0x38, 0x59, 0xa7, 0x19, 0xa9, 0xba, + 0xb1, 0x19, 0x6e, 0x6c, 0x0c, 0xa2, 0xbd, 0x05, 0x7a, 0xf9, 0xd3, 0x89, + 0x23, 0x86, 0xa1, 0x81, 0x3f, 0xc8, 0x87, 0x5d, 0x8d, 0x36, 0x4f, 0x15, + 0xe7, 0xfd, 0x69, 0xd1, 0xcc, 0x66, 0x59, 0x47, 0x04, 0x15, 0x27, 0x81, + 0x64, 0xdf, 0x65, 0x62, 0x95, 0xba, 0x9c, 0xfc, 0xee, 0x79, 0xf6, 0xcb, + 0xe2, 0x6e, 0xe1, 0x36, 0xe6, 0xb4, 0x5e, 0xc2, 0x24, 0xad, 0x37, 0x9c, + 0x60, 0x79, 0xb1, 0x0a, 0x2e, 0x0c, 0xb5, 0xf7, 0xf7, 0x85, 0xef, 0x0a, + 0xb7, 0xa7, 0xc3, 0xfc, 0xd9, 0xcb, 0x65, 0x06, 0x05, 0x4d, 0x20, 0xe2, + 0xf3, 0xec, 0x61, 0x0c, 0xbb, 0xa9, 0xb0, 0x45, 0xa2, 0x48, 0xaf, 0x56, + 0xe4, 0xf6, 0xd3, 0xf0, 0xc8, 0xd9, 0x6a, 0x23, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(5, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_6(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xa7, 0xdc, 0xcd, 0xd4, 0x31, 0xae, 0x57, 0x26, 0xb8, 0x35, 0x85, 0xb5, + 0x4e, 0xae, 0x41, 0x08, 0xf7, 0xb7, 0xa2, 0x5c, 0x70, 0x18, 0x7c, 0x0a, + 0xcb, 0xb9, 0x4c, 0x96, 0xcc, 0x27, 0x7a, 0xa8, + }, + { + 0x94, 0xc8, 0xf4, 0xb8, 0xe1, 0x95, 0xa4, 0x73, 0x56, 0xa8, 0x9a, 0x50, + 0xd1, 0x38, 0x9a, 0xb5, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x51, 0x73, 0x3e, 0xee, 0x2e, 0x92, 0x2f, 0x40, 0x55, 0xe5, 0x39, 0x39, + 0xe2, 0x22, 0xe7, 0x1f, 0xae, 0x73, 0x0e, 0xb0, 0x37, 0x44, 0x3d, 0xb2, + 0xc7, 0x67, 0x97, 0x08, 0xab, 0xb8, 0x6a, 0x65, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x99, 0xba, 0x26, 0x91, 0xa6, 0x22, 0xaf, 0xec, 0xc9, 0x47, 0x24, 0x18, + 0xe6, 0xa8, 0xf9, 0xf1, 0xcd, 0xc1, 0xe3, 0x58, 0x3c, 0x3b, 0xc7, 0xa2, + 0xa6, 0x50, 0xa1, 0xab, 0x79, 0xdc, 0xbc, 0xcb, 0xd6, 0x56, 0x63, 0x6c, + 0x57, 0x31, 0x79, 0x27, 0x6e, 0x78, 0x25, 0x69, 0x42, 0x0c, 0x97, 0x43, + 0x8c, 0x06, 0xbe, 0x89, 0x88, 0x67, 0xf6, 0x28, 0xb1, 0xc0, 0x1e, 0xb5, + 0x70, 0x26, 0x3d, 0x2c, 0x0f, 0x09, 0xc7, 0xaa, 0xb5, 0x36, 0xf6, 0xfb, + 0xa7, 0xdf, 0x6a, 0xad, 0x19, 0xe0, 0x5c, 0x23, 0x6b, 0x64, 0x56, 0x74, + 0x66, 0x7c, 0x03, 0xd1, 0xb6, 0xa0, 0x4d, 0x7f, 0xc1, 0x11, 0x77, 0xfe, + 0x78, 0x93, 0x3b, 0x30, 0x96, 0x79, 0xf5, 0xbf, 0x26, 0xa4, 0x63, 0x2b, + 0x9a, 0x13, 0xe3, 0x14, 0xc4, 0xbf, 0x45, 0x32, 0x42, 0x8d, 0x3d, 0x95, + 0xc6, 0x89, 0x00, 0x2b, 0x6d, 0xc1, 0xfb, 0xb1, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(6, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_7(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xc2, 0x86, 0x42, 0x5e, 0xcf, 0x54, 0x3a, 0x49, 0xbc, 0xc9, 0x19, 0x6b, + 0x0d, 0xb1, 0xa8, 0x0b, 0xc5, 0x4e, 0x49, 0x48, 0xad, 0xba, 0x6f, 0x41, + 0x71, 0x2a, 0x35, 0x0a, 0x02, 0x89, 0x1f, 0xa6, + }, + { + 0x95, 0x7a, 0x65, 0x9a, 0x4e, 0xc2, 0xe0, 0xb7, 0xad, 0x18, 0x54, 0x83, + 0xc2, 0x20, 0xfd, 0x61, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x08, 0xc2, 0x12, 0x98, 0x13, 0xee, 0xa0, 0x77, 0x6f, 0xba, 0x72, 0x78, + 0x8f, 0xdf, 0x27, 0x18, 0x75, 0x9c, 0xc3, 0xc4, 0x20, 0x7f, 0xa2, 0x0a, + 0x5f, 0xe2, 0x3a, 0xc6, 0xe3, 0x2c, 0xc2, 0x8e, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8e, 0x10, 0x20, 0xa4, 0xfd, 0x84, 0xc9, 0x9e, 0x0f, 0xc7, 0xe3, 0xf7, + 0xce, 0x48, 0xde, 0x5e, 0xd9, 0xec, 0x9a, 0x5c, 0x2c, 0xcd, 0x62, 0x4d, + 0xbe, 0x6f, 0x30, 0xe2, 0xf6, 0x88, 0xa3, 0x1d, 0xc5, 0x59, 0x57, 0x63, + 0x03, 0x57, 0xa5, 0xd4, 0x8c, 0xa2, 0xa4, 0x56, 0x24, 0x1a, 0x28, 0xbf, + 0xb1, 0x6d, 0x8b, 0xb0, 0x00, 0x87, 0x76, 0x97, 0xa7, 0xce, 0x24, 0xd9, + 0xad, 0x4d, 0x22, 0xb0, 0xc1, 0x51, 0x17, 0x99, 0x6f, 0x1f, 0x27, 0x0b, + 0x94, 0xf4, 0x6d, 0x7a, 0x9b, 0xdf, 0xa7, 0x60, 0x8f, 0xa1, 0xdd, 0x84, + 0x91, 0x77, 0xa9, 0xb8, 0x04, 0x9e, 0x51, 0xb6, 0xb7, 0xa2, 0x74, 0x26, + 0x23, 0x85, 0x4a, 0x1f, 0xdd, 0xb5, 0xef, 0xc4, 0x47, 0xee, 0xd1, 0xea, + 0x1a, 0xed, 0x6f, 0x02, 0xb4, 0xb2, 0x75, 0x4e, 0xcf, 0x71, 0xea, 0x05, + 0x09, 0xda, 0x2e, 0x54, 0xf5, 0x24, 0xa7, 0xe7, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(7, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_8(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x02, 0x81, 0x8b, 0xd7, 0xc1, 0xec, 0x45, 0x6a, 0xce, 0x55, 0xbe, 0xeb, + 0xa9, 0x9f, 0x64, 0x6a, 0x6d, 0x3a, 0xa0, 0xea, 0x78, 0x35, 0x6e, 0xa7, + 0x26, 0xb7, 0x63, 0xff, 0x0d, 0xd2, 0xd6, 0x56, + }, + { + 0xc4, 0x82, 0x68, 0x7d, 0x50, 0x8c, 0x9b, 0x5c, 0x2a, 0x75, 0xf7, 0xce, + 0x39, 0x00, 0x14, 0xe8, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xcf, 0x31, 0x9b, 0xfa, 0x63, 0x98, 0x0e, 0x3c, 0xb9, 0x97, 0xfd, 0x28, + 0x77, 0x1b, 0xb5, 0x61, 0x4e, 0x3a, 0xcb, 0x11, 0x49, 0xba, 0x45, 0xc1, + 0x33, 0xff, 0xbb, 0xab, 0x17, 0x43, 0x31, 0x93, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x19, 0xa2, 0x31, 0xff, 0x26, 0xc1, 0x86, 0x5c, 0xe7, 0x5d, 0x7a, 0x71, + 0x85, 0xc3, 0x0d, 0xd0, 0xb3, 0x33, 0x12, 0x64, 0x33, 0xd0, 0xc8, 0xcb, + 0xf1, 0xbe, 0x0d, 0x2b, 0x38, 0x4d, 0x4e, 0xb3, 0xa8, 0xaf, 0xf0, 0x35, + 0x40, 0xfb, 0xfa, 0x5f, 0x54, 0x96, 0x52, 0x1a, 0x4e, 0x4a, 0x64, 0x07, + 0x1b, 0x44, 0xc7, 0x8b, 0xd0, 0xb7, 0xe6, 0x8f, 0xac, 0x9e, 0x56, 0x95, + 0xc5, 0xc1, 0x3f, 0xd3, 0xb9, 0xdb, 0xe7, 0xf7, 0x73, 0x97, 0x81, 0xa4, + 0xc8, 0xf0, 0xb9, 0x80, 0xf1, 0xb1, 0x7d, 0x99, 0xbc, 0xe1, 0x7c, 0xeb, + 0x52, 0xb5, 0x68, 0x66, 0xae, 0x02, 0x45, 0x6f, 0xfe, 0xf8, 0x33, 0x99, + 0xc8, 0xcf, 0x78, 0x26, 0xf3, 0xc4, 0x5c, 0x8a, 0x19, 0x31, 0x58, 0x90, + 0x91, 0x9d, 0x20, 0xf4, 0x0f, 0xc4, 0xe1, 0x8d, 0x07, 0xe9, 0xc8, 0xcc, + 0xd1, 0x6c, 0x33, 0x27, 0xb5, 0x98, 0x8f, 0x71, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(8, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_9(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x77, 0xa5, 0xc8, 0x6d, 0x99, 0xbe, 0x7b, 0xc2, 0x50, 0x28, 0x70, 0xf4, + 0x02, 0x5f, 0x9f, 0x75, 0x63, 0xe9, 0x17, 0x4e, 0xc6, 0x7c, 0x5f, 0x48, + 0x1f, 0x21, 0xfc, 0xf2, 0xb4, 0x1c, 0xae, 0x4b, + }, + { + 0xed, 0x04, 0x4a, 0xd7, 0x2e, 0xe8, 0x22, 0x50, 0x6a, 0x6d, 0x0b, 0x12, + 0x11, 0x50, 0x29, 0x67, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x77, 0x81, 0x00, 0x74, 0x9f, 0x01, 0xa4, 0xd3, 0x5c, 0x3b, 0x4a, 0x95, + 0x8a, 0xaf, 0xe2, 0x96, 0x87, 0x7e, 0x0a, 0xca, 0xfd, 0x08, 0x9f, 0x50, + 0xbc, 0x77, 0x97, 0xa4, 0x2a, 0x33, 0xab, 0x71, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x83, 0x1a, 0x4d, 0xa5, 0x66, 0xf4, 0x62, 0x89, 0x90, 0x48, 0x93, 0xef, + 0x1c, 0xc1, 0xcd, 0x4a, 0xd1, 0x9e, 0xe4, 0x8f, 0x38, 0x57, 0xe2, 0xb6, + 0x9e, 0x93, 0x6d, 0x10, 0xaf, 0xbd, 0xc2, 0x98, 0x22, 0xe8, 0x5d, 0x02, + 0x66, 0x3d, 0x34, 0x6e, 0xf3, 0xe0, 0x9a, 0x84, 0x8b, 0x1d, 0x9c, 0xc0, + 0x4f, 0x4c, 0x4c, 0x6e, 0x3b, 0x3b, 0x0e, 0x56, 0xa0, 0x34, 0xe2, 0x33, + 0x4d, 0x34, 0xca, 0x08, 0xf8, 0x09, 0x7b, 0xe3, 0x07, 0xba, 0x41, 0xd0, + 0x20, 0xbc, 0x94, 0xf8, 0xc1, 0x93, 0x7f, 0xe8, 0x56, 0x44, 0xee, 0xb5, + 0x59, 0x2c, 0x2b, 0x5a, 0x21, 0x38, 0xf7, 0xde, 0xd9, 0xa5, 0xb4, 0x4b, + 0x20, 0x0c, 0x8b, 0x5b, 0xeb, 0x27, 0x59, 0x7c, 0x79, 0x0f, 0x94, 0xd6, + 0x60, 0xeb, 0x61, 0xe8, 0x24, 0x83, 0x91, 0xed, 0xc3, 0xae, 0x2d, 0x77, + 0x65, 0x6c, 0xbe, 0x83, 0x54, 0x27, 0x5b, 0x13, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(9, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_10(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x0e, 0xa4, 0x58, 0xcf, 0xf8, 0xbf, 0xd1, 0xdd, 0x8b, 0x1a, 0xdd, 0xcb, + 0xa9, 0xc0, 0x13, 0x17, 0xd5, 0x30, 0x39, 0xe5, 0x33, 0x10, 0x4e, 0x32, + 0xf9, 0x6e, 0x7d, 0x34, 0x2e, 0x6c, 0x7b, 0x9b, + }, + { + 0x93, 0x5a, 0x4b, 0x66, 0xfc, 0x74, 0xc2, 0xa4, 0x87, 0x57, 0xa9, 0x9c, + 0x39, 0x9e, 0x64, 0xe3, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x6c, 0x5f, 0x37, 0x08, 0xe7, 0xb7, 0x14, 0xc4, 0xed, 0x13, 0x9b, 0x4f, + 0xa9, 0xe8, 0xc7, 0x63, 0xaf, 0x01, 0x77, 0x34, 0x84, 0x00, 0x51, 0x09, + 0xa8, 0x5e, 0x33, 0x65, 0x3b, 0xb0, 0xce, 0x98, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x37, 0x3a, 0x37, 0xaf, 0x84, 0xfd, 0xde, 0xc1, 0x36, 0x45, 0xa9, 0x76, + 0x8d, 0x6a, 0x78, 0x5a, 0xe5, 0xa2, 0x58, 0x9d, 0x64, 0xcd, 0x9b, 0x37, + 0x98, 0x0d, 0xde, 0x25, 0x41, 0x49, 0x92, 0x10, 0xc4, 0xf4, 0x08, 0x33, + 0x5d, 0xe1, 0xd5, 0x85, 0x34, 0x90, 0x64, 0xf3, 0xf5, 0x3a, 0x2b, 0x4c, + 0x5e, 0xc6, 0xdc, 0x2a, 0x09, 0x59, 0x1f, 0x99, 0xad, 0x9f, 0xad, 0x52, + 0x8a, 0xc8, 0x34, 0x74, 0x16, 0x4b, 0x45, 0x49, 0x7b, 0xf1, 0x67, 0xf8, + 0x1e, 0x66, 0xfa, 0x08, 0x46, 0x3f, 0xfe, 0xa9, 0x17, 0xf6, 0x89, 0x1e, + 0x48, 0xf1, 0x49, 0xfa, 0xfc, 0x20, 0x62, 0x2b, 0xb1, 0x17, 0x2f, 0x34, + 0x88, 0x6f, 0xeb, 0x45, 0xc2, 0x6f, 0xd4, 0x46, 0xa4, 0xa4, 0xe2, 0x89, + 0x1b, 0x4b, 0xc5, 0x94, 0x18, 0x68, 0x96, 0x14, 0x1a, 0xaa, 0xee, 0xb3, + 0x01, 0xb4, 0x9e, 0x7c, 0x1a, 0x26, 0xfe, 0xc7, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(10, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_11(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xbf, 0xb6, 0x8b, 0xe4, 0xce, 0x17, 0x56, 0xd2, 0x5b, 0xdf, 0xad, 0x5e, + 0x0c, 0x2f, 0x8b, 0xec, 0x29, 0x36, 0x09, 0x01, 0xcc, 0x4d, 0xa5, 0x1d, + 0x42, 0x3d, 0x15, 0x91, 0xcc, 0x57, 0xe1, 0xba, + }, + { + 0x98, 0xaf, 0xe4, 0xbd, 0x19, 0x4c, 0x14, 0x3e, 0x09, 0x96, 0x80, 0xc5, + 0x04, 0xcc, 0xea, 0xab, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb9, 0x7c, 0xaf, 0x21, 0x0e, 0x82, 0x49, 0x8c, 0x34, 0x08, 0x79, 0x0d, + 0x41, 0xc3, 0x20, 0xdd, 0x4a, 0x72, 0x00, 0x77, 0x78, 0x38, 0x9b, 0x44, + 0xb7, 0xbc, 0x3c, 0x1c, 0x4b, 0x8c, 0x53, 0xf8, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x40, 0x9e, 0x0a, 0xa9, 0x49, 0xfb, 0x3b, 0x38, 0x23, 0x1b, 0xf8, 0x73, + 0x2e, 0x79, 0x59, 0xe9, 0x43, 0xa3, 0x38, 0xea, 0x39, 0x90, 0x26, 0xb7, + 0x44, 0xdf, 0x15, 0xcb, 0xfe, 0xff, 0x8d, 0x71, 0xb3, 0xda, 0x02, 0x3d, + 0xcc, 0xe0, 0x59, 0xa8, 0x8c, 0xf0, 0xd4, 0xb7, 0x47, 0x5f, 0x62, 0x8e, + 0x47, 0x64, 0xc8, 0xbe, 0xf1, 0x3c, 0x70, 0xcf, 0xbb, 0xbb, 0x6d, 0xa2, + 0xa1, 0x8a, 0xab, 0xca, 0xd9, 0x19, 0xdb, 0x09, 0xd0, 0x4f, 0xc5, 0x97, + 0x65, 0xed, 0xb1, 0x65, 0x14, 0x7c, 0x88, 0xdd, 0x47, 0x3a, 0x0f, 0x3c, + 0x5e, 0xe1, 0x92, 0x37, 0xca, 0x95, 0x56, 0x97, 0xe0, 0x01, 0xba, 0x65, + 0x4c, 0x5e, 0xe0, 0xbd, 0x26, 0x76, 0x1b, 0x49, 0x33, 0x31, 0x54, 0x42, + 0x6b, 0xc6, 0x32, 0x86, 0x29, 0x8a, 0x8b, 0xe6, 0x34, 0xfe, 0x0d, 0x72, + 0xcf, 0xde, 0xef, 0x0f, 0x3f, 0xc4, 0x8e, 0xca, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(11, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_12(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x4f, 0x68, 0x80, 0xa6, 0x46, 0x10, 0x00, 0x44, 0x63, 0x03, 0x1d, 0x67, + 0xd7, 0x92, 0x4f, 0xa4, 0x46, 0xc3, 0x91, 0x38, 0xd4, 0xd4, 0x10, 0x07, + 0xe8, 0xdf, 0x3d, 0x65, 0x69, 0x1a, 0x93, 0x67, + }, + { + 0x6b, 0x33, 0xb2, 0xc1, 0x36, 0x00, 0xf4, 0xb1, 0xdf, 0x6c, 0xa3, 0xd1, + 0x96, 0x0e, 0x8d, 0xd4, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x57, 0xb8, 0x7b, 0x8c, 0x8f, 0x48, 0x31, 0x2b, 0x53, 0x33, 0xd4, 0x3b, + 0x36, 0x77, 0x30, 0xc0, 0xa5, 0xad, 0x47, 0x25, 0xa1, 0x67, 0x78, 0xfc, + 0xb5, 0x3f, 0xe1, 0x36, 0xd1, 0x36, 0xcb, 0xfd, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x73, 0xd0, 0xf3, 0x24, 0xed, 0x18, 0x6e, 0x2a, 0xd0, 0x6b, 0xd1, 0x80, + 0x0e, 0x26, 0x2b, 0xdb, 0xda, 0x79, 0xba, 0x54, 0xe6, 0x26, 0x76, 0x1b, + 0xd6, 0x0f, 0x74, 0xf4, 0x3e, 0x3b, 0xb6, 0x29, 0x58, 0xec, 0x1e, 0x2f, + 0x1d, 0x94, 0x0a, 0xf1, 0x63, 0xe1, 0xca, 0xdc, 0x12, 0x4e, 0x7e, 0xba, + 0xba, 0x2f, 0x72, 0xe6, 0x7e, 0xfd, 0x74, 0x6c, 0x7f, 0x6d, 0x0c, 0xad, + 0x53, 0xef, 0x03, 0xd8, 0x59, 0xd9, 0x3c, 0xff, 0x77, 0x8a, 0x32, 0xee, + 0x5b, 0xe1, 0x72, 0xfe, 0x7f, 0xdb, 0xdc, 0x23, 0x2d, 0xed, 0x36, 0x0d, + 0x70, 0x4a, 0x6f, 0xa0, 0xf7, 0x0b, 0xeb, 0xe9, 0x42, 0xe5, 0x64, 0x78, + 0x34, 0x54, 0x92, 0xf4, 0x9d, 0xc5, 0xc6, 0xfc, 0x34, 0x6b, 0x88, 0xa5, + 0x89, 0x47, 0xad, 0x25, 0x0e, 0x68, 0x8e, 0x8c, 0x62, 0x6f, 0xe1, 0xef, + 0xe7, 0x62, 0x46, 0x20, 0xe5, 0x71, 0x97, 0x6e, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(12, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_13(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xaa, 0xe3, 0x52, 0xe1, 0x11, 0x84, 0x32, 0x19, 0xca, 0xe8, 0xf7, 0x0e, + 0x7b, 0x8f, 0x6e, 0xb9, 0xbb, 0x53, 0xd2, 0x46, 0xcb, 0xec, 0x1e, 0x4f, + 0x07, 0xd4, 0x27, 0x57, 0x14, 0x32, 0x95, 0xb4, + }, + { + 0xb8, 0x44, 0x85, 0xdc, 0xcd, 0x1b, 0xf9, 0x32, 0x10, 0xe3, 0x22, 0xea, + 0xfc, 0xbe, 0xbc, 0xd9, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf9, 0x23, 0x7f, 0x00, 0xd7, 0x44, 0xd8, 0xfb, 0xff, 0x21, 0xb9, 0xd0, + 0x04, 0x3c, 0x25, 0x8e, 0x87, 0x31, 0x81, 0x7e, 0x6a, 0x5f, 0xb7, 0xb4, + 0xbf, 0x50, 0x11, 0x68, 0x0e, 0x5b, 0xc6, 0x42, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xcf, 0xb2, 0x8b, 0x93, 0x52, 0x2c, 0x7d, 0x61, 0xd8, 0xd3, 0xce, 0x3f, + 0x08, 0x0e, 0x43, 0x5e, 0x4c, 0x83, 0xc7, 0xe1, 0x3a, 0x9d, 0xab, 0x78, + 0x8d, 0xb8, 0xfe, 0xf0, 0x40, 0x72, 0x67, 0xa1, 0x4f, 0xbc, 0x93, 0x24, + 0xe0, 0x90, 0xe2, 0x4d, 0xf5, 0x49, 0x1f, 0xed, 0xfa, 0x81, 0x11, 0x68, + 0x69, 0x98, 0x39, 0x38, 0xd4, 0xd4, 0xd7, 0x32, 0x4a, 0x31, 0x0c, 0x3a, + 0xf3, 0x3a, 0x6f, 0x79, 0x38, 0xf6, 0x02, 0xc5, 0xe4, 0xe6, 0x3f, 0x17, + 0x71, 0xcd, 0xaa, 0xbd, 0xab, 0x07, 0x82, 0xb5, 0xaf, 0xfb, 0x54, 0xeb, + 0x53, 0x04, 0x7c, 0x10, 0x9a, 0x96, 0x06, 0x73, 0x9d, 0xd0, 0x06, 0x5b, + 0xd2, 0x1e, 0xca, 0x33, 0x13, 0x29, 0x86, 0x55, 0x48, 0x78, 0x35, 0x4f, + 0x5f, 0x9f, 0x85, 0x2e, 0x67, 0x4d, 0xd6, 0x90, 0x16, 0x3b, 0x0f, 0xf7, + 0x4c, 0x7a, 0x25, 0xe6, 0xba, 0xe8, 0xce, 0x39, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(13, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_14(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x58, 0x9e, 0x79, 0xe3, 0x39, 0xb7, 0xd2, 0xa1, 0xb8, 0x79, 0xf0, 0xb0, + 0xe1, 0xa7, 0xd1, 0xad, 0x24, 0x74, 0xea, 0xa8, 0x02, 0x5b, 0x07, 0x0f, + 0x1f, 0xfa, 0x87, 0x7b, 0x71, 0x24, 0xd4, 0xff, + }, + { + 0x09, 0x61, 0xed, 0x64, 0xdb, 0xd6, 0x20, 0x65, 0xd9, 0x6e, 0x75, 0xde, + 0x6d, 0x2f, 0xf9, 0xd6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe9, 0x28, 0x38, 0x8d, 0x3a, 0xf4, 0x8c, 0x29, 0x68, 0x52, 0x7a, 0x4d, + 0x2f, 0x9c, 0x26, 0x26, 0xfb, 0xc3, 0xf3, 0xf5, 0xa5, 0xd8, 0x4e, 0x05, + 0x83, 0xab, 0x6f, 0x78, 0xe7, 0xf8, 0xb0, 0x81, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xfc, 0xe6, 0xce, 0xd1, 0xec, 0xf4, 0x74, 0xd1, 0x81, 0xab, 0x33, 0x1f, + 0x79, 0xc3, 0xd2, 0xcc, 0x8a, 0x76, 0x8e, 0xc2, 0x81, 0x8d, 0xe5, 0xb3, + 0xfc, 0x7c, 0xf4, 0x18, 0x32, 0x27, 0x16, 0xd6, 0xa6, 0x85, 0x37, 0x33, + 0x56, 0x1a, 0x49, 0x7c, 0x0c, 0x25, 0xcb, 0x28, 0x8d, 0x2c, 0x9f, 0xcf, + 0xbc, 0xa8, 0x91, 0xba, 0xfd, 0x5a, 0x83, 0x4c, 0x85, 0xf3, 0x60, 0x3f, + 0x40, 0x2a, 0xcf, 0x1a, 0x7b, 0x1e, 0xa9, 0x2d, 0xb8, 0x47, 0xed, 0x5c, + 0x25, 0x2a, 0x86, 0x2a, 0xd4, 0xab, 0x5e, 0x25, 0x97, 0x15, 0xf1, 0xfc, + 0x81, 0xda, 0x67, 0xf5, 0x23, 0x0b, 0xf8, 0xbe, 0x50, 0xee, 0x80, 0x69, + 0x75, 0x80, 0x95, 0xf7, 0xd0, 0xe5, 0x59, 0xe0, 0x3f, 0x2c, 0x60, 0x72, + 0x29, 0x0e, 0x61, 0x79, 0x44, 0x58, 0x43, 0x76, 0x09, 0xe4, 0x73, 0xeb, + 0x66, 0x58, 0x0c, 0xdd, 0xaa, 0xd1, 0x9b, 0x71, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(14, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_15(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x71, 0x42, 0x77, 0xd4, 0x08, 0xad, 0x87, 0xfd, 0xe3, 0x17, 0xf0, 0xa9, + 0x47, 0x32, 0xfc, 0xe6, 0x2f, 0x13, 0x52, 0xbd, 0xc9, 0x09, 0x36, 0x67, + 0x3b, 0x4f, 0x1d, 0xaa, 0x09, 0x25, 0xaa, 0x26, + }, + { + 0xd1, 0x65, 0x82, 0xa9, 0x9f, 0x23, 0x01, 0x0b, 0x42, 0x48, 0xb8, 0x8d, + 0x86, 0x48, 0x54, 0x19, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xbd, 0x9f, 0xc7, 0xcb, 0x2f, 0xd5, 0x06, 0x3b, 0x2c, 0x3c, 0x0c, 0x4f, + 0x34, 0x6a, 0xd2, 0xe3, 0x87, 0x93, 0x71, 0xa9, 0xc8, 0x05, 0xe5, 0x9b, + 0x9f, 0x2c, 0xd2, 0xcc, 0x2a, 0x40, 0x89, 0x4f, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x62, 0xef, 0x7a, 0x43, 0x12, 0x88, 0x25, 0x2e, 0x0d, 0x73, 0x6c, 0x1d, + 0x4e, 0x36, 0xcc, 0x9a, 0xc3, 0x71, 0x07, 0xdc, 0xd0, 0xd0, 0xe9, 0x71, + 0xa2, 0x24, 0x44, 0xa4, 0xad, 0xae, 0x73, 0xa4, 0x1e, 0xff, 0x0b, 0x11, + 0xc8, 0x62, 0x5e, 0x11, 0x8d, 0xbc, 0x92, 0x26, 0x14, 0x2f, 0xd0, 0xa6, + 0xaa, 0x10, 0xac, 0x9b, 0x19, 0x09, 0x19, 0xbd, 0xa4, 0x4e, 0x72, 0x48, + 0xd6, 0xc8, 0x88, 0x74, 0x61, 0x2a, 0xbd, 0x77, 0xfb, 0x37, 0x16, 0xea, + 0x51, 0x5a, 0x2d, 0x56, 0x32, 0x37, 0xc4, 0x46, 0xe2, 0xa2, 0x82, 0xe7, + 0xc3, 0xb0, 0xa3, 0xae, 0xf2, 0x7d, 0x34, 0x27, 0xcc, 0x7d, 0x0a, 0x7d, + 0x38, 0x71, 0x46, 0x59, 0xc3, 0x40, 0x1d, 0xbc, 0x91, 0xd3, 0x59, 0x51, + 0x59, 0x31, 0x8e, 0xbc, 0xa0, 0x1a, 0xe7, 0xd7, 0xfd, 0x1c, 0x89, 0xf6, + 0xad, 0x6b, 0x60, 0x41, 0x73, 0xb0, 0xc7, 0x44, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(15, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_16(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xfa, 0x0e, 0xe1, 0xfe, 0x39, 0xc7, 0xc3, 0x90, 0xaa, 0x94, 0x15, 0x9d, + 0x0d, 0xe9, 0x75, 0x64, 0x34, 0x2b, 0x59, 0x17, 0x77, 0xf3, 0xe5, 0xf6, + 0xa4, 0xba, 0x2a, 0xea, 0x34, 0x2e, 0xc8, 0x40, + }, + { + 0xdd, 0x08, 0x20, 0x65, 0x5c, 0xb2, 0xff, 0xdb, 0x0d, 0xa9, 0xe9, 0x31, + 0x0a, 0x67, 0xc9, 0xe5, + }, + { + 0xf2, 0xe5, 0x8f, 0xe6, 0x0a, 0x3a, 0xfc, 0x59, 0xda, 0xd3, 0x75, 0x95, + 0x41, 0x5f, 0xfd, 0x31, 0x8c, 0xcf, 0x69, 0xd6, 0x77, 0x80, 0xf6, 0xfa, + 0x07, 0x97, 0xdc, 0x9a, 0xa4, 0x3e, 0x14, 0x4c, + }, + { + 0xe0, 0x62, 0x9b, 0x6d, 0x79, 0x75, 0xdd, 0xfa, 0x96, 0xa3, 0x99, 0x64, + 0x87, 0x40, 0xe6, 0x0f, 0x1f, 0x95, 0x57, 0xdc, 0x58, 0xb3, 0xd7, 0x41, + 0x5f, 0x9b, 0xa9, 0xd4, 0xdb, 0xb5, 0x01, 0xf6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf9, 0x2d, 0x4c, 0xf9, 0x9a, 0x53, 0x5b, 0x20, 0x22, 0x2a, 0x52, 0xa6, + 0x8d, 0xb0, 0x4c, 0x5a, 0xf6, 0xf5, 0xff, 0xc7, 0xb6, 0x6a, 0x47, 0x3a, + 0x37, 0xa2, 0x56, 0xbd, 0x8d, 0x29, 0x8f, 0x9b, 0x4a, 0xa4, 0xaf, 0x7e, + 0x8d, 0x18, 0x1e, 0x02, 0x36, 0x79, 0x03, 0xf9, 0x3b, 0xdb, 0x74, 0x4c, + 0x6c, 0x2f, 0x3f, 0x34, 0x72, 0x62, 0x6b, 0x40, 0xce, 0x9b, 0xd6, 0xa7, + 0x0e, 0x7b, 0x8f, 0x93, 0x99, 0x2a, 0x16, 0xa7, 0x6f, 0xab, 0x6b, 0x5f, + 0x16, 0x25, 0x68, 0xe0, 0x8e, 0xe6, 0xc3, 0xe8, 0x04, 0xae, 0xfd, 0x95, + 0x2d, 0xdd, 0x3a, 0xcb, 0x79, 0x1c, 0x50, 0xf2, 0xad, 0x69, 0xe9, 0xa0, + 0x40, 0x28, 0xa0, 0x6a, 0x9c, 0x01, 0xd3, 0xa6, 0x2a, 0xca, 0x2a, 0xaf, + 0x6e, 0xfe, 0x69, 0xed, 0x97, 0xa0, 0x16, 0x21, 0x3a, 0x2d, 0xd6, 0x42, + 0xb4, 0x88, 0x67, 0x64, 0x07, 0x2d, 0x9c, 0xbe, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(16, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_17(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xcf, 0xf7, 0x2f, 0x34, 0x51, 0x15, 0x37, 0x6a, 0x57, 0xf4, 0xdb, 0x8a, + 0x5c, 0x9f, 0x64, 0x05, 0x3e, 0x73, 0x79, 0x17, 0x1a, 0x5a, 0x1e, 0x81, + 0xe8, 0x2a, 0xad, 0x34, 0x48, 0xd1, 0x7d, 0x44, + }, + { + 0xd1, 0xe9, 0x71, 0xec, 0x79, 0x5d, 0x09, 0x8b, 0x3d, 0xae, 0x14, 0xff, + 0xcb, 0xee, 0xcf, 0xd9, + }, + { + 0x6e, 0xc0, 0xc7, 0x98, 0xc2, 0x40, 0xf2, 0x27, 0x40, 0xca, 0xd7, 0xe2, + 0x7b, 0x41, 0xf5, 0xe4, 0x2d, 0xcc, 0xaf, 0x66, 0xde, 0xf3, 0xb7, 0xf3, + 0x41, 0xc4, 0xd8, 0x27, 0x29, 0x4f, 0x83, 0xc9, + }, + { + 0x45, 0xec, 0x80, 0xf0, 0xc0, 0x0c, 0xad, 0x0f, 0xf0, 0xb7, 0x61, 0x6d, + 0x2a, 0x93, 0x0a, 0xf3, 0xf5, 0xcf, 0x23, 0xcd, 0x61, 0xbe, 0x7f, 0xbf, + 0x7c, 0x65, 0xbe, 0x00, 0x31, 0xe9, 0x3e, 0x38, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x17, 0xa7, 0x90, 0x1e, 0x25, 0x50, 0xde, 0x08, 0x8f, 0x47, 0x25, 0x18, + 0xd3, 0x77, 0xcc, 0x4c, 0xc6, 0x97, 0x9f, 0x4a, 0x64, 0xf4, 0x97, 0x5c, + 0x74, 0x34, 0x42, 0x15, 0xe4, 0x80, 0x7a, 0x12, 0x34, 0xee, 0xfe, 0xf9, + 0x9f, 0x64, 0xcb, 0x8a, 0xbc, 0x3f, 0xb8, 0x62, 0x09, 0xf6, 0xfc, 0x7d, + 0xdd, 0x03, 0xe9, 0x4f, 0x83, 0x74, 0x6c, 0x5a, 0xbe, 0x53, 0x60, 0xcd, + 0xde, 0x4f, 0x25, 0x25, 0xcc, 0xf7, 0x16, 0x7e, 0x6f, 0x0b, 0xef, 0xae, + 0x05, 0xb3, 0x8f, 0xd6, 0x08, 0x9a, 0x2a, 0xb8, 0x37, 0x19, 0x87, 0x4c, + 0xe8, 0xf6, 0x70, 0x48, 0x0d, 0x5f, 0x3e, 0xd9, 0xbf, 0x40, 0x53, 0x8a, + 0x15, 0xaa, 0xad, 0x11, 0x2d, 0xb1, 0x61, 0x8a, 0x58, 0xb1, 0x06, 0x87, + 0xb6, 0x88, 0x75, 0xf0, 0x0f, 0x13, 0x9a, 0x72, 0xbd, 0xf0, 0x43, 0xf7, + 0x36, 0xe4, 0xa3, 0x20, 0xc0, 0x6e, 0xfd, 0x2c, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(17, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_18(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xb7, 0x09, 0x9b, 0x06, 0xfc, 0x7a, 0x8a, 0x74, 0xc5, 0x82, 0x19, 0x72, + 0x9d, 0xb6, 0xb0, 0xf7, 0x80, 0xd7, 0xb4, 0xfa, 0x30, 0x7b, 0xc3, 0xd3, + 0xf9, 0xf2, 0x2b, 0xfb, 0x76, 0x35, 0x96, 0xa3, + }, + { + 0xb8, 0x77, 0x20, 0x59, 0xa1, 0x35, 0xa6, 0xb6, 0x1d, 0xa7, 0x2f, 0x37, + 0x54, 0x11, 0xde, 0x26, + }, + { + 0x2a, 0xc1, 0xbf, 0xb2, 0x4e, 0x0b, 0x8c, 0x6a, 0xc2, 0x80, 0x3e, 0x89, + 0x26, 0x18, 0x22, 0xb7, 0xf7, 0x2a, 0x03, 0x20, 0xdf, 0x2b, 0x19, 0x91, + 0x71, 0xb7, 0x9b, 0xcb, 0xdb, 0x40, 0xb7, 0x19, + }, + { + 0x9a, 0xec, 0x4f, 0x56, 0xec, 0x5e, 0x96, 0xfb, 0xd9, 0x60, 0x48, 0xb9, + 0xa6, 0x3a, 0xc8, 0xd0, 0x47, 0xae, 0xdb, 0xbe, 0xea, 0x77, 0x12, 0xe2, + 0x41, 0x13, 0x3b, 0x1a, 0x35, 0x7e, 0xcf, 0xc4, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x0e, 0x1f, 0x2b, 0xfe, 0xf7, 0x78, 0xf5, 0xe5, 0xbe, 0x67, 0x1e, 0xcb, + 0x49, 0x71, 0x62, 0x4e, 0xc7, 0x84, 0xed, 0x27, 0x32, 0xab, 0xc4, 0xfb, + 0xb9, 0x8a, 0x8b, 0x48, 0x2f, 0xb6, 0x87, 0x37, 0xdf, 0x91, 0xfd, 0x15, + 0xac, 0xfa, 0xd2, 0x95, 0x14, 0x03, 0xac, 0x77, 0xc5, 0xca, 0x3e, 0xdf, + 0xfc, 0x1e, 0x03, 0x39, 0x8a, 0xe6, 0xcf, 0x6a, 0xc2, 0x4a, 0x91, 0x67, + 0x8d, 0xb5, 0xc7, 0x29, 0x0a, 0xbc, 0x3f, 0xa0, 0x01, 0xaa, 0x02, 0xd5, + 0x03, 0x99, 0x32, 0x6f, 0x85, 0xd2, 0xb8, 0x94, 0x21, 0x99, 0xa1, 0x57, + 0x5f, 0x67, 0x46, 0x36, 0x47, 0x40, 0xa5, 0x91, 0x05, 0x52, 0xc6, 0x39, + 0x80, 0x4d, 0x75, 0x30, 0xc0, 0xd4, 0x13, 0x39, 0x34, 0x5a, 0x58, 0xff, + 0x00, 0x80, 0xec, 0xcf, 0x17, 0x11, 0x89, 0x51, 0x92, 0xa3, 0x81, 0x7a, + 0x8d, 0xc3, 0xf0, 0x0f, 0x28, 0xcc, 0x10, 0xcc, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(18, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_19(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x7b, 0xa0, 0x2a, 0x73, 0x4c, 0x87, 0x44, 0xb1, 0x5e, 0xf8, 0xb4, 0x07, + 0x4f, 0xe6, 0x39, 0xb3, 0x2e, 0x44, 0x31, 0x76, 0x2a, 0xb5, 0xb7, 0xcd, + 0x4d, 0x5d, 0xf6, 0x75, 0xea, 0x90, 0x67, 0x2b, + }, + { + 0x8a, 0x42, 0x4f, 0x32, 0x10, 0x86, 0x07, 0xc8, 0xf1, 0xf4, 0x5d, 0x97, + 0xf5, 0x00, 0xee, 0x12, + }, + { + 0x3a, 0xd6, 0x27, 0x43, 0x3f, 0x46, 0x51, 0x87, 0xc4, 0x81, 0x41, 0xe3, + 0x0c, 0x26, 0x78, 0x10, 0x60, 0x91, 0xe7, 0xa6, 0x80, 0x22, 0x9a, 0x53, + 0x4b, 0x85, 0x1b, 0x8d, 0x46, 0xfe, 0xb9, 0x57, + }, + { + 0xd8, 0xf0, 0x2b, 0x59, 0xb6, 0xa3, 0xdd, 0x27, 0x6b, 0xc6, 0x9c, 0xba, + 0x68, 0xef, 0xcf, 0x11, 0xab, 0x83, 0xea, 0xd1, 0x39, 0x7a, 0xfd, 0x98, + 0x41, 0x78, 0x6b, 0xd1, 0xbb, 0x5d, 0xa9, 0x7a, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x1f, 0xb9, 0x11, 0x86, 0xba, 0x4b, 0x44, 0x59, 0xd9, 0x94, 0xb4, 0xb9, + 0xf4, 0xca, 0x25, 0x2c, 0x7b, 0xe6, 0x29, 0x4d, 0x6c, 0xdb, 0x5f, 0xe5, + 0x6f, 0x8f, 0xf7, 0x84, 0xd4, 0xb1, 0x90, 0xa1, 0xc6, 0x45, 0x6e, 0x0a, + 0x41, 0x22, 0x3b, 0xbb, 0xdf, 0x83, 0xed, 0x8e, 0x7c, 0xfb, 0xfa, 0x76, + 0x5d, 0x9d, 0x8b, 0xc7, 0xea, 0x5f, 0x4d, 0x79, 0xea, 0x7e, 0xcc, 0xb4, + 0x92, 0x80, 0x81, 0xa2, 0x1d, 0xe4, 0xcc, 0xa3, 0x66, 0x20, 0xd6, 0x26, + 0x7f, 0x55, 0xd9, 0xa3, 0x52, 0xb7, 0x6f, 0xc0, 0xa5, 0x73, 0x75, 0x88, + 0x41, 0x12, 0xc3, 0x1f, 0x65, 0xff, 0x28, 0xe7, 0x6d, 0x31, 0x56, 0x98, + 0xc2, 0x9e, 0x6c, 0x4c, 0x05, 0xcb, 0x58, 0xb0, 0xa0, 0x7a, 0xe6, 0x61, + 0x43, 0xb4, 0xab, 0xc7, 0x8b, 0x9d, 0x25, 0xc7, 0x8b, 0x41, 0x21, 0xe1, + 0xe4, 0x5b, 0xef, 0x1a, 0x6c, 0x17, 0x93, 0xe2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(19, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_20(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x9a, 0x88, 0x65, 0xdf, 0xe0, 0x53, 0xae, 0x77, 0xcb, 0x6a, 0x93, 0x65, + 0xb8, 0x8f, 0x34, 0xee, 0xc1, 0x7e, 0xa5, 0xcb, 0xfb, 0x0b, 0x1f, 0x04, + 0xd1, 0x45, 0x9e, 0x7f, 0xa9, 0xc4, 0xf3, 0xcb, + }, + { + 0x18, 0x0c, 0x0a, 0x74, 0xda, 0x3e, 0xc4, 0x64, 0xdf, 0x11, 0xfa, 0xc1, + 0x72, 0xd1, 0xc6, 0x32, + }, + { + 0x33, 0x63, 0x72, 0xec, 0x82, 0xd0, 0xd6, 0x8b, 0xef, 0xad, 0x83, 0x69, + 0x19, 0x66, 0xef, 0x6f, 0xfc, 0x65, 0x10, 0x53, 0x88, 0xeb, 0x2d, 0x6e, + 0xed, 0x82, 0x6c, 0x22, 0x85, 0x03, 0x7c, 0x77, + }, + { + 0x75, 0xb9, 0x51, 0x08, 0xef, 0xf1, 0xfa, 0xbe, 0x83, 0x61, 0x3e, 0x1c, + 0x4d, 0xe5, 0x75, 0xe7, 0x2a, 0x5c, 0xdc, 0x4b, 0xb9, 0x31, 0x1d, 0xd0, + 0x06, 0xf9, 0x71, 0xa0, 0x52, 0x38, 0x66, 0x92, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x3c, 0x68, 0x3f, 0x6d, 0x4f, 0x8f, 0x5a, 0x40, 0x18, 0xd0, 0x16, 0x33, + 0xdf, 0xee, 0x74, 0x26, 0x6a, 0xaa, 0x68, 0xed, 0x6f, 0xc6, 0x49, 0xe8, + 0x1b, 0x64, 0xdf, 0xdf, 0x5f, 0x75, 0xe7, 0x5d, 0x5c, 0x05, 0x8d, 0x66, + 0xcf, 0x5f, 0xd0, 0x1a, 0x4f, 0x14, 0x3a, 0x6f, 0xf6, 0x95, 0x51, 0x7a, + 0x4a, 0x43, 0xbd, 0x3a, 0xdf, 0xd1, 0xfb, 0x2c, 0x28, 0xba, 0x9a, 0x41, + 0x06, 0x31, 0x40, 0xbe, 0xdb, 0xff, 0xdb, 0x4d, 0x21, 0xb1, 0xac, 0xe1, + 0x55, 0x0d, 0x59, 0x20, 0x9e, 0xc6, 0x1f, 0x1e, 0x2d, 0xba, 0xcb, 0x2a, + 0x91, 0x16, 0xa7, 0x9c, 0xb1, 0x41, 0x0b, 0xf2, 0xde, 0xca, 0x52, 0x18, + 0x08, 0x0a, 0xac, 0xd9, 0xc6, 0x8e, 0x1d, 0x65, 0x57, 0x72, 0x1a, 0x89, + 0x13, 0xe2, 0x3f, 0x61, 0x7e, 0x30, 0xf2, 0xe5, 0x94, 0xf6, 0x12, 0x67, + 0xd5, 0xed, 0x81, 0x46, 0x4e, 0xe7, 0x30, 0xb2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(20, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_21(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x22, 0xc1, 0xaf, 0x2f, 0x2a, 0x4c, 0x88, 0x5f, 0x06, 0x98, 0x85, 0x67, + 0xda, 0x9f, 0xc9, 0x0f, 0x34, 0xf8, 0x0f, 0x6d, 0xd5, 0x10, 0x1c, 0x28, + 0x1b, 0xee, 0xf4, 0x97, 0xa6, 0xa1, 0xb2, 0xf8, + }, + { + 0x3f, 0xaf, 0xde, 0xcf, 0x79, 0xa4, 0x17, 0x48, 0x01, 0xf1, 0x33, 0x13, + 0x16, 0x29, 0x03, 0x7b, + }, + { + 0x80, 0x32, 0x7d, 0xac, 0x48, 0x61, 0x11, 0xb8, 0xa8, 0xb2, 0xc8, 0xe8, + 0x38, 0x1f, 0xb2, 0xd7, 0x13, 0xa6, 0x76, 0x95, 0xc2, 0xe6, 0x60, 0xb2, + 0xb0, 0xd4, 0xaf, 0x69, 0x6c, 0xc3, 0xe1, 0xde, + }, + { + 0xf9, 0x5a, 0x0e, 0x4b, 0xd2, 0x4f, 0x0e, 0x2e, 0x9e, 0x44, 0x4f, 0x51, + 0x1b, 0x76, 0x32, 0x86, 0x8e, 0xad, 0x0d, 0x5b, 0xb3, 0x84, 0x67, 0x71, + 0x26, 0x4e, 0x03, 0xf8, 0xab, 0x8e, 0xd0, 0x74, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x77, 0xa7, 0xfe, 0xa2, 0xf3, 0x5a, 0x18, 0x8f, 0x6d, 0x1b, 0xfd, 0xd4, + 0x9b, 0x56, 0x9d, 0x8c, 0x45, 0xe2, 0xdd, 0x43, 0x1d, 0x35, 0xa1, 0x8c, + 0x6f, 0x43, 0x2c, 0x72, 0x4f, 0x1e, 0x33, 0xae, 0x92, 0xcb, 0x89, 0xa9, + 0xcf, 0x91, 0x51, 0x9e, 0x50, 0x70, 0x5a, 0x53, 0x19, 0x9f, 0x5b, 0x57, + 0x2d, 0xc8, 0x5c, 0x1a, 0xef, 0x8f, 0x28, 0xfb, 0x52, 0xdc, 0x79, 0x86, + 0x22, 0x8f, 0x66, 0x95, 0x4d, 0x54, 0xed, 0xa8, 0x4a, 0x86, 0x96, 0x2c, + 0xf2, 0x5c, 0xf7, 0x65, 0xbd, 0x99, 0x49, 0x87, 0x63, 0x49, 0x29, 0x1b, + 0x1a, 0xae, 0x5f, 0x88, 0xfc, 0xf4, 0xb3, 0x76, 0x91, 0x2d, 0x20, 0x5a, + 0xdd, 0x4f, 0x53, 0xb2, 0x77, 0x0c, 0x65, 0x79, 0x46, 0xc0, 0xd8, 0x24, + 0x28, 0x1f, 0x44, 0x15, 0x09, 0x15, 0x3f, 0x48, 0x35, 0x6d, 0x9d, 0x43, + 0xf8, 0xa9, 0x27, 0xe0, 0x69, 0x3d, 0xb8, 0xfc, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(21, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_22(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xd0, 0x84, 0x0e, 0x3a, 0x8d, 0x62, 0x9d, 0x5b, 0x88, 0x3d, 0x33, 0xe0, + 0x53, 0xa3, 0x41, 0xb2, 0x1c, 0x67, 0x4e, 0x67, 0xe1, 0x99, 0x9f, 0x06, + 0x8c, 0x49, 0x7e, 0xcf, 0xaa, 0xbf, 0xd6, 0xf6, + }, + { + 0x07, 0x1d, 0xe7, 0x24, 0x4e, 0xcb, 0x2f, 0xdf, 0x7a, 0xb2, 0x7f, 0x2d, + 0x84, 0xaa, 0x7b, 0x7a, + }, + { + 0x90, 0xd6, 0x09, 0x52, 0x7f, 0xad, 0x96, 0xff, 0xe6, 0x4a, 0xb1, 0x53, + 0x86, 0x03, 0x46, 0xf3, 0xd2, 0x37, 0xc8, 0x94, 0x05, 0x55, 0xae, 0x17, + 0xb4, 0x78, 0x42, 0xd8, 0x2d, 0x3b, 0x09, 0x43, + }, + { + 0x1d, 0xd1, 0xa8, 0xb5, 0x98, 0x56, 0xc4, 0x9a, 0x38, 0x8f, 0x59, 0x4c, + 0x5f, 0x42, 0xcc, 0x2e, 0x4a, 0x56, 0xb3, 0xcc, 0xb8, 0xa6, 0x5e, 0x70, + 0x66, 0xe4, 0x4c, 0x12, 0xf4, 0x34, 0x4d, 0x50, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x7a, 0xb2, 0x8a, 0x9b, 0x2d, 0x3a, 0xe9, 0x99, 0x19, 0x55, 0x53, 0xe6, + 0x55, 0x0c, 0xce, 0xd4, 0xc2, 0xda, 0xcc, 0xbe, 0x7e, 0xc9, 0xdc, 0xbb, + 0x0d, 0x46, 0x7f, 0xab, 0xba, 0x18, 0x5b, 0x72, 0x7f, 0xbf, 0xd9, 0x83, + 0x02, 0x42, 0xcd, 0x09, 0x8f, 0x4d, 0xb3, 0xcf, 0x4a, 0x85, 0xe8, 0xbf, + 0x8e, 0x8d, 0x59, 0x74, 0xb6, 0x2b, 0x28, 0x55, 0x09, 0x22, 0xb3, 0x2e, + 0xd5, 0xbf, 0xc1, 0xa5, 0x22, 0xb6, 0x60, 0x5c, 0xf9, 0x3b, 0xf8, 0xd9, + 0x0b, 0xde, 0xc1, 0xc5, 0xb9, 0xe5, 0x9c, 0x6f, 0xc3, 0x7a, 0x81, 0x7d, + 0x43, 0x70, 0x68, 0xa8, 0x72, 0x54, 0xbe, 0x1f, 0x7c, 0x46, 0x18, 0xad, + 0xa4, 0x6f, 0xbc, 0x3a, 0x2e, 0xfb, 0x02, 0xe4, 0x45, 0x24, 0xe2, 0x1d, + 0x91, 0xbe, 0x75, 0x34, 0xcf, 0x05, 0xfb, 0xfd, 0x85, 0x83, 0x04, 0xb7, + 0x06, 0xd6, 0xa9, 0x1e, 0xa1, 0xcc, 0x6a, 0xd5, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(22, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_23(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x2e, 0x2d, 0xd5, 0x68, 0x69, 0x10, 0x44, 0x92, 0x76, 0x7a, 0x59, 0x77, + 0x86, 0x52, 0x83, 0x19, 0x19, 0xe1, 0xc8, 0xb9, 0x70, 0xf8, 0x4e, 0x82, + 0x4a, 0xe4, 0x11, 0x65, 0x97, 0xa0, 0xab, 0x7f, + }, + { + 0x01, 0xc4, 0x2a, 0x7e, 0x98, 0x36, 0x41, 0xde, 0x46, 0xc8, 0x2f, 0xd0, + 0x9b, 0x4f, 0x2f, 0x76, + }, + { + 0xbc, 0xd9, 0xe1, 0x50, 0x8f, 0xcc, 0x22, 0x82, 0x0a, 0x8b, 0xe0, 0x71, + 0x80, 0xfe, 0xa5, 0x04, 0x53, 0x67, 0x33, 0x3b, 0x56, 0x9e, 0x11, 0x1b, + 0x01, 0x1c, 0xd5, 0x7d, 0xc1, 0x85, 0x87, 0x65, + }, + { + 0x73, 0x06, 0x50, 0x7c, 0xd3, 0xca, 0x7e, 0xec, 0x66, 0x7e, 0x64, 0x0d, + 0x27, 0x0c, 0xfb, 0xb0, 0x33, 0x06, 0x3d, 0x97, 0x52, 0x0b, 0x6b, 0x7e, + 0x38, 0xff, 0x3c, 0xea, 0x0e, 0x79, 0xd1, 0x2b, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb9, 0x15, 0x72, 0x6c, 0x7b, 0x8c, 0x5d, 0xc3, 0x97, 0x5f, 0x1a, 0x33, + 0x46, 0x84, 0xb9, 0x73, 0xab, 0xf6, 0xa9, 0x49, 0x5d, 0x93, 0x00, 0x88, + 0xcf, 0x5d, 0x07, 0x15, 0x48, 0xe4, 0xfd, 0x29, 0xa6, 0x7b, 0x55, 0xcc, + 0x56, 0x1e, 0xd6, 0x94, 0x9a, 0xd2, 0x81, 0x50, 0xa9, 0xfb, 0x43, 0x07, + 0xc1, 0xfa, 0x5f, 0x78, 0x3a, 0x7e, 0xa8, 0x72, 0xe8, 0xd7, 0xc7, 0xe6, + 0x7f, 0xf0, 0xc2, 0x90, 0x60, 0x81, 0xee, 0x91, 0x57, 0x37, 0xd8, 0x13, + 0xc2, 0x5b, 0xe5, 0xc3, 0x0b, 0x95, 0x2a, 0x36, 0xf3, 0x93, 0xe6, 0xba, + 0xa5, 0x6a, 0xb0, 0x1a, 0xdc, 0x2b, 0x47, 0x76, 0xad, 0x7b, 0x5d, 0x03, + 0x6a, 0x53, 0x65, 0x98, 0x77, 0xc7, 0xa4, 0xe5, 0x22, 0x0a, 0x89, 0x7d, + 0x6c, 0x07, 0x99, 0xaf, 0x37, 0xbe, 0xee, 0xd9, 0x11, 0x73, 0xfb, 0xe9, + 0xc6, 0x13, 0xc3, 0xb6, 0xb9, 0xbb, 0x28, 0xe5, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(23, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_24(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xd1, 0xaa, 0xb0, 0xf1, 0x6b, 0xd4, 0x7a, 0x5c, 0xcd, 0x67, 0xc2, 0x2e, + 0x09, 0x4d, 0xaa, 0x37, 0x35, 0xea, 0xe2, 0x1a, 0xa5, 0x7f, 0x0b, 0xcd, + 0x9e, 0x05, 0x3d, 0x9d, 0x0d, 0x54, 0x5c, 0xb8, + }, + { + 0x19, 0x93, 0x10, 0xdf, 0xe1, 0xb0, 0x12, 0x65, 0xb8, 0xc0, 0xd2, 0xb4, + 0x6d, 0x6c, 0x7c, 0x9f, + }, + { + 0x62, 0x5b, 0x4b, 0x8f, 0x4d, 0xe7, 0x2e, 0xa9, 0xcb, 0x6f, 0x70, 0x55, + 0x63, 0x22, 0xdc, 0x2a, 0x19, 0xd6, 0xb2, 0xb3, 0x2d, 0xe6, 0x23, 0xf5, + 0x57, 0xe4, 0x19, 0xa0, 0x84, 0xba, 0x60, 0xfd, + }, + { + 0xf5, 0x0c, 0xab, 0xae, 0x4e, 0x06, 0x0f, 0x39, 0x71, 0x09, 0x6b, 0x78, + 0xe5, 0x50, 0xcd, 0xa2, 0x83, 0x7a, 0x26, 0xa6, 0x93, 0xd9, 0x05, 0xdb, + 0x2d, 0x99, 0x2d, 0x58, 0x9b, 0x26, 0x8f, 0x44, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x98, 0x7e, 0x1f, 0xdf, 0xe0, 0x04, 0xc6, 0x19, 0xcf, 0x1e, 0x90, 0x34, + 0x57, 0x67, 0x07, 0xec, 0xcd, 0x84, 0x94, 0x00, 0xe1, 0x9c, 0x87, 0xa1, + 0xfe, 0xf5, 0xb0, 0x17, 0x9e, 0xc5, 0x1c, 0x42, 0xa2, 0xf8, 0xc4, 0x5d, + 0x79, 0x42, 0xd0, 0x02, 0x3a, 0x02, 0x3c, 0x89, 0xf1, 0x88, 0xb2, 0x63, + 0x43, 0x62, 0x70, 0x39, 0x85, 0x69, 0x53, 0x69, 0x86, 0x33, 0x22, 0xf5, + 0x86, 0x19, 0xc5, 0x0a, 0x73, 0x85, 0xa2, 0xdc, 0x91, 0xfc, 0x78, 0xf9, + 0x4b, 0x59, 0xf0, 0x13, 0x1d, 0xc2, 0xb5, 0x6a, 0x0d, 0x7c, 0x69, 0x9d, + 0x42, 0x72, 0x85, 0xda, 0x1c, 0x10, 0x4b, 0x0a, 0xd1, 0x73, 0x9d, 0xa1, + 0x0d, 0x80, 0x71, 0xc2, 0x39, 0x93, 0x78, 0x70, 0x45, 0xdc, 0x21, 0xf0, + 0x07, 0x0e, 0x1e, 0x9a, 0xa1, 0x65, 0x8f, 0xc8, 0xe3, 0xad, 0xd7, 0x3d, + 0xac, 0x72, 0x62, 0xe8, 0x0e, 0x0a, 0xa2, 0xee, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(24, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_25(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x44, 0x94, 0x80, 0xea, 0xa1, 0x00, 0xaf, 0xf6, 0xf4, 0x8d, 0xc6, 0x28, + 0x6a, 0x5a, 0x81, 0xb9, 0x72, 0x8b, 0x08, 0x48, 0x64, 0xf7, 0x8a, 0x9d, + 0xa9, 0x8f, 0x60, 0x6a, 0x00, 0xa6, 0xa4, 0x1f, + }, + { + 0xe5, 0x3c, 0x6c, 0x5a, 0xc3, 0xda, 0x9f, 0x47, 0x26, 0x38, 0x9a, 0x03, + 0xf9, 0x7b, 0xb6, 0x40, + }, + { + 0x6b, 0x8f, 0xed, 0xc0, 0x84, 0xd8, 0xe2, 0x8d, 0x33, 0x3a, 0xef, 0x6d, + 0xb3, 0x70, 0x2b, 0x63, 0x51, 0xf0, 0xd2, 0x4e, 0x30, 0x90, 0x8c, 0xcc, + 0xb6, 0x37, 0x94, 0x28, 0x26, 0x55, 0x88, 0x6b, + }, + { + 0x73, 0xa6, 0xd6, 0x4e, 0x19, 0x66, 0xae, 0x32, 0x43, 0x88, 0xdc, 0x12, + 0xc1, 0x45, 0x44, 0xe9, 0xdc, 0x5a, 0xe4, 0xfc, 0xb3, 0x31, 0xe9, 0x9d, + 0x35, 0x0c, 0x45, 0x6f, 0xf1, 0x6f, 0x9a, 0xa0, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xa0, 0x69, 0x12, 0xd3, 0x62, 0xda, 0x7e, 0xb2, 0x55, 0x98, 0x85, 0x7f, + 0x6d, 0x65, 0x34, 0x4c, 0x3e, 0x23, 0xec, 0x3d, 0xeb, 0x80, 0xc6, 0xe4, + 0x31, 0x58, 0x84, 0x5b, 0x95, 0xea, 0xec, 0xa2, 0x41, 0xc0, 0xbb, 0xbd, + 0x67, 0xac, 0x38, 0x5e, 0x24, 0x69, 0x34, 0x44, 0x45, 0x5c, 0xc1, 0xc2, + 0xc0, 0x8c, 0x11, 0x34, 0xd9, 0x56, 0xb8, 0xbc, 0x93, 0xb2, 0x8b, 0xe9, + 0xc2, 0xd3, 0x32, 0x2b, 0x3e, 0x09, 0x25, 0x29, 0x79, 0xdf, 0xb8, 0xd3, + 0x9d, 0x04, 0xc9, 0x4f, 0x81, 0xbe, 0xbd, 0xa5, 0xc7, 0x31, 0x10, 0x60, + 0x5a, 0x23, 0x7b, 0x56, 0x12, 0x16, 0xbd, 0xa9, 0xee, 0x9b, 0xde, 0xe1, + 0xcc, 0x0c, 0x77, 0x28, 0xbc, 0xc8, 0x30, 0x46, 0x82, 0x33, 0x4c, 0xa9, + 0x44, 0xe4, 0x67, 0xa2, 0x7a, 0x85, 0x31, 0x3f, 0xa5, 0x39, 0x5a, 0x9c, + 0x79, 0x0e, 0x35, 0xde, 0xfd, 0x2e, 0xdb, 0x12, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(25, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_26(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x9a, 0x61, 0x74, 0x16, 0x6e, 0x97, 0xaa, 0x49, 0x81, 0xdd, 0xf5, 0x80, + 0xbc, 0x01, 0xc9, 0x67, 0x54, 0xb9, 0xf0, 0xba, 0x04, 0x27, 0x50, 0xaa, + 0xbf, 0xda, 0x1c, 0xff, 0xe5, 0x6e, 0x85, 0x81, + }, + { + 0xd7, 0x51, 0x2f, 0xf6, 0xb7, 0xdb, 0x7c, 0xe1, 0x41, 0xb2, 0xbb, 0x01, + 0xdc, 0xd0, 0x42, 0x5e, + }, + { + 0xed, 0x75, 0x28, 0x8f, 0x23, 0x27, 0x5f, 0x94, 0x22, 0x44, 0x4d, 0xa5, + 0xd3, 0xb5, 0x3c, 0xcb, 0x3c, 0x4a, 0xc8, 0xac, 0xfb, 0x65, 0x9a, 0x1e, + 0x9b, 0x76, 0x55, 0xc2, 0xdb, 0x52, 0xf8, 0x79, + }, + { + 0x68, 0x88, 0xb9, 0x27, 0x7e, 0x57, 0xdc, 0x57, 0x66, 0x3d, 0x40, 0x2e, + 0xba, 0x8d, 0x03, 0xcf, 0x56, 0xa0, 0x70, 0xdc, 0x86, 0x8e, 0x6a, 0x12, + 0x8b, 0x18, 0x04, 0x00, 0x02, 0xba, 0xf6, 0x90, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x03, 0x51, 0x9d, 0xfb, 0x2f, 0xf8, 0x8c, 0xc2, 0xb5, 0x3e, 0xec, 0xc4, + 0x8a, 0xe2, 0xa1, 0x8d, 0xdc, 0xf9, 0x1a, 0x5d, 0x69, 0xd5, 0xae, 0xfc, + 0xdd, 0xa8, 0x44, 0x4e, 0x6d, 0xf7, 0x90, 0xa5, 0x24, 0x0e, 0x67, 0xb2, + 0xa4, 0xde, 0x75, 0xb4, 0xbb, 0x8a, 0x31, 0xf0, 0xf8, 0xae, 0xb5, 0xe7, + 0x85, 0xff, 0xb7, 0xa1, 0x34, 0x1b, 0xb5, 0x2f, 0xe0, 0x0a, 0x05, 0xee, + 0x66, 0xfa, 0x2d, 0x44, 0xea, 0x99, 0x56, 0xe0, 0x55, 0xf9, 0xff, 0xa6, + 0x64, 0x7c, 0x3b, 0xfe, 0x85, 0x1a, 0xb3, 0x64, 0xad, 0xe7, 0x1a, 0x0d, + 0x35, 0x6d, 0xe7, 0x10, 0xdd, 0xaf, 0xb7, 0x62, 0x2b, 0x1d, 0xa1, 0xbc, + 0x53, 0xfd, 0x4d, 0x32, 0x10, 0x40, 0x72, 0x89, 0xc6, 0x8d, 0x8a, 0xeb, + 0x34, 0x6b, 0xf1, 0x58, 0x06, 0xdb, 0xe7, 0x87, 0xe7, 0x81, 0xb9, 0x4f, + 0x63, 0xda, 0x3e, 0x1f, 0x61, 0xb5, 0xac, 0x60, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(26, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_27(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x9c, 0x6a, 0xe1, 0x00, 0x2e, 0xe1, 0xb0, 0xad, 0xd0, 0xbe, 0x56, 0x3c, + 0xe5, 0x0f, 0x89, 0x9d, 0xa9, 0x36, 0xe1, 0x3e, 0xfa, 0x62, 0x0d, 0x08, + 0xc2, 0x68, 0x8c, 0x19, 0x25, 0x14, 0x76, 0x3a, + }, + { + 0xfd, 0xe7, 0xdb, 0x51, 0x60, 0xc7, 0x30, 0x44, 0xbe, 0x73, 0xe9, 0xd4, + 0xc1, 0xb2, 0x2d, 0x86, + }, + { + 0x8f, 0xda, 0xae, 0xff, 0xd6, 0x4e, 0x53, 0xf7, 0xb4, 0x37, 0x4d, 0x90, + 0x2d, 0x44, 0x12, 0x09, 0x96, 0x4e, 0x12, 0xb6, 0x5d, 0x29, 0xaf, 0xec, + 0x25, 0x8e, 0x65, 0xdb, 0x6d, 0xe1, 0x67, 0xca, + }, + { + 0xbc, 0xc2, 0x8f, 0xd5, 0x8e, 0x39, 0x7f, 0x53, 0xf4, 0x94, 0xad, 0x81, + 0x32, 0xdf, 0x82, 0xc5, 0xd8, 0xc4, 0xc2, 0x2e, 0xa0, 0xb7, 0x13, 0x9b, + 0xd8, 0x1e, 0xeb, 0xa6, 0x56, 0x67, 0xbb, 0x69, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x02, 0x1d, 0x93, 0x8c, 0x9b, 0x4d, 0xb7, 0x80, 0xc7, 0xd8, 0x13, 0x4a, + 0xef, 0xf1, 0x05, 0x3e, 0x5b, 0x88, 0x43, 0x37, 0x0b, 0x8a, 0xe9, 0xa6, + 0x74, 0x9f, 0xca, 0x71, 0x99, 0xd8, 0x09, 0x81, 0x0f, 0x1b, 0xc8, 0xdf, + 0xa4, 0x94, 0x26, 0x47, 0x0c, 0x30, 0xc3, 0x61, 0x6f, 0x90, 0x3e, 0x35, + 0xfb, 0xac, 0xb2, 0x34, 0x20, 0xa3, 0x2f, 0x1b, 0xee, 0x56, 0x7c, 0xc3, + 0x23, 0x00, 0xf7, 0x04, 0x24, 0x6d, 0xdc, 0x02, 0x17, 0xf2, 0x36, 0xef, + 0x52, 0xc3, 0xec, 0x9e, 0x24, 0x33, 0xca, 0x66, 0xf0, 0x5c, 0x25, 0x72, + 0x1f, 0x76, 0x61, 0xc4, 0x3f, 0x22, 0xc1, 0xa1, 0x25, 0xed, 0x5d, 0xb5, + 0x31, 0xbd, 0x08, 0x36, 0xeb, 0x43, 0x5c, 0x27, 0xee, 0xfc, 0x74, 0x24, + 0xce, 0x9d, 0x84, 0x5e, 0x1d, 0x4c, 0xc4, 0xc5, 0x03, 0x09, 0x7b, 0x4f, + 0xfc, 0xa7, 0x88, 0xe6, 0x74, 0xa5, 0xcb, 0x53, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(27, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_28(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xfe, 0x96, 0xa8, 0x5b, 0x69, 0xd4, 0x6b, 0x54, 0x09, 0x18, 0x92, 0x7b, + 0xb6, 0x09, 0xdc, 0x57, 0x64, 0x2e, 0xea, 0xef, 0xd4, 0x6b, 0xb5, 0xda, + 0x21, 0x63, 0xa0, 0xbc, 0x60, 0x29, 0x4b, 0x58, + }, + { + 0x22, 0x19, 0x5a, 0x41, 0x0d, 0x24, 0xdb, 0x45, 0x58, 0x94, 0x48, 0xdf, + 0xe9, 0x79, 0xd3, 0xfd, + }, + { + 0x20, 0xf6, 0x98, 0x83, 0x3a, 0x44, 0x72, 0xfd, 0x7b, 0x78, 0xfb, 0x9b, + 0x0c, 0x4e, 0xb6, 0x86, 0x04, 0xf1, 0x66, 0xa2, 0x69, 0x4c, 0x4a, 0xf4, + 0x8d, 0xac, 0x2b, 0x23, 0x76, 0x79, 0x0e, 0x1e, + }, + { + 0x09, 0xcb, 0x87, 0x08, 0x79, 0xd3, 0xf7, 0x34, 0x21, 0x4f, 0x6a, 0x4b, + 0xd2, 0xe0, 0x8c, 0x62, 0xa2, 0xa9, 0x54, 0xbe, 0xbe, 0x55, 0x94, 0x16, + 0xd8, 0xc3, 0x55, 0x1a, 0xaf, 0xe7, 0x1d, 0x6a, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd3, 0xe9, 0x6d, 0xbe, 0x29, 0xe1, 0xfc, 0xb8, 0xed, 0x83, 0xb1, 0x9d, + 0xbf, 0xb2, 0x40, 0xe6, 0xf4, 0x16, 0x79, 0xfb, 0xe8, 0x38, 0x53, 0xaa, + 0x71, 0x44, 0x66, 0x17, 0xe6, 0x3e, 0x5a, 0xf7, 0x8c, 0xf9, 0x8b, 0x33, + 0x1d, 0x15, 0xbc, 0xcb, 0x8c, 0x67, 0x3c, 0x4e, 0x5d, 0x5d, 0xce, 0xc4, + 0x67, 0xa1, 0xfe, 0x26, 0xa6, 0xcd, 0x16, 0x96, 0xd0, 0xc9, 0xbc, 0x49, + 0xf7, 0x81, 0x39, 0xd0, 0x51, 0x28, 0x7d, 0xf7, 0xf3, 0xae, 0x0d, 0xbb, + 0x4b, 0xbf, 0x58, 0x1c, 0xb8, 0x21, 0x19, 0x31, 0x06, 0x3c, 0x3f, 0x46, + 0x12, 0xce, 0xd5, 0x3f, 0x59, 0xd1, 0xb4, 0xeb, 0xb8, 0x75, 0x72, 0x91, + 0x39, 0xf5, 0xd2, 0xa7, 0xd6, 0x06, 0x42, 0xe8, 0xf2, 0x83, 0x5e, 0xed, + 0x88, 0x8b, 0x7e, 0x3e, 0x49, 0xc0, 0xdf, 0xfd, 0x01, 0x2c, 0xd7, 0x46, + 0xab, 0xfa, 0x3e, 0x1c, 0x5c, 0x23, 0x08, 0xc6, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(28, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_29(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xa4, 0xfd, 0x69, 0x3f, 0xf0, 0xa8, 0xaf, 0x24, 0xbc, 0xec, 0x35, 0x2d, + 0x31, 0x96, 0x54, 0x9f, 0xd0, 0xda, 0x5e, 0xe5, 0xd9, 0x9c, 0xa5, 0x84, + 0x16, 0xca, 0x03, 0xce, 0x4c, 0x50, 0xf3, 0x8e, + }, + { + 0x8c, 0xd6, 0x7f, 0x2b, 0xf7, 0x1d, 0x43, 0x66, 0xce, 0x61, 0x39, 0x66, + 0x42, 0x53, 0x1f, 0xf5, + }, + { + 0x36, 0x89, 0x69, 0xc1, 0x5a, 0x48, 0x49, 0xd7, 0x59, 0x3b, 0xe8, 0xb1, + 0x62, 0x11, 0x3b, 0x92, 0x98, 0xa5, 0x35, 0xc1, 0x48, 0xff, 0x66, 0x8a, + 0x9e, 0x8b, 0x14, 0x7f, 0xb3, 0xaf, 0x4e, 0xba, + }, + { + 0x83, 0xd2, 0xbe, 0x9a, 0x0d, 0x74, 0xe6, 0xa4, 0x21, 0x59, 0xae, 0x63, + 0x0a, 0xce, 0xbf, 0x4e, 0x15, 0x27, 0x1e, 0xf7, 0xf1, 0x4f, 0x3d, 0xe1, + 0x47, 0x52, 0xbe, 0x0e, 0x0e, 0x82, 0x2b, 0x11, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe9, 0x18, 0x8f, 0xc0, 0xea, 0xec, 0x74, 0xb2, 0x60, 0x8e, 0x21, 0xe3, + 0xa4, 0x0b, 0xe9, 0x4a, 0xaf, 0x4a, 0xe0, 0x8e, 0xb6, 0x84, 0xde, 0x8f, + 0x8b, 0xba, 0x2d, 0x5f, 0xd3, 0xb0, 0x73, 0xaa, 0x55, 0x31, 0xc9, 0x38, + 0xc0, 0xfc, 0x62, 0x8d, 0xa6, 0x57, 0x25, 0xc5, 0x4b, 0x5c, 0x68, 0xbb, + 0x91, 0xd7, 0xd3, 0x26, 0x56, 0x5e, 0x96, 0x68, 0x5e, 0x0a, 0x4e, 0x7b, + 0x22, 0x0c, 0x50, 0xe0, 0xca, 0xf1, 0x62, 0x8e, 0xdb, 0xa5, 0xbd, 0x75, + 0x5b, 0x31, 0x89, 0x4f, 0x8c, 0xb9, 0x0a, 0xfa, 0x76, 0xe8, 0x8c, 0x5e, + 0xb9, 0xe6, 0x1b, 0x49, 0x32, 0x44, 0x4c, 0x13, 0x97, 0xde, 0xe3, 0xe3, + 0x22, 0x41, 0xa3, 0xfb, 0x70, 0xa3, 0x92, 0x9e, 0x49, 0xf6, 0xda, 0x02, + 0xee, 0xa5, 0x48, 0x12, 0xab, 0xb3, 0xd6, 0xb5, 0xce, 0xe1, 0x8f, 0x03, + 0xaf, 0x1e, 0x0b, 0x49, 0x58, 0x43, 0x0a, 0xb3, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(29, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_30(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x25, 0x4f, 0xf5, 0x68, 0x7a, 0x6d, 0xad, 0x3f, 0x1d, 0x23, 0x7d, 0xc7, + 0x62, 0xf5, 0x8d, 0x24, 0xef, 0x2e, 0x2c, 0x08, 0x4d, 0x0a, 0x48, 0xd2, + 0x6a, 0x3d, 0xc8, 0x1e, 0x54, 0x90, 0xcd, 0xa3, + }, + { + 0xf2, 0xec, 0x39, 0x2a, 0xcc, 0xa4, 0x91, 0xe0, 0x3c, 0xe4, 0x7b, 0x95, + 0x96, 0x3a, 0x49, 0xfc, + }, + { + 0xf8, 0x06, 0xb9, 0xb4, 0xa5, 0x66, 0x82, 0xc6, 0x1b, 0x55, 0xcb, 0x6a, + 0x33, 0x4c, 0xaf, 0x87, 0xff, 0xe1, 0x35, 0xad, 0xfe, 0xa6, 0xd0, 0xc3, + 0xfc, 0x22, 0xb3, 0x98, 0x98, 0xfb, 0xd0, 0x78, + }, + { + 0xb8, 0x49, 0x4b, 0x1c, 0x1f, 0x17, 0x52, 0xfb, 0x6f, 0x80, 0xd7, 0x32, + 0xa8, 0x9b, 0x08, 0x11, 0x58, 0x57, 0xf7, 0xcc, 0x96, 0xe7, 0xdf, 0xf0, + 0x5e, 0xbb, 0x82, 0x27, 0x06, 0x88, 0x99, 0x17, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x0e, 0x52, 0x7e, 0x00, 0x49, 0x4d, 0x55, 0x56, 0x4f, 0x9d, 0x9b, 0x28, + 0xe7, 0x11, 0x0f, 0x9a, 0x61, 0xce, 0x36, 0xc8, 0x83, 0xb5, 0xbe, 0x2d, + 0xcb, 0x05, 0x54, 0x44, 0x16, 0x4c, 0xdd, 0xdd, 0x1a, 0x9f, 0x27, 0x31, + 0x71, 0x6f, 0x22, 0xd6, 0xff, 0x47, 0x6c, 0xe4, 0x13, 0xc7, 0x7a, 0xbf, + 0xc0, 0xe9, 0x46, 0x87, 0x1d, 0x54, 0x81, 0x34, 0x5c, 0x2e, 0x97, 0xb4, + 0xbf, 0xdd, 0x12, 0xac, 0x03, 0xdf, 0x60, 0x6f, 0xc5, 0x6b, 0xdb, 0x99, + 0xac, 0x7b, 0x71, 0xa6, 0x9b, 0x5b, 0x91, 0x60, 0x37, 0x3b, 0xbe, 0xc3, + 0xe9, 0xdd, 0xe4, 0x77, 0x18, 0x0a, 0xf4, 0x54, 0xe7, 0xac, 0xc6, 0xbc, + 0x58, 0xdc, 0x0a, 0xfb, 0x42, 0x81, 0xc0, 0xde, 0x43, 0x54, 0xc1, 0xbf, + 0x59, 0x90, 0x54, 0xe3, 0x80, 0x0c, 0x6d, 0x60, 0xd8, 0x92, 0x85, 0x88, + 0x65, 0xb5, 0x36, 0x1f, 0x50, 0xbf, 0xca, 0x9b, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(30, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_31(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xff, 0x0c, 0xdd, 0x55, 0x5c, 0x60, 0x46, 0x47, 0x60, 0xb2, 0x89, 0xb7, + 0xbc, 0x1f, 0x81, 0x1a, 0x41, 0xff, 0xf7, 0x2d, 0xe5, 0x90, 0x83, 0x85, + 0x8c, 0x02, 0x0a, 0x10, 0x53, 0xbd, 0xc7, 0x4a, + }, + { + 0x7b, 0xc0, 0x99, 0x28, 0x5a, 0xd5, 0x62, 0x19, 0x93, 0xb6, 0x39, 0xc4, + 0xa9, 0x4c, 0x37, 0x6b, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x14, 0xfc, 0x6c, 0x9b, 0x17, 0x8d, 0xb6, 0x44, 0xa8, 0xcd, 0x71, 0x30, + 0xa4, 0xcf, 0x05, 0x16, 0x78, 0xc8, 0xf4, 0xfa, 0x8f, 0x24, 0xc2, 0x7b, + 0x0a, 0x53, 0x13, 0x38, 0xa5, 0xce, 0x85, 0x89, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x2f, 0x26, 0x20, 0x34, 0x7b, 0xdd, 0xca, 0xa2, 0x94, 0x36, 0x85, 0x34, + 0x6b, 0xbf, 0x31, 0xc4, 0x40, 0x81, 0xf8, 0x66, 0x5f, 0x3d, 0xdb, 0x2b, + 0x42, 0xae, 0x14, 0x16, 0xa7, 0x4c, 0x4b, 0x77, 0xfa, 0xb3, 0xfa, 0x19, + 0xae, 0xec, 0xc5, 0x47, 0xe7, 0x6c, 0x8c, 0xbe, 0x6a, 0xd1, 0xf1, 0x00, + 0xa3, 0xfc, 0x8b, 0x2c, 0xe2, 0xa1, 0xea, 0x3a, 0x3d, 0xd7, 0xcf, 0xad, + 0x46, 0xc1, 0xb2, 0x78, 0x30, 0xb9, 0x40, 0xba, 0x18, 0xd0, 0x9e, 0x9b, + 0x7f, 0xa9, 0x02, 0xbb, 0x76, 0x06, 0x69, 0xb1, 0x73, 0x5c, 0xc7, 0xb7, + 0xbd, 0x39, 0x05, 0x2d, 0xa7, 0xf2, 0x62, 0x6f, 0xa8, 0x70, 0x00, 0xcf, + 0xfa, 0xda, 0x41, 0x00, 0x19, 0xd0, 0x53, 0x38, 0x6a, 0xd8, 0x08, 0xbd, + 0x3c, 0x0c, 0xfc, 0xf5, 0x6b, 0x91, 0x87, 0x9e, 0xb8, 0xd3, 0xf9, 0x32, + 0xee, 0x2d, 0x18, 0x5e, 0x54, 0xf3, 0x1b, 0x74, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(31, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_32(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xf6, 0x1b, 0x9a, 0x29, 0x3d, 0x18, 0x95, 0x2c, 0x74, 0x65, 0xa5, 0x11, + 0x38, 0x2c, 0x03, 0x1b, 0x86, 0x0b, 0xcc, 0x85, 0x86, 0xa7, 0xec, 0x99, + 0xd7, 0x52, 0x3e, 0xad, 0x8a, 0xca, 0xd0, 0xcb, + }, + { + 0xe3, 0x32, 0xa1, 0x0e, 0x88, 0xf0, 0x0d, 0x95, 0x1d, 0xdf, 0xd4, 0xc7, + 0xb0, 0xb5, 0x96, 0x58, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x10, 0xf2, 0x3a, 0xfe, 0xbe, 0x72, 0x60, 0x93, 0xde, 0x81, 0x70, 0x03, + 0x6a, 0x9f, 0x69, 0x4e, 0x80, 0x84, 0xc0, 0x9c, 0x6e, 0x62, 0x0e, 0x98, + 0xbb, 0x45, 0xf1, 0x6e, 0xe5, 0x60, 0x31, 0xce, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd3, 0x43, 0x84, 0x89, 0x3e, 0xf4, 0xcb, 0x3e, 0x42, 0x38, 0x6a, 0x42, + 0xef, 0xbd, 0xce, 0x46, 0x7c, 0xd4, 0x11, 0xa7, 0x6e, 0x6a, 0x32, 0xe1, + 0xd6, 0x34, 0xa5, 0xa3, 0x67, 0x0a, 0x95, 0x97, 0x39, 0x85, 0x85, 0x1b, + 0x5f, 0x36, 0x9a, 0x1b, 0xe6, 0x5a, 0xdd, 0x3e, 0xd6, 0x1f, 0x7c, 0x6a, + 0x11, 0x98, 0x64, 0x85, 0xb7, 0xe1, 0x6b, 0x57, 0x26, 0x3e, 0xed, 0x71, + 0xff, 0xc5, 0xa8, 0x97, 0x56, 0xcb, 0x42, 0xb7, 0xbd, 0xfd, 0xf9, 0x2b, + 0x2e, 0x31, 0xc3, 0x6b, 0x4d, 0x7b, 0x7c, 0xbd, 0x2e, 0x65, 0x0c, 0xcb, + 0xd6, 0xc0, 0xb5, 0xdf, 0xc9, 0x5c, 0xd8, 0x93, 0x7e, 0xf1, 0xe8, 0xeb, + 0xc7, 0x1a, 0x04, 0xcf, 0x33, 0xc3, 0x98, 0xf7, 0xf9, 0x08, 0x6f, 0x0b, + 0xae, 0x57, 0xee, 0x9a, 0xf8, 0xf9, 0x3f, 0x3b, 0x8e, 0xc1, 0xc9, 0x81, + 0x69, 0x17, 0xf6, 0x99, 0xd8, 0xf4, 0x32, 0x72, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(32, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_33(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x1b, 0x6b, 0x52, 0xb7, 0xba, 0x19, 0xc2, 0x6e, 0x62, 0xbd, 0x0a, 0xc9, + 0xb2, 0x33, 0xbc, 0xf0, 0x04, 0xbb, 0xc9, 0xfd, 0x9e, 0x1e, 0x73, 0x7c, + 0xcf, 0x88, 0x4a, 0x76, 0x08, 0x29, 0xcd, 0x10, + }, + { + 0xd3, 0x81, 0xc8, 0xbe, 0x20, 0x32, 0x74, 0xf1, 0x76, 0x69, 0x18, 0xb4, + 0x5e, 0x08, 0xdd, 0xc6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x2f, 0x50, 0x4e, 0xb2, 0x9f, 0x8e, 0xc0, 0x70, 0x4f, 0x07, 0x0b, 0x59, + 0xc0, 0x20, 0x76, 0xf4, 0xa4, 0xe5, 0xc8, 0xe7, 0xb6, 0x45, 0x68, 0xb2, + 0x2c, 0x5f, 0xf5, 0xba, 0xe1, 0x96, 0xd5, 0xeb, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xa4, 0x15, 0x00, 0xfc, 0x54, 0xcc, 0xf5, 0x49, 0xfe, 0x21, 0xb3, 0x69, + 0x34, 0x28, 0xe0, 0x3c, 0xcd, 0xff, 0xbf, 0x42, 0xff, 0x79, 0x0d, 0x47, + 0xdf, 0xf3, 0x4f, 0xd8, 0x8f, 0xce, 0x01, 0xaf, 0xd4, 0x9a, 0x26, 0xd3, + 0x00, 0xad, 0x66, 0xa3, 0x4c, 0xd3, 0xd1, 0xae, 0xc7, 0x3d, 0xd0, 0x02, + 0xdc, 0x83, 0xc1, 0xb8, 0x6c, 0x43, 0x2d, 0x72, 0x17, 0x66, 0xfb, 0x90, + 0x36, 0x61, 0x30, 0xa3, 0xa2, 0x88, 0x88, 0xa6, 0x3a, 0x5d, 0x0b, 0x8b, + 0xef, 0xa8, 0x95, 0x61, 0x1c, 0x25, 0xbf, 0xa8, 0x81, 0x75, 0x36, 0xeb, + 0x0b, 0x20, 0xb9, 0x98, 0x2c, 0x7d, 0x97, 0x6f, 0x47, 0x07, 0x56, 0x3b, + 0x16, 0xb4, 0x9c, 0xcb, 0xd4, 0x35, 0xcf, 0x04, 0x9b, 0x6a, 0x6e, 0x11, + 0xdf, 0x12, 0xe5, 0xfa, 0xf0, 0xd2, 0x0f, 0xc9, 0xde, 0xab, 0x39, 0x5a, + 0xc6, 0x93, 0x03, 0x60, 0x1b, 0xa3, 0x1f, 0xe3, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(33, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_34(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x36, 0x36, 0x7f, 0xa9, 0x73, 0xaa, 0x4e, 0x2e, 0xc7, 0xbc, 0xef, 0x33, + 0x99, 0x00, 0xdd, 0x95, 0x94, 0x16, 0xbd, 0x63, 0xe7, 0x46, 0xaa, 0x3c, + 0x14, 0xa9, 0xb6, 0x6e, 0x83, 0x8f, 0xc7, 0x80, + }, + { + 0xfb, 0xa0, 0x71, 0x24, 0xe6, 0xd5, 0x7f, 0x3c, 0x81, 0xba, 0x59, 0x6d, + 0x25, 0x6e, 0x43, 0x3c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf3, 0x0b, 0xd1, 0x1a, 0x1f, 0x2b, 0xc9, 0x7d, 0xd8, 0xd4, 0x82, 0x9f, + 0x75, 0xd5, 0x9d, 0x55, 0x77, 0xe7, 0x26, 0x82, 0x5e, 0x23, 0x64, 0xd2, + 0x04, 0xe9, 0x07, 0x7d, 0xf4, 0x8f, 0x65, 0xa9, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x6a, 0x5b, 0xdf, 0xdf, 0x37, 0x31, 0x9c, 0x2e, 0x6b, 0xd2, 0xbc, 0x44, + 0x93, 0x84, 0x55, 0xe0, 0x3a, 0x2e, 0x83, 0x0b, 0x23, 0xee, 0x8e, 0xbd, + 0x6f, 0x98, 0x2f, 0xf8, 0x38, 0xb4, 0x99, 0xd6, 0xd3, 0x7b, 0x44, 0xef, + 0x0a, 0x59, 0x41, 0xba, 0x42, 0xfe, 0x02, 0x45, 0xe6, 0x4b, 0x28, 0xee, + 0x1a, 0x2f, 0xa3, 0xe8, 0xd2, 0x24, 0x69, 0xce, 0xb4, 0xc6, 0xf6, 0x75, + 0x62, 0x9c, 0x3c, 0x6a, 0xbf, 0x61, 0xaa, 0xb6, 0xb1, 0xe8, 0x87, 0xc8, + 0xcf, 0x66, 0x44, 0x80, 0x3f, 0x5d, 0x51, 0x16, 0xbe, 0x11, 0xff, 0x42, + 0x69, 0x8d, 0x42, 0xac, 0x36, 0x86, 0x80, 0x70, 0x36, 0xf5, 0x1a, 0xf4, + 0xae, 0x34, 0x4a, 0x36, 0x5e, 0x8a, 0xd8, 0xeb, 0xc3, 0xa6, 0x23, 0xde, + 0x1b, 0xcc, 0x68, 0xe0, 0x64, 0xd9, 0xfa, 0x82, 0xb6, 0xc8, 0x0f, 0xb0, + 0x57, 0x00, 0x60, 0xbc, 0x58, 0xe8, 0x7e, 0xbd, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(34, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_35(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x24, 0x85, 0xcf, 0xc6, 0x15, 0xd7, 0xfa, 0xb6, 0x0f, 0x46, 0x57, 0xe4, + 0x70, 0xc8, 0x12, 0x1e, 0xdd, 0x6b, 0xc1, 0xfa, 0x22, 0x47, 0xb2, 0x05, + 0xce, 0x40, 0x40, 0xee, 0x13, 0xc3, 0x6f, 0x17, + }, + { + 0x08, 0x7e, 0x6b, 0x4b, 0xf1, 0xe7, 0x75, 0xa4, 0xc9, 0xf1, 0x82, 0xdf, + 0x61, 0x80, 0x13, 0x43, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x9a, 0xee, 0x0e, 0xbe, 0xd8, 0xda, 0xf7, 0x03, 0x36, 0x0a, 0xa1, 0xfa, + 0x2e, 0x17, 0xfa, 0xc6, 0xb7, 0x94, 0x5a, 0xc4, 0x5c, 0xda, 0xaa, 0xcb, + 0xcc, 0x9f, 0xce, 0x22, 0xd2, 0x8c, 0x0d, 0x1d, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xca, 0x4e, 0x2c, 0x4b, 0x63, 0xbb, 0x7f, 0x08, 0x43, 0x8b, 0x82, 0x5c, + 0xde, 0xb6, 0xa8, 0x83, 0xa2, 0xca, 0xf3, 0x0d, 0xdb, 0xcc, 0xeb, 0x05, + 0xc9, 0x1d, 0x37, 0xc0, 0x56, 0x76, 0xf6, 0x3c, 0xc4, 0xde, 0x0b, 0xd6, + 0x80, 0xa8, 0x21, 0xa9, 0x95, 0x56, 0x4e, 0xcd, 0x12, 0xe5, 0x4f, 0xc0, + 0x56, 0xa3, 0x9e, 0x4e, 0xc5, 0xfe, 0x33, 0x73, 0xb4, 0xd6, 0x62, 0x04, + 0x02, 0xb6, 0xa5, 0x37, 0x76, 0x2f, 0x95, 0xa2, 0xd4, 0x90, 0x95, 0x81, + 0xc8, 0x98, 0x5d, 0xf8, 0x01, 0xc7, 0x2f, 0x32, 0x23, 0xbd, 0x94, 0x67, + 0x96, 0xac, 0x71, 0xdc, 0x8f, 0xc1, 0xb2, 0x83, 0x8e, 0xa5, 0xaa, 0x68, + 0x64, 0x49, 0x08, 0xcc, 0x74, 0xcd, 0x81, 0x84, 0x86, 0x1b, 0x88, 0x94, + 0xe0, 0x74, 0x92, 0x2e, 0x85, 0xa5, 0xe2, 0x58, 0xfb, 0x6e, 0xd3, 0xec, + 0x10, 0xe3, 0xff, 0xe2, 0x40, 0xb6, 0x73, 0x8c, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(35, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_36(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xd1, 0x09, 0xe7, 0x55, 0xa7, 0x25, 0xc9, 0x64, 0x8d, 0x33, 0x71, 0xff, + 0xbf, 0x2c, 0xe0, 0x80, 0x45, 0xd1, 0x71, 0x75, 0xbb, 0x1e, 0x77, 0x7a, + 0xaa, 0x73, 0xfc, 0x6f, 0x9e, 0xc2, 0xac, 0xf6, + }, + { + 0xc1, 0x42, 0xf6, 0xe0, 0x4d, 0xc8, 0x87, 0xd0, 0x2d, 0x57, 0xb1, 0xc2, + 0x7c, 0x1c, 0x77, 0xae, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x09, 0x1f, 0xd9, 0xe5, 0xb5, 0xb7, 0x41, 0x5f, 0x87, 0x3f, 0x2c, 0xb1, + 0xe5, 0x54, 0xea, 0xbd, 0xd9, 0x1f, 0x96, 0xb6, 0x84, 0xc1, 0x0c, 0xd0, + 0x02, 0x4f, 0xb3, 0x2e, 0x48, 0x1d, 0x4c, 0xb0, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x1d, 0x6f, 0xd5, 0x0a, 0x84, 0x38, 0x69, 0xbb, 0x8a, 0x9b, 0x83, 0xcc, + 0xb4, 0xd1, 0x00, 0xaf, 0x18, 0xee, 0xfc, 0xbd, 0xcb, 0x98, 0xaf, 0xa2, + 0x73, 0x73, 0x7c, 0x68, 0x7b, 0x50, 0x40, 0x22, 0x73, 0xb9, 0x88, 0x6c, + 0xa1, 0x32, 0x0e, 0xca, 0x2c, 0x55, 0x8e, 0xd2, 0x64, 0xa4, 0x2e, 0x02, + 0xe1, 0xa7, 0xdc, 0xbc, 0xa2, 0x67, 0xa3, 0x85, 0xdc, 0x70, 0xd6, 0xe1, + 0x5a, 0xc4, 0x27, 0x6a, 0x6a, 0xd5, 0x91, 0x07, 0xd6, 0x3b, 0x2d, 0x07, + 0x73, 0x91, 0xee, 0xe7, 0x62, 0xd9, 0xfb, 0xe2, 0x29, 0x46, 0xc7, 0xd6, + 0xe3, 0x75, 0x78, 0xd4, 0xdd, 0xcc, 0xfa, 0xe9, 0x78, 0x96, 0x28, 0xa6, + 0x05, 0x37, 0xa3, 0x93, 0x3c, 0xf7, 0xcf, 0xcb, 0x12, 0x71, 0xa2, 0x92, + 0x15, 0x99, 0x1b, 0xd3, 0x41, 0xdf, 0xf3, 0x9b, 0x2c, 0x9b, 0x6c, 0x24, + 0x3a, 0x03, 0xdd, 0xde, 0x0b, 0x73, 0xff, 0xb1, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(36, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_37(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x8b, 0xc4, 0x7b, 0x94, 0xd0, 0x69, 0x19, 0xa1, 0x7b, 0x23, 0xfc, 0xcb, + 0xd4, 0xd2, 0x34, 0x94, 0xbe, 0x25, 0x87, 0xe0, 0xb5, 0xd2, 0xb8, 0x23, + 0x95, 0x59, 0x3d, 0xd4, 0x2a, 0x28, 0x37, 0xa5, + }, + { + 0xbf, 0x4d, 0x19, 0xfd, 0xfa, 0xf2, 0xd5, 0xee, 0x48, 0x39, 0x11, 0x95, + 0x82, 0x8a, 0xcb, 0xed, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x08, 0x19, 0x0c, 0xb3, 0x1d, 0x8f, 0x20, 0xe8, 0xdf, 0x5e, 0x5a, 0x64, + 0x8e, 0xda, 0x89, 0x63, 0x68, 0xff, 0x3b, 0xae, 0x1b, 0x60, 0xf7, 0xca, + 0x1c, 0x93, 0xf8, 0xbc, 0xdc, 0xdf, 0xbd, 0xcb, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x61, 0x05, 0x19, 0x7b, 0x7f, 0xd3, 0xa3, 0x12, 0x17, 0x27, 0x89, 0x95, + 0x50, 0x14, 0x4f, 0x8b, 0x9f, 0x03, 0xcf, 0x9b, 0x1a, 0x57, 0x0e, 0x97, + 0x2a, 0xd2, 0x3f, 0x0e, 0xa7, 0x14, 0xdb, 0x42, 0x4a, 0x0b, 0xdc, 0xba, + 0x04, 0x5b, 0x6a, 0xeb, 0x12, 0x37, 0xc7, 0xab, 0xe9, 0x0b, 0xcf, 0x84, + 0x3d, 0x42, 0x53, 0xb3, 0x75, 0x72, 0x49, 0x53, 0xc3, 0xf7, 0x26, 0xa9, + 0xad, 0x8b, 0x25, 0xba, 0x91, 0x3e, 0x4d, 0xb3, 0x74, 0x18, 0x5a, 0xf9, + 0x36, 0x37, 0xf3, 0xdc, 0xdf, 0x97, 0x3b, 0x98, 0x67, 0x23, 0xf5, 0x90, + 0xee, 0x76, 0x69, 0x16, 0x05, 0x2c, 0x5e, 0xaa, 0x41, 0x91, 0x51, 0xf0, + 0x9d, 0x12, 0x41, 0x0e, 0x48, 0x28, 0x4a, 0xc8, 0xee, 0x87, 0xf2, 0x5e, + 0xd9, 0x67, 0x1b, 0x23, 0x5c, 0xd7, 0xac, 0xaa, 0x44, 0x0a, 0xd4, 0xb6, + 0xad, 0xa8, 0x64, 0xed, 0x62, 0xfb, 0x98, 0x23, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(37, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_38(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x8b, 0x95, 0xec, 0xfe, 0x9f, 0xd0, 0x90, 0xa0, 0x92, 0x10, 0x17, 0x2b, + 0x4c, 0xc1, 0x99, 0xef, 0x1b, 0xfa, 0x73, 0xed, 0xdd, 0xe5, 0x0d, 0x3d, + 0x41, 0x47, 0xc7, 0x5b, 0x6e, 0x0e, 0x76, 0xeb, + }, + { + 0x13, 0x0c, 0x18, 0xae, 0xc9, 0x41, 0x5a, 0x2a, 0x54, 0xd6, 0xcf, 0xa4, + 0x33, 0x44, 0x08, 0x33, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x82, 0x5f, 0x0b, 0x1d, 0xd1, 0xa1, 0x57, 0x0f, 0xb7, 0x10, 0x23, 0x15, + 0x12, 0xcc, 0x28, 0x86, 0x81, 0xfc, 0xba, 0x15, 0xa0, 0xa4, 0x5c, 0xef, + 0x45, 0xaa, 0x1f, 0x26, 0x82, 0xcf, 0x37, 0xf8, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5e, 0xec, 0xa5, 0x1c, 0x5a, 0x05, 0x8f, 0x08, 0xbc, 0xdc, 0xf8, 0x3c, + 0x1d, 0x90, 0x44, 0xb5, 0x20, 0x3b, 0x77, 0xb5, 0x36, 0xf8, 0x66, 0x23, + 0x15, 0x3e, 0x67, 0xf0, 0x5f, 0x3a, 0xdb, 0x28, 0xee, 0xb8, 0x92, 0x5b, + 0x61, 0x07, 0xd7, 0xa8, 0xac, 0xca, 0x77, 0x8b, 0xc4, 0x52, 0x6e, 0xf1, + 0xcf, 0xf5, 0xac, 0x5f, 0xdd, 0x02, 0x39, 0x52, 0x2f, 0xa1, 0x75, 0xd3, + 0xe0, 0x65, 0xd7, 0x8c, 0x19, 0xa6, 0xda, 0xba, 0x56, 0xe2, 0x0b, 0x28, + 0x4b, 0x43, 0x3e, 0xa8, 0x1c, 0xba, 0xe8, 0x13, 0x9c, 0xa7, 0x94, 0x45, + 0xb8, 0x87, 0x74, 0x99, 0x49, 0xda, 0xe8, 0xb9, 0xf0, 0x3e, 0x55, 0x9f, + 0xcf, 0x5f, 0x71, 0x07, 0x22, 0x83, 0x1e, 0xfa, 0x92, 0xad, 0xe0, 0xcd, + 0x0c, 0xab, 0x5c, 0x34, 0x3d, 0xfd, 0x4b, 0xcd, 0xd8, 0xd6, 0xbc, 0xef, + 0xba, 0xf0, 0x53, 0x1a, 0x8d, 0xed, 0x69, 0x3c, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(38, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_39(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xe8, 0x43, 0x6e, 0x86, 0x22, 0xea, 0x34, 0x5d, 0xcb, 0x94, 0x31, 0x64, + 0x0a, 0xff, 0x32, 0x8c, 0x21, 0xbe, 0x83, 0x83, 0x21, 0xda, 0xf0, 0x89, + 0x51, 0x0d, 0x27, 0xaa, 0x4d, 0x3d, 0x64, 0x0c, + }, + { + 0xd6, 0x9a, 0xe9, 0xda, 0xe2, 0x16, 0xae, 0x6c, 0xf3, 0x6f, 0x48, 0xcf, + 0x3f, 0x97, 0xbd, 0x3a, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd9, 0x12, 0xaa, 0xb4, 0x83, 0x68, 0xed, 0xe1, 0xc5, 0xf9, 0xc1, 0x11, + 0x6c, 0xb4, 0xe2, 0xe9, 0x91, 0xfb, 0xaf, 0x26, 0x24, 0xd9, 0xf8, 0x1a, + 0xf4, 0x7e, 0x8d, 0x74, 0x67, 0x46, 0x01, 0x05, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xc3, 0xcb, 0x77, 0x89, 0xf6, 0x9f, 0x6a, 0x99, 0xc3, 0x8c, 0xcd, 0x8d, + 0x73, 0xb6, 0x27, 0xc5, 0xa2, 0x4d, 0xa7, 0x11, 0x6f, 0x9d, 0x1b, 0x11, + 0xb4, 0xa9, 0xfe, 0x34, 0x48, 0xa6, 0x83, 0x7d, 0x21, 0x90, 0x99, 0xb3, + 0x39, 0xf0, 0x6f, 0x18, 0x5d, 0x9f, 0x4c, 0x3d, 0x1b, 0x9a, 0x47, 0x4b, + 0xbd, 0x2c, 0x63, 0x3a, 0xcc, 0x09, 0xfd, 0x54, 0x0a, 0xb8, 0xdf, 0x42, + 0x3b, 0x95, 0x15, 0xd5, 0x2c, 0x68, 0xc5, 0x39, 0x06, 0x8f, 0xcb, 0xa5, + 0x31, 0xb8, 0x85, 0xc2, 0x6c, 0xcc, 0x4f, 0x57, 0x6e, 0x34, 0x71, 0xf7, + 0xe0, 0x88, 0x6f, 0x39, 0x72, 0x51, 0x31, 0xc2, 0xf1, 0x25, 0x6b, 0x45, + 0x02, 0x20, 0x47, 0x3b, 0xcd, 0x07, 0xdd, 0xd9, 0x0a, 0xc8, 0x63, 0x05, + 0x9e, 0xb1, 0x8c, 0x69, 0x82, 0x70, 0x3c, 0xa4, 0x21, 0x9c, 0x74, 0x7d, + 0x84, 0x58, 0x00, 0x92, 0x09, 0x6a, 0x55, 0xc1, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(39, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_40(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x61, 0x30, 0x87, 0x33, 0xc0, 0x88, 0x36, 0x27, 0xae, 0x93, 0x19, 0xe1, + 0x86, 0x57, 0x07, 0x24, 0x40, 0xc7, 0x58, 0x8f, 0x58, 0x13, 0x1e, 0xda, + 0x02, 0x81, 0xa4, 0xe6, 0xc6, 0x3e, 0xc6, 0xf4, + }, + { + 0x37, 0x38, 0x4d, 0x9f, 0x08, 0xc4, 0x25, 0x70, 0x35, 0xf7, 0x30, 0xdb, + 0x48, 0xa2, 0xc1, 0x53, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xec, 0x66, 0x81, 0xc5, 0x28, 0x13, 0x99, 0xbf, 0xb3, 0xad, 0x4f, 0x5c, + 0x6d, 0x73, 0xde, 0x97, 0x26, 0x35, 0x1e, 0x18, 0x9c, 0x46, 0xba, 0x94, + 0x30, 0x42, 0x50, 0xb7, 0x10, 0x52, 0xf9, 0x04, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb3, 0xf6, 0x42, 0xcd, 0x6f, 0xfb, 0x6d, 0xea, 0xa1, 0x1c, 0x07, 0x4e, + 0x76, 0x72, 0x99, 0xd9, 0x3d, 0x24, 0x11, 0xfe, 0x4d, 0xbd, 0xe2, 0xad, + 0xc0, 0x46, 0x30, 0x90, 0x4e, 0x3b, 0xd5, 0xe6, 0x1b, 0x53, 0x44, 0x0f, + 0x9d, 0x51, 0x39, 0x8a, 0xf3, 0xeb, 0x8e, 0x95, 0x12, 0x33, 0xe5, 0x85, + 0xd8, 0x89, 0x75, 0x73, 0x7e, 0x3f, 0x45, 0xe2, 0x3f, 0x5d, 0x63, 0xbb, + 0xd4, 0x2a, 0x28, 0x62, 0xe8, 0x27, 0xa8, 0xa4, 0x9c, 0xed, 0xd8, 0xec, + 0xf8, 0xfd, 0x82, 0x56, 0xa4, 0x75, 0x73, 0xd3, 0x5c, 0x26, 0x22, 0xd7, + 0xe8, 0x7d, 0x83, 0xe5, 0x35, 0x72, 0x05, 0xe0, 0xdc, 0xe5, 0x31, 0xf9, + 0x2e, 0x8f, 0xa3, 0x25, 0x77, 0x82, 0xf1, 0xdb, 0x47, 0xcf, 0x70, 0xdb, + 0xe9, 0x44, 0x01, 0xcd, 0x50, 0xe2, 0x7d, 0xcc, 0xe1, 0x83, 0x69, 0x3a, + 0xd5, 0x01, 0xdb, 0x7b, 0x0a, 0xeb, 0x55, 0xb2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(40, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_41(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x7c, 0x6b, 0x15, 0xd4, 0x47, 0x7c, 0x5d, 0xdf, 0xf3, 0xea, 0xfa, 0xd5, + 0x56, 0x90, 0xe0, 0x21, 0xf8, 0xbf, 0x5d, 0x34, 0x3b, 0xc6, 0xdc, 0x2d, + 0x58, 0xd2, 0x9a, 0x97, 0x9a, 0xa9, 0x21, 0xc3, + }, + { + 0x79, 0x38, 0x80, 0x4e, 0xeb, 0xf0, 0x61, 0x38, 0x8d, 0x3c, 0x34, 0x61, + 0x44, 0xf4, 0x92, 0x11, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x7d, 0x8b, 0x82, 0xd9, 0xee, 0x9a, 0x99, 0xaf, 0x59, 0x34, 0x7d, 0xa7, + 0x67, 0x78, 0x05, 0x14, 0x42, 0xbe, 0x40, 0x98, 0xa3, 0x00, 0xa4, 0xc6, + 0x06, 0xa3, 0x24, 0x73, 0x14, 0xea, 0x46, 0x18, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x62, 0xac, 0xe9, 0x9f, 0xe2, 0xdb, 0x12, 0xe9, 0x3c, 0x2c, 0x91, 0x55, + 0xd7, 0x0a, 0x58, 0x1b, 0x2b, 0xac, 0xb8, 0xf1, 0xed, 0x90, 0x9a, 0x24, + 0xde, 0x1b, 0x36, 0x5f, 0xde, 0xec, 0xc6, 0x71, 0x35, 0x60, 0x7a, 0x44, + 0x79, 0x2b, 0x00, 0x4e, 0x50, 0x7d, 0x07, 0xf5, 0xb3, 0x61, 0x48, 0x0c, + 0xe4, 0xb2, 0xf1, 0xf6, 0xd3, 0x2b, 0xb2, 0x53, 0x69, 0x33, 0xec, 0xe2, + 0x81, 0x6d, 0x47, 0xa9, 0x46, 0x77, 0xcd, 0x82, 0x3e, 0xf6, 0x4a, 0x17, + 0xba, 0xaa, 0x33, 0x59, 0x87, 0x72, 0x2b, 0x0e, 0x1c, 0x02, 0x39, 0x94, + 0x0b, 0x0f, 0x3d, 0x00, 0x52, 0x19, 0xd8, 0xd3, 0x78, 0x15, 0x7c, 0xcf, + 0x17, 0xc1, 0x41, 0x62, 0x16, 0x5a, 0x8e, 0xf3, 0x8f, 0xd4, 0x08, 0xa4, + 0xe9, 0xac, 0x85, 0xa7, 0x08, 0x04, 0xd5, 0x73, 0x53, 0xc7, 0x5f, 0xb1, + 0x87, 0xbe, 0x0d, 0x72, 0xcf, 0x69, 0x9c, 0xc8, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(41, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_42(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x71, 0x59, 0xc7, 0xae, 0xa9, 0x6d, 0xa8, 0xab, 0x86, 0x48, 0xf8, 0xf8, + 0x54, 0xf3, 0x51, 0xbe, 0x9b, 0x28, 0x45, 0x66, 0x90, 0xb7, 0x88, 0xc4, + 0x9c, 0x3d, 0xce, 0x74, 0xb2, 0x31, 0x1e, 0x63, + }, + { + 0x6a, 0xed, 0x95, 0x1f, 0xc6, 0xe1, 0x55, 0x7f, 0x5f, 0x1c, 0xb6, 0xad, + 0xbe, 0xc5, 0x46, 0x86, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xce, 0x6d, 0xe3, 0xb5, 0x21, 0x17, 0x77, 0xf9, 0x05, 0x66, 0x69, 0xd0, + 0x46, 0x01, 0x84, 0x00, 0x3e, 0x87, 0x97, 0x84, 0xdf, 0xff, 0x86, 0xd7, + 0xeb, 0xf0, 0x8a, 0x23, 0x3e, 0x6a, 0x54, 0x82, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x13, 0x33, 0xd1, 0x21, 0x11, 0xb9, 0x59, 0xc5, 0x11, 0x74, 0xca, 0x21, + 0x88, 0xed, 0x84, 0xca, 0x7d, 0xfd, 0xa3, 0x0d, 0x5f, 0xf2, 0x53, 0x27, + 0xcd, 0x19, 0xf7, 0x37, 0x79, 0x59, 0x0b, 0x19, 0xc0, 0xb5, 0x24, 0x75, + 0x60, 0x33, 0x00, 0x8b, 0x64, 0x06, 0xab, 0xe6, 0x31, 0xcc, 0xa6, 0xb8, + 0x2e, 0xbd, 0xda, 0x5c, 0xe7, 0xb9, 0xe2, 0x96, 0x8a, 0x8a, 0xde, 0xe3, + 0xe4, 0xa6, 0xb3, 0xea, 0xa8, 0x07, 0x9a, 0x64, 0xe7, 0x62, 0x2f, 0x66, + 0x28, 0xc3, 0x62, 0xb5, 0xc6, 0xdc, 0xb6, 0x1b, 0x7c, 0xf6, 0x45, 0x67, + 0xe6, 0xec, 0x5a, 0xe3, 0x12, 0x04, 0x72, 0x50, 0x51, 0x3e, 0xc5, 0x65, + 0x91, 0x60, 0xeb, 0xa5, 0xc7, 0x58, 0x35, 0x2f, 0x74, 0x16, 0xa0, 0x39, + 0x86, 0x37, 0x90, 0x2a, 0x4d, 0x7e, 0x86, 0xad, 0xf9, 0x84, 0x50, 0xdf, + 0x11, 0x1e, 0xf4, 0x33, 0x11, 0x1f, 0xf2, 0xd1, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(42, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_43(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xeb, 0xcf, 0xe2, 0x5c, 0xea, 0x69, 0x66, 0x45, 0xc7, 0x9e, 0x77, 0x29, + 0x22, 0xdf, 0x04, 0xd4, 0x84, 0x17, 0xf9, 0xcf, 0x2e, 0xce, 0xf7, 0x27, + 0xcc, 0xcb, 0x3e, 0x89, 0x98, 0x89, 0x3c, 0x59, + }, + { + 0x13, 0x6e, 0x0c, 0x8e, 0x8f, 0xad, 0x1c, 0x49, 0x43, 0x5e, 0x6e, 0xac, + 0x76, 0x3c, 0x77, 0x6f, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x38, 0xb4, 0x8d, 0xb1, 0x1f, 0xf3, 0x1c, 0xe5, 0xe0, 0xa0, 0xcb, 0x62, + 0x79, 0x86, 0xb8, 0x8b, 0xea, 0xd7, 0x4b, 0xe8, 0x34, 0xa4, 0xe3, 0x47, + 0xde, 0x17, 0x07, 0x4c, 0xe1, 0x17, 0x24, 0x4c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd9, 0x0c, 0xb0, 0x83, 0x5b, 0x0c, 0xa6, 0x4c, 0x8d, 0x1d, 0xec, 0x23, + 0xf2, 0x77, 0x3b, 0x6d, 0xd8, 0x35, 0xbe, 0xe7, 0xe2, 0x7c, 0x91, 0x82, + 0x2d, 0xbf, 0x08, 0x98, 0xd1, 0x81, 0xde, 0x5b, 0xe4, 0xe4, 0xf6, 0xa1, + 0xd5, 0x97, 0x12, 0xe3, 0xb4, 0x72, 0x00, 0xcb, 0x14, 0xe1, 0x22, 0x52, + 0xe9, 0xd7, 0xc5, 0x62, 0x4c, 0x84, 0x1e, 0x4c, 0x05, 0xc7, 0x37, 0x2a, + 0x5e, 0x70, 0xe8, 0x3a, 0x1d, 0x86, 0xd0, 0xc0, 0x69, 0xbf, 0xb2, 0x9a, + 0x21, 0xf5, 0x11, 0xc4, 0xcc, 0x8c, 0x4c, 0xd9, 0xf6, 0x6b, 0xa3, 0xa0, + 0x81, 0x02, 0x44, 0xdf, 0x25, 0x18, 0xbf, 0x37, 0x85, 0xb3, 0x03, 0xe7, + 0xae, 0xbe, 0x9f, 0x19, 0x06, 0xbc, 0xff, 0x55, 0xa4, 0x54, 0x5d, 0x53, + 0xd2, 0xfb, 0x8d, 0xd7, 0x2e, 0xee, 0x00, 0x3f, 0x10, 0x00, 0x9e, 0x9b, + 0x41, 0x82, 0x52, 0x11, 0xf2, 0x35, 0x2b, 0xe9, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(43, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_44(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xb0, 0xcc, 0xe5, 0xac, 0xf0, 0xd3, 0x30, 0x5c, 0xf5, 0xeb, 0xdb, 0x55, + 0x87, 0x0a, 0xf9, 0x31, 0x68, 0x20, 0x0d, 0xa5, 0x6f, 0xa2, 0xfa, 0x68, + 0x85, 0xbf, 0x1c, 0x2a, 0x93, 0x28, 0x95, 0x6f, + }, + { + 0x6d, 0x79, 0x66, 0x19, 0x8e, 0xc2, 0x34, 0x18, 0x08, 0x97, 0x39, 0x00, + 0xa9, 0xfc, 0xf0, 0x44, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x2c, 0x0b, 0xb1, 0xbd, 0xa5, 0xa0, 0x12, 0x57, 0x57, 0xb6, 0x4d, 0x57, + 0x3a, 0xd0, 0x4c, 0xf3, 0x6d, 0x47, 0xee, 0x46, 0x15, 0x58, 0x3f, 0xa8, + 0xfe, 0x5a, 0x2d, 0xec, 0x8b, 0x80, 0x59, 0x21, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb4, 0x17, 0xb4, 0x47, 0x0e, 0xa9, 0x50, 0x77, 0x2c, 0xbe, 0xda, 0x48, + 0x5d, 0xe1, 0xe9, 0x45, 0xd2, 0x31, 0x9a, 0x6a, 0x35, 0x00, 0xd8, 0x8f, + 0xd5, 0x22, 0x08, 0x0a, 0x26, 0x44, 0xcf, 0x7c, 0x18, 0x61, 0xd4, 0x28, + 0x1d, 0xbe, 0xab, 0x81, 0x51, 0x8b, 0x59, 0x24, 0x50, 0x50, 0xb1, 0xb4, + 0xa5, 0xf8, 0x9e, 0x9a, 0x61, 0xbe, 0x4c, 0x5a, 0x43, 0x72, 0xb4, 0x97, + 0x2f, 0x1c, 0x17, 0xb9, 0x83, 0x35, 0x99, 0x07, 0xa4, 0x4d, 0x88, 0xb5, + 0xbb, 0x12, 0x84, 0x84, 0x28, 0xef, 0xea, 0x84, 0x40, 0x78, 0x93, 0x64, + 0x0f, 0xb0, 0x36, 0x3b, 0x23, 0x71, 0xe1, 0x48, 0x91, 0x24, 0x8a, 0xfd, + 0x61, 0xab, 0xb5, 0xac, 0x04, 0x74, 0xc5, 0x00, 0xe1, 0xc8, 0xef, 0x2c, + 0x11, 0x41, 0x84, 0xd7, 0xea, 0x47, 0x66, 0xd4, 0x6b, 0x78, 0xd2, 0x74, + 0x29, 0x86, 0xbb, 0x34, 0xe6, 0x2c, 0x49, 0xde, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(44, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_45(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x10, 0x3e, 0x04, 0xdc, 0x6c, 0x88, 0x5d, 0xe4, 0x22, 0x50, 0x67, 0xc8, + 0xdd, 0x67, 0xce, 0xc5, 0xa3, 0xdd, 0x7c, 0x45, 0x58, 0x6d, 0x2a, 0xdf, + 0x59, 0xb5, 0x4b, 0x54, 0x6c, 0xdc, 0x15, 0x91, + }, + { + 0x5e, 0x37, 0xbf, 0x8f, 0x45, 0x5a, 0x28, 0x35, 0xcf, 0x44, 0x8d, 0xa6, + 0x83, 0xd6, 0x36, 0xb4, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x93, 0x6f, 0xfb, 0x8c, 0xb0, 0x83, 0x33, 0x24, 0xbe, 0x82, 0x3a, 0xe7, + 0x23, 0x92, 0x99, 0x96, 0xbc, 0x45, 0x0f, 0x81, 0x57, 0x6f, 0x2c, 0x43, + 0xb4, 0x82, 0x9e, 0xa8, 0x50, 0x44, 0xcb, 0x55, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x14, 0xef, 0xb3, 0xf1, 0x2f, 0xa0, 0x3b, 0xd2, 0x0b, 0x94, 0xb9, 0x79, + 0x4e, 0xee, 0xd7, 0xde, 0x9e, 0x7f, 0x7f, 0xc9, 0xf1, 0x06, 0xd6, 0x80, + 0x36, 0x63, 0x22, 0xe7, 0x10, 0x28, 0x5c, 0x1e, 0xb8, 0xc1, 0x43, 0x60, + 0x76, 0x41, 0xe0, 0xc4, 0x4f, 0xe9, 0xdb, 0x92, 0xc0, 0xab, 0xb5, 0xfd, + 0xa3, 0x80, 0x6b, 0xef, 0x59, 0x61, 0x28, 0x9e, 0x3e, 0xd7, 0x2b, 0x67, + 0xb1, 0x4f, 0x1e, 0x98, 0xdc, 0x3b, 0xd9, 0xb9, 0x38, 0x86, 0x3d, 0x5c, + 0xd9, 0xe4, 0x5f, 0xff, 0x3e, 0x7c, 0x5e, 0xb2, 0x56, 0xb4, 0x87, 0xf0, + 0x29, 0x64, 0x3a, 0x0a, 0x27, 0xc0, 0x9b, 0xcb, 0x6f, 0x5e, 0xec, 0x83, + 0x63, 0xc4, 0xde, 0xbe, 0xd6, 0x17, 0x52, 0xdf, 0x88, 0x40, 0xcd, 0x34, + 0xe6, 0xae, 0x7f, 0x5e, 0xe3, 0xfb, 0x53, 0xb7, 0x26, 0x76, 0x78, 0xd1, + 0x5e, 0x01, 0x72, 0xa6, 0x99, 0xfa, 0xbd, 0x8d, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(45, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_46(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x28, 0xba, 0x1a, 0x66, 0x16, 0x32, 0xef, 0xc8, 0xec, 0xce, 0xd5, 0xf5, + 0x1b, 0x79, 0x13, 0x00, 0xfb, 0x3b, 0x55, 0xb0, 0x5d, 0x04, 0x17, 0x08, + 0x63, 0x8d, 0xe4, 0xbe, 0xb7, 0x57, 0xa9, 0xe5, + }, + { + 0x76, 0x82, 0x87, 0x96, 0xaf, 0xf0, 0x7f, 0x55, 0x79, 0x5c, 0xb5, 0x47, + 0x13, 0xc7, 0x7e, 0xd4, + }, + { + 0x40, 0x93, 0x3f, 0xdc, 0xce, 0x41, 0x59, 0xb0, 0x95, 0x51, 0x11, 0xf8, + 0x44, 0x47, 0x1b, 0x0d, 0xb8, 0x5b, 0x73, 0xbd, 0xd2, 0xb7, 0x8c, 0x46, + 0x8d, 0xd3, 0x9e, 0x2a, 0x9b, 0x29, 0xae, 0xf2, + }, + { + 0xa5, 0xf5, 0x42, 0xb0, 0x4a, 0xaa, 0x5d, 0xbc, 0x93, 0x1e, 0x47, 0x01, + 0x9f, 0xeb, 0x38, 0x96, 0x26, 0x16, 0xc5, 0x7a, 0xf0, 0x9b, 0x7c, 0x1d, + 0xf8, 0x3f, 0x2b, 0x86, 0x0f, 0xf7, 0x65, 0x86, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x65, 0xe5, 0xaa, 0x47, 0xb3, 0x85, 0xf1, 0xea, 0x42, 0xb2, 0x31, 0xb9, + 0xfe, 0x74, 0x42, 0x53, 0xb8, 0x59, 0x88, 0x59, 0xd7, 0x01, 0x1e, 0x52, + 0x5f, 0x5a, 0x2a, 0x1a, 0xd3, 0x2a, 0x97, 0x2a, 0x85, 0x08, 0x02, 0xc6, + 0x0a, 0x2b, 0xe1, 0x9b, 0xe2, 0x70, 0x06, 0x3a, 0x3c, 0xfb, 0xea, 0xae, + 0x95, 0x4f, 0x10, 0xb1, 0x22, 0x35, 0x2d, 0xe6, 0xa0, 0x8a, 0xc4, 0x10, + 0xe0, 0x99, 0x16, 0x53, 0xaa, 0xb2, 0x71, 0xb3, 0x60, 0xfe, 0x91, 0x91, + 0xcf, 0x5a, 0xdd, 0xcc, 0xcc, 0xed, 0x8c, 0x4a, 0xcf, 0xb6, 0x14, 0x57, + 0x04, 0x99, 0x92, 0x98, 0x8f, 0xd7, 0xa9, 0xac, 0xca, 0x1f, 0x1b, 0xca, + 0x35, 0xf1, 0x47, 0x58, 0x13, 0x69, 0x4a, 0x39, 0x98, 0x8e, 0x5f, 0xac, + 0x9f, 0x4a, 0xc0, 0x57, 0x22, 0x86, 0xbc, 0x46, 0x25, 0x82, 0xad, 0x0a, + 0xf7, 0x8a, 0xb3, 0xb8, 0x5e, 0xc1, 0x7a, 0x25, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(46, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_47(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xcf, 0xd5, 0x49, 0xc8, 0x08, 0x0a, 0x50, 0x2e, 0x3e, 0xdd, 0x79, 0x05, + 0x58, 0x4e, 0x5b, 0xe1, 0x4d, 0x7e, 0xf5, 0x59, 0x10, 0xd2, 0x82, 0xd8, + 0x1d, 0x34, 0x5c, 0x53, 0xca, 0x34, 0xe0, 0x7b, + }, + { + 0xa5, 0x65, 0xe4, 0xbc, 0x2f, 0x46, 0x17, 0x69, 0xc0, 0xa8, 0xf2, 0x11, + 0xa6, 0x7d, 0xc9, 0xa7, + }, + { + 0xd4, 0xad, 0xd6, 0x4c, 0x86, 0x03, 0x41, 0x56, 0x29, 0xda, 0x5c, 0xd5, + 0x8c, 0x51, 0x89, 0x58, 0xc8, 0x4d, 0x43, 0xad, 0xa7, 0x1b, 0xd1, 0xbd, + 0x57, 0x8f, 0xbe, 0x67, 0x74, 0x4b, 0x24, 0x76, + }, + { + 0x27, 0x12, 0xa4, 0x16, 0x15, 0xf2, 0xb4, 0xaf, 0x37, 0xd6, 0x41, 0xc3, + 0xa7, 0x34, 0x07, 0xad, 0x62, 0xb4, 0x3e, 0xeb, 0xd0, 0x43, 0x9b, 0xc7, + 0x0f, 0xaf, 0x2b, 0x7f, 0x25, 0x25, 0xe2, 0xf1, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb5, 0x22, 0x5f, 0xa8, 0xb7, 0xb1, 0xff, 0x05, 0x8f, 0x3e, 0xd4, 0x92, + 0xcc, 0x7f, 0x66, 0xcb, 0xc3, 0x93, 0x47, 0x74, 0x03, 0x14, 0x47, 0x12, + 0x5a, 0xf8, 0x20, 0xcf, 0xe9, 0x42, 0x9c, 0x19, 0x5d, 0xf9, 0xb3, 0xcc, + 0x9a, 0x11, 0xb0, 0x2c, 0xf3, 0x80, 0x06, 0x13, 0xeb, 0x53, 0x4d, 0xc2, + 0xce, 0x13, 0x65, 0xbc, 0x40, 0x9b, 0x2b, 0x13, 0xd6, 0x5b, 0xed, 0xe5, + 0x4c, 0xd2, 0x13, 0xa5, 0x49, 0xf2, 0xef, 0x9e, 0x3d, 0x17, 0xc4, 0xfb, + 0x99, 0x55, 0x1e, 0xea, 0x53, 0x9b, 0x91, 0x25, 0x48, 0x83, 0xca, 0xd8, + 0x6f, 0x5c, 0x38, 0x53, 0xa8, 0x03, 0x56, 0x6a, 0xc1, 0xea, 0x86, 0x4a, + 0x08, 0xbf, 0x6e, 0x80, 0x29, 0x58, 0x8f, 0xf8, 0x58, 0x0f, 0x7d, 0x26, + 0x57, 0xdc, 0x8f, 0x38, 0x9f, 0x72, 0xca, 0xb4, 0x25, 0x1a, 0x19, 0xc4, + 0xfa, 0x2e, 0x53, 0x9a, 0xfa, 0xc7, 0xc1, 0xc1, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(47, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_48(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x5c, 0xc9, 0x13, 0xe1, 0x26, 0x29, 0x48, 0x12, 0x62, 0xad, 0x31, 0x7f, + 0xb8, 0xd3, 0x98, 0x70, 0xb4, 0xf7, 0x26, 0x0c, 0xca, 0xcd, 0xce, 0xbd, + 0x91, 0x31, 0x71, 0x0a, 0xe7, 0x1e, 0x0c, 0x98, + }, + { + 0xd4, 0x6d, 0xe6, 0xc6, 0xf4, 0xa5, 0x43, 0xfe, 0x5f, 0x47, 0x3c, 0x2c, + 0x2d, 0x0e, 0x21, 0x4a, + }, + { + 0xca, 0x7f, 0x2f, 0x65, 0x01, 0xe6, 0xde, 0xa1, 0xbf, 0x7f, 0x54, 0xe6, + 0xbd, 0x50, 0x30, 0x47, 0x97, 0xab, 0x80, 0xea, 0x02, 0x28, 0x81, 0x3e, + 0xb3, 0x84, 0x98, 0x42, 0xf2, 0x17, 0x27, 0x3f, + }, + { + 0xe7, 0xf0, 0x08, 0xab, 0xd0, 0x0d, 0x52, 0x52, 0x97, 0xff, 0x6e, 0x2c, + 0x39, 0xa3, 0x58, 0xe6, 0xc7, 0x5c, 0x4a, 0x64, 0xf6, 0xac, 0x68, 0xde, + 0xfd, 0x27, 0x56, 0x23, 0xf4, 0x96, 0xca, 0x07, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8c, 0xa7, 0xdd, 0x3d, 0x3b, 0x82, 0xf6, 0x40, 0xb3, 0x3c, 0xf1, 0x76, + 0xb2, 0x2d, 0xe7, 0x13, 0x0c, 0x1d, 0xc5, 0x4c, 0x68, 0x4d, 0xdf, 0x8b, + 0xc7, 0xb0, 0x8a, 0x18, 0x17, 0x53, 0xad, 0x7a, 0xf8, 0xc4, 0x63, 0x82, + 0x87, 0xf7, 0x24, 0xdf, 0x8f, 0xf9, 0x91, 0x43, 0x1f, 0x99, 0xa3, 0x10, + 0x51, 0x73, 0xb1, 0x07, 0xf0, 0x64, 0x54, 0x1d, 0xd9, 0x24, 0x40, 0xfd, + 0x4c, 0xee, 0x65, 0x9e, 0x93, 0x22, 0xb5, 0x15, 0x41, 0x68, 0xf4, 0x9d, + 0xb3, 0x6f, 0x32, 0x24, 0x5a, 0xe4, 0xd9, 0x83, 0x15, 0x59, 0xeb, 0x83, + 0x9b, 0x28, 0xb9, 0xa3, 0x88, 0xae, 0x49, 0x80, 0xce, 0xea, 0xdd, 0x99, + 0x03, 0xd4, 0xfe, 0xbc, 0x66, 0x2b, 0xb7, 0xd2, 0x46, 0x01, 0x74, 0x63, + 0xe8, 0x43, 0xe7, 0x72, 0x56, 0x72, 0x66, 0x22, 0xcd, 0x1f, 0x10, 0x25, + 0xc5, 0x1b, 0x66, 0x24, 0xce, 0x84, 0x77, 0x16, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(48, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_49(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xb8, 0xbc, 0x5e, 0x67, 0x20, 0xa4, 0x14, 0xb7, 0xf7, 0xa2, 0x13, 0xd4, + 0x55, 0xd4, 0x3e, 0xc5, 0x5c, 0x77, 0x3e, 0xdf, 0x24, 0x03, 0x31, 0x97, + 0x16, 0xde, 0xf9, 0xee, 0xc1, 0x29, 0x39, 0x75, + }, + { + 0x2d, 0xa2, 0x86, 0x29, 0x23, 0x31, 0x05, 0x6d, 0xcf, 0x88, 0x4d, 0xe8, + 0x94, 0x4e, 0x02, 0x6b, + }, + { + 0x51, 0x4e, 0xb0, 0xc6, 0x9b, 0xbe, 0xa5, 0xb9, 0x95, 0x32, 0x49, 0x76, + 0xca, 0x12, 0x33, 0x37, 0xe2, 0x6f, 0x63, 0x9b, 0x06, 0xa7, 0xa3, 0x62, + 0xff, 0x57, 0x67, 0x35, 0x20, 0xcb, 0x70, 0xdb, + }, + { + 0x3c, 0x1b, 0xba, 0x68, 0x1b, 0x3e, 0x04, 0x08, 0xd0, 0x8b, 0x92, 0xfd, + 0xd3, 0x25, 0x2d, 0xda, 0x67, 0x68, 0x5d, 0x86, 0x5f, 0xe8, 0x28, 0x6d, + 0x6c, 0x4f, 0xd6, 0x69, 0xc3, 0x3c, 0x09, 0x20, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb9, 0x41, 0x60, 0x02, 0xc5, 0x44, 0xe0, 0x79, 0x99, 0x84, 0x64, 0xd5, + 0x18, 0x1a, 0xfe, 0x70, 0xc1, 0x06, 0xd4, 0x4b, 0x87, 0x6d, 0x16, 0xb3, + 0x9f, 0x93, 0x6a, 0xff, 0x36, 0xec, 0x86, 0xdd, 0xef, 0x5f, 0xb2, 0x68, + 0x8a, 0x0a, 0xad, 0xf6, 0x69, 0xc3, 0x9b, 0x6f, 0x67, 0x24, 0xff, 0x3e, + 0xea, 0xac, 0x90, 0xb7, 0x06, 0x74, 0xc1, 0x4d, 0x97, 0xe9, 0x94, 0xbd, + 0xec, 0x0f, 0xd5, 0x23, 0x73, 0xcf, 0x7a, 0x21, 0x25, 0x0c, 0x83, 0x5e, + 0x93, 0xc7, 0x3d, 0x7c, 0x49, 0x79, 0x0b, 0x59, 0x30, 0x0d, 0xb4, 0x85, + 0xf0, 0x21, 0xb1, 0x35, 0x93, 0xa3, 0x2d, 0x72, 0xb7, 0x05, 0x7d, 0xa0, + 0xd5, 0x5f, 0x63, 0xa6, 0xca, 0xe5, 0x18, 0x35, 0x40, 0xe8, 0x17, 0x29, + 0x0d, 0x8b, 0x91, 0xce, 0x55, 0xf4, 0x5f, 0xeb, 0x77, 0x30, 0x73, 0x2f, + 0xa9, 0x15, 0x6d, 0xa8, 0x27, 0x6d, 0x67, 0x32, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(49, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_50(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x28, 0xdc, 0x2f, 0x25, 0xb2, 0x63, 0x4c, 0x06, 0x72, 0xa0, 0xfa, 0x03, + 0x37, 0x85, 0x63, 0xde, 0x21, 0x45, 0x00, 0xfa, 0xa7, 0x7e, 0xe4, 0x07, + 0x64, 0x09, 0xaa, 0x16, 0xbc, 0x85, 0x12, 0xd2, + }, + { + 0x85, 0xd5, 0x2e, 0xd3, 0x4e, 0x06, 0x29, 0x09, 0xbb, 0x5e, 0x61, 0x75, + 0xdf, 0xa1, 0x87, 0xb8, + }, + { + 0x5b, 0xb0, 0xe4, 0x22, 0xce, 0xec, 0x47, 0xaa, 0xf4, 0x80, 0x82, 0x90, + 0x9f, 0x11, 0xc9, 0x98, 0xa5, 0xa7, 0x7d, 0x54, 0x32, 0x0b, 0x28, 0xea, + 0xea, 0xab, 0x71, 0x32, 0x21, 0xc9, 0x54, 0x19, + }, + { + 0x43, 0x93, 0xb2, 0x0d, 0x7d, 0xd1, 0x5d, 0x67, 0xa2, 0xf7, 0x8e, 0x74, + 0x37, 0xe1, 0xe7, 0xa9, 0x51, 0x10, 0xdc, 0x2d, 0xf6, 0x46, 0xdb, 0x22, + 0x34, 0x2a, 0x71, 0x1a, 0xe1, 0x02, 0xd1, 0xd6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x66, 0xdb, 0xf2, 0xb1, 0x21, 0xbf, 0xd4, 0xa7, 0x25, 0x84, 0xb5, 0x61, + 0xc6, 0x50, 0xf5, 0x09, 0x95, 0xd2, 0x2f, 0x0f, 0x37, 0x7d, 0xf2, 0xf6, + 0x0c, 0xd2, 0x6e, 0x03, 0x77, 0xb7, 0xd1, 0xae, 0x7b, 0x1a, 0xfc, 0x72, + 0xd2, 0x2f, 0x9a, 0xb5, 0xb5, 0x42, 0x76, 0x4a, 0x21, 0x9c, 0xbb, 0x66, + 0xf3, 0x25, 0x3e, 0x60, 0x2e, 0x93, 0x80, 0x7d, 0x3e, 0xc2, 0xbe, 0xe5, + 0xab, 0x13, 0x1f, 0x00, 0xfb, 0x4e, 0xd3, 0x28, 0x8b, 0xb1, 0xb6, 0xf5, + 0x2d, 0xd3, 0x9d, 0x79, 0xc8, 0x17, 0xab, 0x73, 0xd9, 0xb1, 0x1f, 0x81, + 0xe3, 0x01, 0x31, 0xd1, 0xf3, 0xca, 0xb9, 0x60, 0x44, 0x1d, 0x07, 0xec, + 0x23, 0xbe, 0xa0, 0xee, 0xd7, 0x71, 0x88, 0xd7, 0x14, 0x07, 0x87, 0x39, + 0xd8, 0x1c, 0x42, 0xcb, 0x22, 0x4b, 0xc5, 0xad, 0x0b, 0x65, 0xc8, 0xc9, + 0xc5, 0xa8, 0x08, 0xb6, 0x05, 0xf1, 0x92, 0x3c, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(50, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_51(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xaf, 0x84, 0x05, 0x9f, 0x96, 0xed, 0x19, 0xb2, 0xe5, 0x3f, 0x09, 0x12, + 0x28, 0xe7, 0x09, 0x67, 0x86, 0x47, 0x35, 0xdc, 0x83, 0x17, 0x8e, 0x15, + 0x9f, 0x57, 0x7c, 0x57, 0xbc, 0x12, 0x1c, 0xbf, + }, + { + 0x84, 0xc6, 0x51, 0x5f, 0xcb, 0x88, 0x13, 0x6a, 0xdc, 0x23, 0x9f, 0x53, + 0x7f, 0xca, 0xbf, 0x4d, + }, + { + 0x9f, 0xab, 0xe3, 0x0a, 0xdb, 0x15, 0xa1, 0x45, 0x2f, 0xba, 0xf2, 0xb6, + 0x27, 0xc0, 0xe4, 0x7a, 0xdc, 0x60, 0xce, 0x6e, 0x9b, 0x10, 0xa5, 0x6a, + 0x33, 0x8f, 0x08, 0xe8, 0x85, 0x8f, 0x82, 0xa1, + }, + { + 0xf5, 0xfd, 0xb3, 0xb3, 0xaa, 0x2e, 0xde, 0xf8, 0xca, 0x8d, 0x31, 0xc9, + 0x91, 0x2e, 0xb4, 0x3a, 0x3a, 0xdc, 0x48, 0x25, 0xc8, 0x8d, 0x46, 0x32, + 0x30, 0xb1, 0x13, 0x91, 0x3f, 0x1d, 0x01, 0x17, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x18, 0x1c, 0x7a, 0x02, 0x26, 0x4e, 0x5a, 0x6a, 0x1f, 0xf4, 0xd9, 0x7d, + 0xbc, 0xe0, 0x74, 0x28, 0xe4, 0xb2, 0xb4, 0x49, 0xa2, 0xb8, 0x61, 0xeb, + 0x0a, 0x61, 0x72, 0x93, 0xfb, 0x84, 0x7e, 0x2a, 0xa1, 0x23, 0x4d, 0x21, + 0x4d, 0x50, 0x92, 0x07, 0x3f, 0x9d, 0xbb, 0x49, 0xfa, 0xe8, 0xb9, 0x63, + 0x56, 0x9b, 0xf4, 0xb7, 0xfe, 0x20, 0xe6, 0xaa, 0x35, 0x5e, 0x56, 0x5d, + 0xb4, 0xc7, 0x5d, 0x62, 0x3b, 0x47, 0xcb, 0x62, 0x7a, 0x7f, 0xde, 0x90, + 0x08, 0xd0, 0x29, 0xd2, 0x0c, 0x09, 0xbb, 0x50, 0xe8, 0x3a, 0xb0, 0x37, + 0xf3, 0x70, 0x8f, 0xc5, 0x18, 0x3f, 0xe0, 0xf2, 0x2a, 0x73, 0x2b, 0x89, + 0xf3, 0x9c, 0x3a, 0x45, 0xf1, 0xf1, 0x61, 0x68, 0x76, 0xf8, 0x72, 0x03, + 0xce, 0xef, 0x06, 0x05, 0xf0, 0x3c, 0x28, 0xb2, 0x65, 0x4d, 0xf0, 0x0a, + 0x4d, 0x55, 0xa0, 0xc0, 0x11, 0xb9, 0x39, 0x16, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(51, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_52(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x4a, 0xf2, 0xbb, 0xf3, 0x6d, 0x2a, 0x30, 0x25, 0x95, 0xde, 0x66, 0x7e, + 0x42, 0xe0, 0x8a, 0xbb, 0x5e, 0x44, 0xcb, 0xde, 0x9b, 0x1b, 0xe2, 0xee, + 0xd0, 0x33, 0x8a, 0xac, 0xb4, 0x86, 0x73, 0xbc, + }, + { + 0xe0, 0xb9, 0x43, 0xf5, 0x5f, 0xc1, 0x34, 0x16, 0x86, 0x9a, 0x62, 0x4a, + 0x9a, 0x38, 0x3f, 0xcf, + }, + { + 0xde, 0xa4, 0xc6, 0xb2, 0x49, 0x0f, 0x18, 0x72, 0xe6, 0x1a, 0x9b, 0xf7, + 0x7c, 0x3f, 0x3b, 0x67, 0xaf, 0xa8, 0xe8, 0x92, 0xbe, 0x0c, 0x3c, 0x1a, + 0xb8, 0x9e, 0x92, 0xa2, 0x70, 0x45, 0xe1, 0xa7, + }, + { + 0xbb, 0x6a, 0x04, 0xce, 0x7f, 0x81, 0xef, 0x18, 0xbb, 0x34, 0x55, 0xc9, + 0x25, 0xb8, 0xd5, 0x76, 0xdf, 0x2b, 0xbf, 0x68, 0xc0, 0xfe, 0x4e, 0x65, + 0xc6, 0x80, 0x22, 0xaa, 0x69, 0xdc, 0x0e, 0xc2, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x31, 0x05, 0x2a, 0x14, 0xc9, 0x11, 0xb6, 0x92, 0x64, 0x57, 0xf5, 0x62, + 0xfc, 0x27, 0xd1, 0x9f, 0x22, 0xa3, 0xde, 0x7d, 0xd1, 0x45, 0xaa, 0x75, + 0xb9, 0xb6, 0x03, 0xa6, 0x10, 0x9f, 0xe1, 0xc1, 0xfe, 0xa3, 0xff, 0x2e, + 0x37, 0xe9, 0xd9, 0x84, 0x14, 0x50, 0x2e, 0x2d, 0xfe, 0xf0, 0x13, 0x77, + 0x88, 0x18, 0x7e, 0x42, 0xa7, 0x1c, 0xd6, 0x94, 0x75, 0xa8, 0xbb, 0x00, + 0x40, 0xac, 0x6d, 0xb2, 0x3a, 0xed, 0x06, 0x92, 0x74, 0x95, 0x95, 0x4a, + 0xaa, 0x23, 0x19, 0x3d, 0xb8, 0x32, 0x89, 0xf7, 0x5f, 0x96, 0x6e, 0xef, + 0x0a, 0x7c, 0xed, 0x68, 0xe8, 0x87, 0x1a, 0xb2, 0xa4, 0x7d, 0x38, 0x92, + 0xf5, 0x94, 0xa9, 0x8c, 0x90, 0xae, 0x51, 0xcf, 0x11, 0xbc, 0xf6, 0xed, + 0x87, 0x9d, 0x45, 0x8d, 0x17, 0x1f, 0x33, 0x4c, 0x04, 0x92, 0x34, 0xdc, + 0xe7, 0x94, 0x1f, 0x34, 0xb4, 0x83, 0x9f, 0xcb, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(52, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_53(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xd6, 0x66, 0xa2, 0xe7, 0x0a, 0xf2, 0x77, 0x12, 0x69, 0x42, 0x5c, 0x4d, + 0xc1, 0xec, 0xa8, 0x7f, 0xe1, 0x77, 0x31, 0x38, 0x43, 0xb8, 0xb6, 0xb9, + 0xc3, 0xd4, 0xda, 0x9d, 0x46, 0x54, 0x0c, 0xaf, + }, + { + 0xd5, 0x48, 0x6a, 0x3b, 0x88, 0x1c, 0x35, 0xbe, 0x94, 0x4d, 0xd2, 0x35, + 0x9b, 0x88, 0xd6, 0xa2, + }, + { + 0x5f, 0x0c, 0xcf, 0x34, 0xc2, 0x57, 0x60, 0x8e, 0xbf, 0x9e, 0x5f, 0xcb, + 0xb9, 0x79, 0xc1, 0xd8, 0xf6, 0x69, 0x04, 0x7e, 0x71, 0x8c, 0x76, 0x0d, + 0x0a, 0x9b, 0xe0, 0xbe, 0xe7, 0xc9, 0x4d, 0x79, + }, + { + 0x1a, 0x6c, 0xf1, 0xd8, 0xf6, 0xa1, 0x7a, 0xd9, 0xdb, 0xa6, 0x89, 0x8f, + 0x7f, 0x82, 0xd3, 0x3d, 0xba, 0x59, 0x6e, 0xac, 0xcc, 0x20, 0x11, 0xd1, + 0x55, 0xac, 0x6e, 0x39, 0xd5, 0x9a, 0x75, 0x58, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x58, 0xfd, 0xe4, 0xf4, 0xe1, 0x08, 0xa5, 0x40, 0x22, 0x6f, 0x40, 0x84, + 0x6b, 0xce, 0x66, 0xda, 0xb6, 0x08, 0x2e, 0xfb, 0x63, 0x6e, 0x89, 0x87, + 0xe1, 0x85, 0x42, 0xdd, 0x6e, 0x28, 0x40, 0xa8, 0x8b, 0xe0, 0x45, 0x01, + 0x94, 0x02, 0xb2, 0x03, 0x71, 0xe0, 0x8e, 0x41, 0x52, 0x38, 0x92, 0x5a, + 0x44, 0x0a, 0x49, 0x3e, 0xd8, 0xe1, 0x03, 0x55, 0xfc, 0x16, 0x46, 0x85, + 0xe4, 0x99, 0x60, 0x0e, 0xe1, 0x92, 0xed, 0x0b, 0x95, 0x31, 0x59, 0x2d, + 0x4a, 0x52, 0xf4, 0xd7, 0x0a, 0xc0, 0xa0, 0xaa, 0xe1, 0x2c, 0x17, 0x05, + 0xe9, 0xc1, 0xec, 0xa2, 0x6b, 0x36, 0xc0, 0x90, 0x6e, 0x21, 0x6f, 0xda, + 0xe4, 0x79, 0xae, 0xf2, 0xdc, 0xa8, 0x46, 0x0d, 0x05, 0x58, 0xbd, 0xf7, + 0x68, 0xd7, 0xc0, 0x00, 0x2f, 0xc7, 0x1d, 0x6a, 0x5e, 0xb0, 0x6f, 0xd6, + 0x60, 0x56, 0x42, 0x57, 0xa1, 0x58, 0xdb, 0x53, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(53, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_54(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x20, 0x8b, 0x9e, 0xf5, 0x00, 0xb0, 0x49, 0x3b, 0x7f, 0x2d, 0xed, 0x5f, + 0x3a, 0xf6, 0xbd, 0x56, 0x8f, 0x5d, 0xff, 0x0e, 0xbe, 0xfd, 0x19, 0x98, + 0xd3, 0x48, 0x03, 0x7e, 0xc3, 0x63, 0xdf, 0x80, + }, + { + 0x13, 0xeb, 0x96, 0x9c, 0xea, 0xc8, 0x94, 0x56, 0xab, 0x22, 0xd8, 0x69, + 0x33, 0xa1, 0x81, 0x81, + }, + { + 0xcc, 0xae, 0xbe, 0xad, 0x9e, 0x2b, 0x91, 0x1e, 0xf9, 0x27, 0xf3, 0x06, + 0x9d, 0xa5, 0xe3, 0x58, 0x2a, 0x78, 0x86, 0xd9, 0x56, 0x57, 0x0d, 0x2e, + 0xdf, 0x2a, 0xf4, 0x34, 0xb9, 0x47, 0x3d, 0xba, + }, + { + 0x06, 0x9b, 0x76, 0x7a, 0xc6, 0x12, 0x3f, 0x9c, 0x55, 0x1d, 0x3b, 0xbd, + 0x43, 0x22, 0x8d, 0xf5, 0x4f, 0x37, 0x9c, 0xa6, 0xb4, 0x18, 0x96, 0x77, + 0x22, 0x82, 0x5f, 0xad, 0x33, 0x34, 0x3f, 0x9c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xec, 0xc7, 0x58, 0xfd, 0x31, 0x6a, 0x75, 0xe5, 0xf9, 0x7a, 0x14, 0x80, + 0x3a, 0xe5, 0x1f, 0x8c, 0x0a, 0x80, 0xec, 0xba, 0x95, 0x4b, 0x54, 0xec, + 0x8b, 0x9d, 0xa8, 0x08, 0x1f, 0x0b, 0xe9, 0x68, 0x0b, 0x11, 0xac, 0xdc, + 0xb9, 0xfc, 0x65, 0xc6, 0xef, 0x45, 0x87, 0x87, 0x54, 0x61, 0x37, 0xfa, + 0xdb, 0xbf, 0x07, 0x7a, 0x60, 0x02, 0x52, 0x88, 0x35, 0xca, 0x3c, 0x80, + 0x8f, 0xa5, 0x93, 0xd8, 0x20, 0xa0, 0x65, 0x01, 0x59, 0x2d, 0x85, 0x7a, + 0xb0, 0xa6, 0x7b, 0x80, 0x3e, 0xcb, 0x63, 0x15, 0xba, 0x1a, 0xa0, 0xc9, + 0x0c, 0xaf, 0xed, 0xe0, 0x24, 0x80, 0xb9, 0x8a, 0x07, 0xcf, 0x9b, 0xb8, + 0x67, 0xdc, 0xe3, 0xb1, 0x57, 0x5b, 0x6b, 0x46, 0xd4, 0x04, 0x6f, 0x44, + 0x08, 0xdd, 0xc7, 0x12, 0x82, 0xfa, 0x43, 0xac, 0xc7, 0x38, 0xa2, 0x76, + 0x65, 0xb3, 0x3a, 0xfc, 0xcf, 0x97, 0x40, 0x77, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(54, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_55(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x01, 0x46, 0x9d, 0xfd, 0xc9, 0x93, 0xba, 0x87, 0x0c, 0x34, 0x87, 0xf9, + 0x3b, 0xec, 0x20, 0x81, 0x97, 0x4d, 0xe5, 0xf4, 0x19, 0x3d, 0x10, 0x5b, + 0xd8, 0xaf, 0x41, 0xcf, 0x00, 0x1f, 0x69, 0x9c, + }, + { + 0x76, 0x15, 0x4e, 0xbb, 0xfe, 0xe0, 0x89, 0x51, 0xcf, 0xfc, 0x61, 0xc1, + 0xc2, 0x2c, 0x96, 0x85, + }, + { + 0x4e, 0x5f, 0xa3, 0x38, 0x43, 0x45, 0xb6, 0x6b, 0x7d, 0xd4, 0xfe, 0x9f, + 0xc7, 0x88, 0xa0, 0x3a, 0x38, 0x05, 0xc5, 0xe8, 0xac, 0xb4, 0x70, 0x7e, + 0x6d, 0x24, 0x41, 0x2c, 0x49, 0x27, 0xe8, 0xff, + }, + { + 0x5e, 0x74, 0x35, 0xf0, 0x0f, 0x59, 0x38, 0x7b, 0xf0, 0x97, 0x7a, 0x6d, + 0x79, 0xc9, 0x5b, 0x83, 0x18, 0x84, 0xe8, 0xed, 0x26, 0x1b, 0xdd, 0x09, + 0x58, 0x87, 0x16, 0x91, 0xc7, 0x0a, 0x3f, 0xe2, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x26, 0xdf, 0xf7, 0x9a, 0xd2, 0xe7, 0x29, 0x32, 0xcc, 0xb0, 0x0a, 0xfe, + 0x66, 0x90, 0x5f, 0xb9, 0x66, 0xfc, 0x7a, 0x05, 0x7b, 0x49, 0x1c, 0x37, + 0x5a, 0x31, 0x54, 0x0a, 0x79, 0xe3, 0x0a, 0x47, 0x80, 0x70, 0x8a, 0x1e, + 0x92, 0x8d, 0x7c, 0x6e, 0xf9, 0x59, 0x43, 0x3b, 0x9a, 0x0d, 0xbd, 0x19, + 0xcc, 0x73, 0x08, 0x2c, 0xf5, 0xd3, 0x04, 0xff, 0x2e, 0x9a, 0xcb, 0xc5, + 0x62, 0x20, 0x02, 0x50, 0xe7, 0x37, 0x6d, 0x7d, 0x35, 0xf2, 0x2b, 0xfa, + 0x25, 0x7c, 0x86, 0xb0, 0xda, 0x74, 0x83, 0x79, 0x1f, 0x8f, 0x82, 0xe7, + 0x95, 0x59, 0xe5, 0xb4, 0xb9, 0xbf, 0xe0, 0xe1, 0xfe, 0xc5, 0x2a, 0xc4, + 0x09, 0x33, 0xb3, 0x93, 0x4b, 0x13, 0xdd, 0x65, 0x0e, 0xd5, 0xcc, 0x18, + 0x3e, 0x79, 0x6b, 0xe3, 0x5f, 0xc5, 0x9f, 0xaf, 0x51, 0x3c, 0x40, 0xf1, + 0x24, 0x9b, 0xc8, 0xfe, 0xc4, 0xf2, 0xf6, 0x11, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(55, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_56(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xf1, 0x9f, 0x4d, 0xd4, 0x01, 0xe7, 0xfb, 0x21, 0xb3, 0xf7, 0xf7, 0x3c, + 0x8b, 0x39, 0x0e, 0xb6, 0x76, 0xf8, 0x95, 0xda, 0xab, 0x86, 0x0b, 0x49, + 0x1c, 0xb2, 0xfa, 0xc8, 0x51, 0x97, 0xc1, 0x49, + }, + { + 0x25, 0x38, 0xe6, 0xbe, 0x68, 0x44, 0x1f, 0x15, 0xac, 0x6f, 0xd0, 0xa3, + 0x4e, 0xf3, 0xb8, 0xb8, + }, + { + 0x12, 0x35, 0x2e, 0x74, 0xb9, 0x12, 0xc5, 0xc6, 0x37, 0xaf, 0x35, 0xb1, + 0x90, 0x47, 0x77, 0x5f, 0x9c, 0xae, 0x26, 0xc1, 0xad, 0x49, 0xc5, 0xd5, + 0x6c, 0xd2, 0x87, 0xc7, 0xb4, 0x11, 0x76, 0x22, + }, + { + 0x05, 0x1f, 0xfc, 0xc7, 0x64, 0x79, 0xa5, 0x67, 0x0c, 0xb0, 0xfb, 0xba, + 0x2b, 0xdc, 0x83, 0x79, 0x33, 0x1d, 0x8d, 0xba, 0xd0, 0x60, 0x69, 0xf9, + 0xa5, 0xe3, 0x6c, 0xb8, 0xf7, 0xaf, 0xb3, 0x98, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8c, 0x44, 0xe3, 0xd5, 0xd0, 0xfe, 0xe7, 0x9b, 0x1a, 0x25, 0x8f, 0x3e, + 0x30, 0xe3, 0xcd, 0x9a, 0x0e, 0xbd, 0x12, 0xcf, 0x68, 0x97, 0x8c, 0xca, + 0x5e, 0xd0, 0x53, 0x44, 0x76, 0x57, 0xff, 0x41, 0x05, 0x77, 0x8b, 0x4d, + 0xd8, 0x72, 0xfd, 0xe9, 0x2f, 0x98, 0x80, 0x4a, 0x72, 0x42, 0xea, 0x57, + 0xe1, 0x3b, 0x0d, 0x6a, 0x8d, 0x49, 0x37, 0x37, 0x48, 0xc4, 0x95, 0xa7, + 0x7d, 0xe8, 0x0e, 0xfe, 0x24, 0xfa, 0xe7, 0x68, 0x60, 0x4d, 0x1c, 0xbb, + 0x94, 0xeb, 0xd0, 0x8f, 0x37, 0x91, 0x40, 0xea, 0x52, 0x08, 0xdb, 0x58, + 0x9d, 0x1d, 0x1d, 0xdc, 0xb6, 0x9e, 0xcc, 0x76, 0x4b, 0x51, 0xfc, 0x08, + 0x25, 0x08, 0xac, 0xd6, 0x93, 0xce, 0xdb, 0xc7, 0x07, 0x0f, 0x55, 0x2d, + 0x29, 0x4b, 0x6b, 0x2b, 0xab, 0x9c, 0x7b, 0x6c, 0x9c, 0x0e, 0x06, 0x88, + 0x8b, 0xab, 0xbd, 0x75, 0x68, 0x8c, 0xf5, 0x36, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(56, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_57(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xa0, 0x24, 0x5f, 0x99, 0x08, 0xf6, 0xc6, 0x64, 0xde, 0xa7, 0x68, 0x9e, + 0x97, 0x1a, 0x1f, 0xf2, 0xc1, 0x89, 0xee, 0xe4, 0x22, 0xea, 0x15, 0x7d, + 0x40, 0xa4, 0x44, 0xd8, 0x3c, 0x94, 0x19, 0x80, + }, + { + 0xf5, 0x69, 0xf2, 0xaf, 0x4d, 0x5f, 0xbb, 0xb7, 0x81, 0x3f, 0x3e, 0x24, + 0x4e, 0x4d, 0x3d, 0xc4, + }, + { + 0x88, 0x7e, 0x6c, 0x40, 0x26, 0x35, 0x97, 0xd7, 0x56, 0xc2, 0x5b, 0x40, + 0x15, 0xe7, 0x09, 0xa9, 0x66, 0x3e, 0x48, 0xd5, 0xa9, 0xfb, 0xb4, 0x81, + 0x3b, 0x85, 0xa5, 0x3b, 0x99, 0x7a, 0x64, 0xb6, + }, + { + 0x2b, 0x85, 0x59, 0x8a, 0x4f, 0x92, 0xa0, 0x0f, 0x4c, 0xb4, 0xc1, 0xfa, + 0xd1, 0x82, 0x9e, 0xd6, 0xf8, 0xf0, 0x2a, 0x8a, 0x81, 0x02, 0x7d, 0x14, + 0xb6, 0x57, 0x4c, 0x91, 0x78, 0x3c, 0x1d, 0xc4, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb4, 0xc4, 0xf4, 0x13, 0x96, 0x70, 0x6c, 0xf3, 0x6d, 0x6c, 0xd9, 0xff, + 0xb6, 0xf8, 0xa9, 0x4c, 0x46, 0x82, 0xa8, 0x69, 0x2a, 0xe9, 0xd8, 0xea, + 0xd8, 0x0a, 0xe8, 0x9d, 0x96, 0x4a, 0x01, 0xa5, 0xde, 0xc1, 0x49, 0x3d, + 0x96, 0xe7, 0x64, 0xb9, 0x49, 0x35, 0xf8, 0x8d, 0xfd, 0x95, 0xe7, 0xb5, + 0xfd, 0x19, 0x6e, 0xed, 0xa8, 0xc2, 0xaf, 0xe9, 0x94, 0x6d, 0xca, 0x07, + 0x25, 0xff, 0x51, 0x7d, 0x7b, 0xa3, 0xd8, 0xf7, 0xe0, 0x17, 0x41, 0x19, + 0x23, 0xfa, 0xa9, 0x28, 0x9f, 0x68, 0xb7, 0xf7, 0xba, 0x6e, 0x29, 0xe3, + 0xde, 0x65, 0x2f, 0xa4, 0xd6, 0x0e, 0x8c, 0xac, 0xf5, 0x82, 0xef, 0xa2, + 0x15, 0x7a, 0x23, 0xe9, 0x53, 0xb5, 0x03, 0x98, 0x1c, 0x48, 0x5c, 0xf5, + 0x23, 0xbd, 0x14, 0x56, 0xbb, 0x7e, 0x8c, 0x32, 0x2f, 0x7b, 0xf0, 0x06, + 0x22, 0x3e, 0x37, 0x74, 0x69, 0x75, 0x00, 0xfd, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(57, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_58(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xee, 0x8f, 0x7a, 0x02, 0x9a, 0xa7, 0xd2, 0x20, 0xa5, 0xa1, 0x9d, 0x28, + 0x5f, 0xff, 0x41, 0x1f, 0x2e, 0xd5, 0x66, 0xa1, 0x2e, 0xc3, 0xc8, 0x13, + 0xf9, 0x55, 0x9d, 0x22, 0x1d, 0xa3, 0x8e, 0x81, + }, + { + 0xb0, 0x28, 0xd4, 0xb9, 0x6d, 0x9a, 0x61, 0x80, 0x1d, 0x24, 0x53, 0xc4, + 0xb4, 0x2f, 0xaf, 0xdb, + }, + { + 0x28, 0x2c, 0xf8, 0x31, 0x13, 0x75, 0x83, 0x7c, 0x25, 0x77, 0xd3, 0x1c, + 0x50, 0x3e, 0xc0, 0x60, 0x23, 0xf8, 0xe2, 0xa5, 0xa0, 0xa2, 0xe5, 0xcf, + 0x9c, 0xb7, 0xd9, 0x11, 0x89, 0x9f, 0x2b, 0x5a, + }, + { + 0x4c, 0x7b, 0x59, 0xe4, 0xdf, 0xd6, 0x9c, 0x36, 0xfe, 0xd4, 0xa1, 0x28, + 0xd7, 0xe6, 0x3d, 0x5e, 0x76, 0x47, 0x14, 0x3f, 0x5d, 0x4a, 0xab, 0x55, + 0x51, 0x6e, 0xad, 0x95, 0x9c, 0x05, 0x94, 0x6a, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb6, 0xe8, 0x89, 0xd0, 0x2d, 0x5d, 0x4c, 0xd5, 0xa9, 0x37, 0xc7, 0x94, + 0x94, 0xe9, 0x92, 0x8c, 0x38, 0x3d, 0x5a, 0x3b, 0xb1, 0x1f, 0x6c, 0xea, + 0xa1, 0x80, 0xc7, 0x96, 0x47, 0x96, 0xac, 0x59, 0xfc, 0xc2, 0x46, 0x61, + 0x71, 0xd6, 0x1f, 0x53, 0x3c, 0xea, 0xee, 0x81, 0xb0, 0xdc, 0x76, 0x3f, + 0x0c, 0x62, 0xc4, 0x49, 0xb7, 0x79, 0xcd, 0x30, 0x3d, 0xdf, 0x56, 0xe1, + 0xce, 0x01, 0xdc, 0x12, 0x7b, 0xf1, 0xbb, 0x52, 0x67, 0x23, 0xfd, 0x7f, + 0x2f, 0x05, 0x46, 0x76, 0xd6, 0x51, 0xc9, 0x4d, 0xfb, 0x06, 0x23, 0xf9, + 0x72, 0x22, 0xe3, 0x42, 0x41, 0xb5, 0x65, 0x4d, 0x5d, 0x9f, 0x23, 0x1b, + 0x99, 0x41, 0x1c, 0x0f, 0x36, 0xd5, 0x7f, 0xcb, 0xd0, 0xed, 0x49, 0xe2, + 0xea, 0xc4, 0x7d, 0xb3, 0xf2, 0xa1, 0x22, 0x17, 0x8e, 0x11, 0x6d, 0x68, + 0xf0, 0x4f, 0xe0, 0x89, 0x88, 0x54, 0xe6, 0x95, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(58, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_59(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x10, 0xb8, 0x78, 0x9c, 0xdb, 0xd6, 0x77, 0x84, 0x42, 0xa4, 0x5e, 0xdf, + 0x22, 0x8b, 0x99, 0x23, 0xf4, 0x52, 0x63, 0x1a, 0xd0, 0xfe, 0x9e, 0x60, + 0x8d, 0x10, 0x82, 0x6b, 0xa7, 0x1d, 0xa7, 0xca, + }, + { + 0x15, 0x9f, 0xc5, 0xd8, 0xe5, 0x0e, 0xb5, 0x6e, 0x22, 0x97, 0x47, 0x89, + 0xb1, 0xdc, 0x20, 0xd1, + }, + { + 0x2d, 0xd5, 0x9e, 0x37, 0x76, 0x6c, 0x66, 0x75, 0x71, 0xb7, 0x79, 0xc0, + 0x6e, 0x12, 0xba, 0x21, 0x91, 0x88, 0x48, 0x97, 0x72, 0xf4, 0x86, 0x31, + 0xa6, 0x72, 0x8b, 0x5b, 0x86, 0x7e, 0x3c, 0xf4, + }, + { + 0x96, 0x6d, 0x94, 0x20, 0x38, 0x03, 0x05, 0x09, 0xb2, 0x0e, 0x61, 0x00, + 0x62, 0x04, 0x2b, 0x6b, 0xf1, 0x04, 0x81, 0x28, 0x18, 0x89, 0x32, 0x92, + 0xa6, 0x8d, 0x57, 0xd1, 0xce, 0x86, 0x51, 0x51, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x3e, 0x6a, 0xcd, 0x8b, 0x4e, 0x85, 0xb4, 0xa0, 0xf7, 0x92, 0x8f, 0x6b, + 0xd4, 0x1a, 0x8e, 0x6b, 0x52, 0x52, 0x4f, 0xe7, 0x27, 0x23, 0xa0, 0x50, + 0x96, 0x37, 0xd3, 0x3f, 0x15, 0xaf, 0xe7, 0xd8, 0xda, 0x6a, 0x15, 0x20, + 0x9b, 0x9e, 0x41, 0x49, 0x57, 0x6f, 0xbb, 0x1f, 0xd8, 0x31, 0xf7, 0x84, + 0xc0, 0x44, 0x39, 0xab, 0xda, 0x46, 0x05, 0xd0, 0x65, 0x56, 0xdc, 0x30, + 0x02, 0x05, 0x5b, 0x58, 0x55, 0xfb, 0xa2, 0x01, 0xf6, 0xda, 0xef, 0x79, + 0xf7, 0x8d, 0x00, 0x1e, 0xd6, 0x9e, 0xca, 0x8a, 0x41, 0x85, 0x13, 0xd0, + 0x24, 0x64, 0xe8, 0xd7, 0x42, 0xc2, 0x79, 0x9c, 0xd6, 0x8e, 0xdf, 0xbe, + 0x88, 0xae, 0x9b, 0x35, 0xa0, 0xaa, 0x06, 0x5c, 0x42, 0xa4, 0x77, 0x00, + 0x58, 0xc4, 0xb0, 0x26, 0xd0, 0x35, 0x0a, 0x7a, 0xfa, 0x9c, 0x52, 0xc3, + 0xc7, 0xfa, 0x05, 0x4f, 0x8a, 0x96, 0xd8, 0x87, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(59, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_60(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x98, 0x29, 0xd2, 0xe5, 0x40, 0x96, 0x29, 0xd9, 0xc5, 0x3c, 0x7d, 0xbb, + 0x16, 0xc6, 0x19, 0xb6, 0x16, 0xb0, 0xd1, 0x73, 0x94, 0xa3, 0xe0, 0x55, + 0xbf, 0x6f, 0xae, 0x9f, 0xcb, 0xbb, 0xaf, 0xd4, + }, + { + 0xe1, 0x5d, 0x27, 0x62, 0x63, 0x15, 0x16, 0x80, 0x7c, 0x1f, 0x07, 0x33, + 0x82, 0xe8, 0x52, 0x12, + }, + { + 0x25, 0x56, 0xe3, 0xd7, 0x5e, 0xef, 0xe6, 0xb6, 0x17, 0x13, 0x28, 0xe6, + 0x60, 0xbb, 0x65, 0x58, 0xda, 0xdf, 0xfa, 0xa1, 0xe0, 0x32, 0xe7, 0xeb, + 0xb6, 0xb3, 0x26, 0x2a, 0xdd, 0xe0, 0xdd, 0xeb, + }, + { + 0xa4, 0xf4, 0xe2, 0x8b, 0x33, 0x0b, 0x73, 0x38, 0x2f, 0xcc, 0x5c, 0x85, + 0x7e, 0xd6, 0x2e, 0x94, 0x5f, 0xd9, 0x71, 0x55, 0x40, 0x64, 0x54, 0x54, + 0x37, 0xa5, 0xd2, 0x2d, 0xdc, 0xbf, 0xf3, 0xee, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x74, 0x74, 0x02, 0xc5, 0x0d, 0xcc, 0xc3, 0xa6, 0x66, 0xd9, 0x4d, 0x2d, + 0x6f, 0x6f, 0x43, 0xfd, 0x2b, 0x50, 0x53, 0x84, 0x73, 0x3c, 0x97, 0x62, + 0xc2, 0xef, 0x84, 0x93, 0x6f, 0xb3, 0x29, 0xc3, 0x66, 0x54, 0x12, 0x88, + 0xfb, 0xc5, 0x78, 0xe9, 0x39, 0x7b, 0x5b, 0x11, 0x98, 0xf1, 0x66, 0x5f, + 0x8c, 0x37, 0x3d, 0xe8, 0x55, 0x6d, 0x3c, 0x08, 0xc6, 0x61, 0x9a, 0xa3, + 0xb3, 0x55, 0xdb, 0x20, 0x6f, 0x84, 0x0b, 0x6a, 0xa4, 0xcc, 0x72, 0x20, + 0x6d, 0x7f, 0xef, 0xb2, 0x43, 0x5d, 0x6b, 0x02, 0x4e, 0x4c, 0x15, 0x68, + 0xe9, 0xab, 0x31, 0xf7, 0x11, 0x0f, 0x43, 0x11, 0xb0, 0x5d, 0x79, 0x96, + 0xce, 0xba, 0x6e, 0x5e, 0x6b, 0xb9, 0x00, 0xf8, 0xe7, 0x21, 0xae, 0x10, + 0x6a, 0x95, 0x11, 0xf8, 0x92, 0x6d, 0xe2, 0xf8, 0x48, 0x71, 0x00, 0x69, + 0x8a, 0xa8, 0xfe, 0x99, 0x53, 0x88, 0xa0, 0x72, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(60, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_61(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x6a, 0xe8, 0x03, 0x03, 0x29, 0x23, 0x91, 0x33, 0x5b, 0xf9, 0xc9, 0x38, + 0x7f, 0xbd, 0x3b, 0xf6, 0x15, 0x75, 0x6c, 0x9c, 0x27, 0xc3, 0x47, 0x8c, + 0x87, 0xe2, 0x60, 0xcf, 0x97, 0xd4, 0x71, 0x10, + }, + { + 0x01, 0xe1, 0x62, 0x47, 0xdd, 0x4c, 0xae, 0x64, 0x99, 0x33, 0x7d, 0x82, + 0x78, 0x4e, 0xa5, 0x7f, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x03, 0x57, 0x02, 0xef, 0x4e, 0x11, 0x2b, 0x17, 0x31, 0x12, 0xc5, 0x85, + 0x1d, 0x07, 0xb2, 0x79, 0x30, 0x98, 0x63, 0x74, 0x0d, 0x38, 0xd0, 0xd0, + 0x72, 0x02, 0x23, 0xe2, 0x40, 0x17, 0xbb, 0xc0, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xcf, 0x43, 0x15, 0x59, 0x8f, 0xcd, 0x6a, 0xf1, 0x31, 0x55, 0x18, 0xc4, + 0xbf, 0xba, 0xc0, 0x54, 0x0c, 0x58, 0x96, 0x35, 0x27, 0x35, 0x48, 0xa7, + 0xb5, 0x07, 0xe7, 0xd2, 0xe6, 0x85, 0xe5, 0x94, 0x7b, 0x87, 0xae, 0x25, + 0x7e, 0x58, 0xfa, 0xf2, 0x14, 0xf2, 0xb5, 0x8e, 0xd1, 0x0c, 0x3b, 0xd3, + 0x5f, 0x75, 0xf6, 0xc3, 0x5d, 0xd6, 0xd4, 0x41, 0xc9, 0x3b, 0xcd, 0x42, + 0xe7, 0x17, 0x20, 0x10, 0x26, 0x31, 0xb1, 0xa6, 0xa4, 0xba, 0x24, 0x7c, + 0x17, 0x5e, 0xd8, 0x00, 0xcf, 0xca, 0x6e, 0x1e, 0x83, 0x9b, 0x5a, 0xa9, + 0x07, 0x60, 0x4c, 0xcf, 0xe6, 0xf9, 0x84, 0xf6, 0x82, 0x2e, 0x00, 0x1a, + 0xb0, 0x2d, 0xd6, 0x63, 0x49, 0x64, 0xf7, 0x89, 0xcb, 0x10, 0x7a, 0x97, + 0x73, 0x46, 0x69, 0x3f, 0x32, 0x44, 0xc8, 0x95, 0xe8, 0x40, 0xdf, 0xa0, + 0xed, 0xf7, 0xf1, 0x4d, 0xc6, 0x1d, 0x79, 0x4f, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(61, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_62(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xda, 0x2c, 0x40, 0x6c, 0x1a, 0x40, 0xf1, 0xbe, 0x98, 0xfd, 0xb2, 0x86, + 0x07, 0x8a, 0x92, 0x7f, 0x60, 0x6a, 0xe8, 0xec, 0x91, 0xab, 0x3a, 0x66, + 0x3f, 0xe2, 0x13, 0xfd, 0x8f, 0x05, 0x23, 0xf9, + }, + { + 0x4b, 0x49, 0x85, 0x7c, 0x62, 0x5f, 0x7a, 0x6c, 0xa2, 0x66, 0x9a, 0xba, + 0x21, 0x3d, 0x79, 0xcb, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x52, 0xc1, 0xc0, 0x06, 0xc5, 0x77, 0x96, 0x91, 0x79, 0xcc, 0x1f, 0xef, + 0xff, 0x1b, 0xb0, 0xdc, 0x42, 0x25, 0x5c, 0x35, 0x8b, 0x68, 0x6c, 0x73, + 0x21, 0x6d, 0xa1, 0x21, 0x6f, 0x82, 0xff, 0xfb, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5b, 0x6e, 0x8e, 0xf0, 0x30, 0x07, 0x12, 0xaa, 0xeb, 0x44, 0xa5, 0x2f, + 0x91, 0xca, 0x2f, 0x3d, 0xee, 0xfc, 0xee, 0xa9, 0x5c, 0xe2, 0x8e, 0x8c, + 0x4d, 0x93, 0x10, 0x12, 0x5a, 0x7d, 0x25, 0x9c, 0x34, 0x23, 0xb2, 0xcd, + 0x66, 0x2b, 0x33, 0x37, 0xae, 0xdf, 0x7d, 0xf1, 0x27, 0x19, 0xaf, 0x7b, + 0xe6, 0xca, 0xcb, 0x3a, 0x65, 0x65, 0x07, 0x0f, 0xaf, 0xc9, 0x86, 0xc3, + 0x36, 0x83, 0x6a, 0xa2, 0xe1, 0x8c, 0x23, 0x7b, 0x23, 0xff, 0x19, 0x33, + 0x9b, 0x4b, 0x5e, 0xf7, 0x04, 0x63, 0x4f, 0x16, 0x26, 0xd6, 0x6b, 0xce, + 0x9e, 0x72, 0x55, 0x51, 0x83, 0x74, 0x2b, 0x59, 0x13, 0x35, 0x82, 0x1c, + 0xe9, 0xc3, 0xa9, 0x5f, 0x2a, 0x1b, 0xea, 0xb6, 0xb0, 0x65, 0x9f, 0xfe, + 0x6e, 0x94, 0x0b, 0x55, 0x9d, 0xfb, 0x8a, 0x8d, 0xf1, 0xa4, 0x73, 0x30, + 0x8c, 0x31, 0x54, 0x58, 0x4e, 0xbf, 0x96, 0x22, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(62, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_63(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x5b, 0x77, 0xe8, 0x85, 0x05, 0x6b, 0x4f, 0xaf, 0x9d, 0x8e, 0xf9, 0xc8, + 0x57, 0x30, 0xfd, 0x50, 0x75, 0xf0, 0xa0, 0x70, 0x15, 0xc6, 0xdb, 0xd7, + 0x32, 0x3c, 0xe6, 0x3e, 0xa5, 0xd7, 0x1e, 0x42, + }, + { + 0x9a, 0xc3, 0xae, 0x89, 0xcf, 0xb2, 0x86, 0xb3, 0x11, 0x49, 0xe7, 0x8b, + 0xce, 0xd8, 0xcf, 0xf0, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x0d, 0xa5, 0xab, 0x25, 0x7b, 0x38, 0x96, 0x73, 0x85, 0x2c, 0xde, 0x48, + 0x00, 0xc0, 0x5a, 0xca, 0x59, 0x6e, 0xc5, 0x7c, 0x25, 0xd7, 0xda, 0x45, + 0x19, 0x11, 0x48, 0x7a, 0x5b, 0xa6, 0xbd, 0xaa, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x1d, 0x60, 0x4f, 0x4d, 0x5b, 0xb1, 0x0e, 0x11, 0x4a, 0xed, 0x67, 0x8a, + 0x51, 0x39, 0xbb, 0x46, 0xee, 0x69, 0x55, 0xd8, 0x6e, 0x06, 0x3d, 0x17, + 0xca, 0x5e, 0xf6, 0xdb, 0x38, 0x71, 0x51, 0x43, 0x0d, 0xb2, 0x3a, 0xa0, + 0xb4, 0x8a, 0x34, 0x3b, 0x2d, 0x35, 0x00, 0x3d, 0x29, 0x5f, 0xd0, 0x24, + 0xfc, 0x34, 0x4e, 0x7c, 0x01, 0x06, 0x49, 0x24, 0x84, 0x69, 0xda, 0x7d, + 0x9a, 0xb7, 0xe2, 0x50, 0x97, 0xbe, 0x35, 0xfe, 0xda, 0xd1, 0xba, 0x89, + 0xad, 0x66, 0xaf, 0x96, 0x80, 0x9c, 0x64, 0xba, 0x3b, 0x2e, 0xfe, 0x60, + 0x1c, 0x1d, 0x6c, 0x20, 0x1c, 0xa5, 0x5e, 0xa8, 0x2d, 0x90, 0x1a, 0xf1, + 0x46, 0xf2, 0x00, 0x29, 0x1b, 0x11, 0x3f, 0xbb, 0x05, 0x9a, 0x20, 0x43, + 0x28, 0x5a, 0x8d, 0x88, 0xee, 0x65, 0x5d, 0xa7, 0x6f, 0x83, 0x79, 0x08, + 0xec, 0xfc, 0x9b, 0xc0, 0xbb, 0xae, 0xc1, 0xc3, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(63, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_64(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x40, 0x30, 0xb2, 0xa9, 0x83, 0xa8, 0xe2, 0x14, 0xc9, 0xb6, 0x05, 0x3f, + 0x47, 0x4d, 0xeb, 0xb1, 0x35, 0x52, 0x2e, 0x2b, 0x0d, 0x50, 0xae, 0x98, + 0x44, 0x1b, 0xef, 0x99, 0xb9, 0x3e, 0x63, 0xb4, + }, + { + 0xd6, 0x29, 0x2c, 0x76, 0x33, 0xac, 0xc7, 0xa1, 0x7e, 0x79, 0x7a, 0x14, + 0x99, 0x43, 0xe6, 0xe4, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xea, 0x9f, 0xf3, 0x34, 0x4c, 0xba, 0x86, 0x34, 0xe8, 0x05, 0x8f, 0x09, + 0x35, 0x10, 0x51, 0x9c, 0x4c, 0xb9, 0x3a, 0x1a, 0xb4, 0x7c, 0x31, 0x23, + 0x67, 0x42, 0x95, 0x28, 0x0a, 0x26, 0x30, 0x9c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe9, 0x8a, 0x2d, 0x67, 0xd2, 0xd5, 0x2d, 0xc6, 0x12, 0x43, 0x7c, 0x57, + 0x87, 0xad, 0xad, 0x2f, 0x5d, 0xaa, 0x82, 0x90, 0x42, 0x3c, 0x45, 0xe5, + 0x90, 0x94, 0x55, 0xe7, 0x55, 0xf2, 0xd4, 0xa7, 0x29, 0xa6, 0xe6, 0xcb, + 0x42, 0xf3, 0x6b, 0x0e, 0x40, 0x57, 0x1f, 0x1d, 0x77, 0x21, 0xb4, 0x0e, + 0x3d, 0x4f, 0x77, 0x3d, 0x84, 0x5e, 0x72, 0x6e, 0x8e, 0x1e, 0x5b, 0xd9, + 0x50, 0x4a, 0x94, 0x59, 0x43, 0xf3, 0x34, 0x60, 0x3f, 0x28, 0x2b, 0xfc, + 0x7c, 0x5d, 0x8b, 0x2a, 0x6a, 0x1c, 0x82, 0xcc, 0xa1, 0xee, 0x94, 0x3b, + 0xe6, 0xc4, 0x64, 0xbc, 0xf8, 0xa4, 0xdf, 0x47, 0x0d, 0x3d, 0xdc, 0xd7, + 0xea, 0xb1, 0xe8, 0xbb, 0xa0, 0x09, 0x0e, 0x53, 0x7c, 0x36, 0x70, 0xf4, + 0x24, 0x43, 0x8e, 0x3a, 0x0b, 0x19, 0x72, 0x97, 0xa7, 0xa1, 0x6d, 0x12, + 0xa2, 0x82, 0x55, 0x8d, 0x55, 0x6f, 0x3b, 0x5e, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(64, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_65(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x94, 0x7b, 0x3f, 0x93, 0xa6, 0x01, 0xda, 0x15, 0xaa, 0xec, 0x58, 0x07, + 0x8d, 0x19, 0x8c, 0x20, 0xc9, 0x13, 0x79, 0xd5, 0xbf, 0x1c, 0x0d, 0xea, + 0x32, 0x96, 0x91, 0xf4, 0x7b, 0x3c, 0xdb, 0x40, + }, + { + 0x97, 0x69, 0x2e, 0xbc, 0x8c, 0x9b, 0x04, 0x5b, 0x73, 0xe8, 0x23, 0x50, + 0x0e, 0xba, 0x50, 0x77, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x59, 0x9f, 0xe8, 0x4d, 0x8a, 0x84, 0xc3, 0x06, 0xee, 0x33, 0x4a, 0x3b, + 0x44, 0x30, 0x05, 0xe3, 0x3b, 0xa0, 0xf8, 0xf5, 0x9b, 0x63, 0x6e, 0x67, + 0xd7, 0x4f, 0x8c, 0x59, 0x65, 0x58, 0xcf, 0x8e, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x38, 0x8d, 0xe4, 0xee, 0x5c, 0x19, 0xad, 0x97, 0x2c, 0x65, 0x0c, 0x86, + 0x5e, 0xc3, 0x4f, 0x7d, 0xb6, 0x69, 0x66, 0x9d, 0x32, 0x6f, 0x0c, 0x55, + 0x89, 0xc5, 0xab, 0x24, 0x10, 0xd6, 0x4f, 0x2d, 0x27, 0x14, 0x84, 0x3c, + 0xf5, 0xa2, 0x28, 0x8e, 0x37, 0x95, 0xfa, 0xe7, 0xf5, 0x41, 0xfd, 0xa4, + 0xbd, 0x4d, 0x48, 0x84, 0x01, 0x4c, 0xc7, 0x75, 0x8e, 0xc2, 0x97, 0x3b, + 0xce, 0x26, 0xa6, 0xb4, 0xc4, 0xda, 0x09, 0x11, 0xde, 0xba, 0x01, 0x64, + 0x24, 0x63, 0x0d, 0x30, 0xd5, 0xf3, 0x53, 0x6e, 0x4e, 0x79, 0x77, 0xdf, + 0xc7, 0x0f, 0x40, 0xb5, 0x30, 0x8f, 0x38, 0xef, 0x6e, 0x5a, 0x3d, 0xd7, + 0xa0, 0x60, 0xda, 0x5c, 0x68, 0xcc, 0xe2, 0x75, 0x05, 0x74, 0x5f, 0x57, + 0x68, 0x24, 0x5a, 0xb3, 0xc3, 0x1f, 0xdc, 0xc5, 0x40, 0xd3, 0x76, 0x7b, + 0x9f, 0xa6, 0x2d, 0x41, 0x71, 0xc7, 0x15, 0xc7, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(65, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_66(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xc8, 0x68, 0xe7, 0x22, 0x1f, 0xe5, 0x65, 0xc1, 0x3e, 0x46, 0xba, 0x78, + 0x14, 0x17, 0xda, 0x8c, 0xf4, 0x2b, 0xed, 0xc9, 0xbf, 0x5e, 0xca, 0xb8, + 0x98, 0xf6, 0x4f, 0x53, 0xa8, 0xe5, 0xbe, 0x2f, + }, + { + 0x49, 0x24, 0x05, 0x87, 0xc2, 0xf9, 0xe2, 0xc9, 0xaf, 0xae, 0x3a, 0x7a, + 0xa7, 0x06, 0x20, 0x80, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xa6, 0x98, 0x20, 0x3c, 0x5f, 0x5e, 0x55, 0x9d, 0x5f, 0x08, 0xdf, 0x28, + 0x23, 0x0a, 0xb3, 0xb1, 0xff, 0x40, 0x59, 0xce, 0x8e, 0x8b, 0x2b, 0x96, + 0x76, 0x88, 0x03, 0x13, 0xd1, 0x34, 0xf7, 0xfd, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x64, 0xe6, 0x9b, 0x9c, 0xdd, 0x82, 0x94, 0x57, 0x3c, 0x67, 0xe0, 0x6c, + 0xd6, 0x62, 0x66, 0x2e, 0x98, 0xcb, 0xca, 0xb9, 0xb8, 0xfc, 0x8c, 0x9a, + 0xd7, 0xd3, 0x66, 0xc3, 0xf9, 0x78, 0xf1, 0x0a, 0xf1, 0xbb, 0xd9, 0x93, + 0x4a, 0xdb, 0x9a, 0x31, 0x22, 0x8d, 0x0c, 0x51, 0xa2, 0x68, 0xac, 0xb7, + 0x76, 0xe3, 0xdf, 0x0d, 0x9a, 0x5d, 0xc4, 0x13, 0xda, 0x62, 0x36, 0xe7, + 0x7c, 0x15, 0xf2, 0x2d, 0xff, 0x41, 0x09, 0x11, 0x5e, 0x2e, 0x7a, 0x09, + 0xd4, 0x5d, 0x43, 0xf5, 0xa2, 0x69, 0x10, 0x4a, 0x71, 0x7e, 0x10, 0x1f, + 0x2c, 0x84, 0x27, 0x04, 0x9a, 0xb6, 0x58, 0x8d, 0xaf, 0x89, 0x07, 0xe3, + 0x31, 0x68, 0xee, 0xbe, 0xde, 0xcc, 0x47, 0x01, 0x90, 0x65, 0x57, 0xf9, + 0x7f, 0xd3, 0x4b, 0x72, 0x46, 0x42, 0xf2, 0x85, 0xc0, 0xb0, 0x6a, 0xbc, + 0x3c, 0xa1, 0x5b, 0xe6, 0x87, 0xc9, 0xbe, 0x1d, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(66, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_67(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x5b, 0x75, 0xc3, 0xc8, 0x00, 0x0a, 0x81, 0x72, 0x18, 0x24, 0xe9, 0x67, + 0x66, 0x62, 0x85, 0x12, 0x57, 0xff, 0x31, 0x5b, 0x9f, 0x20, 0x65, 0x63, + 0x1e, 0x4b, 0x1c, 0x31, 0xa8, 0x24, 0xed, 0x0f, + }, + { + 0x18, 0x71, 0xbf, 0x15, 0xff, 0x16, 0xe9, 0x4c, 0x9c, 0x8d, 0x93, 0xda, + 0x29, 0x51, 0x55, 0x66, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x99, 0x48, 0x67, 0xb4, 0x13, 0x45, 0x9c, 0x17, 0xa1, 0xe5, 0x07, 0x69, + 0xcb, 0x2d, 0xc3, 0x0a, 0x00, 0x12, 0xc8, 0xd5, 0x94, 0x74, 0x2e, 0xd4, + 0xea, 0x2c, 0x2a, 0xc4, 0x34, 0xbe, 0x33, 0x86, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x2b, 0x40, 0xdb, 0x08, 0xa5, 0xe1, 0x5e, 0xb1, 0x81, 0x7f, 0x05, 0x14, + 0x1c, 0xb0, 0xb5, 0x86, 0x46, 0x84, 0xea, 0x4e, 0x10, 0x04, 0xc2, 0x60, + 0x98, 0xb4, 0x83, 0x11, 0x9b, 0xde, 0x01, 0x75, 0x26, 0xdf, 0x8d, 0x39, + 0x3a, 0xbd, 0x6a, 0x26, 0x02, 0xf4, 0x2f, 0xe3, 0x52, 0x24, 0xea, 0x7d, + 0xee, 0xd2, 0xf6, 0x40, 0x3d, 0x92, 0xc4, 0x1d, 0xf8, 0x01, 0xab, 0x93, + 0x65, 0xce, 0x24, 0xa6, 0xa9, 0xae, 0xa9, 0x08, 0xdc, 0xf6, 0x11, 0x3e, + 0x02, 0xcb, 0x67, 0xae, 0x13, 0x01, 0x5b, 0x61, 0x74, 0xf2, 0x2c, 0xd9, + 0x43, 0x31, 0xa4, 0x79, 0xab, 0x03, 0xb7, 0xa1, 0x9d, 0xe2, 0x81, 0xe0, + 0x69, 0xa1, 0x7b, 0x60, 0x0c, 0x66, 0x49, 0xd7, 0xb8, 0x8e, 0x5b, 0xa3, + 0xf3, 0x40, 0xfb, 0xdb, 0x53, 0x7a, 0x9e, 0x45, 0x81, 0x49, 0x6c, 0x8e, + 0xaa, 0x40, 0xe5, 0xb8, 0x88, 0x62, 0xc4, 0xb0, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(67, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_68(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xbb, 0x44, 0x58, 0xcc, 0xeb, 0x0d, 0xce, 0x73, 0x32, 0xf3, 0x0c, 0xe9, + 0x0f, 0x69, 0xd8, 0x28, 0x25, 0xb5, 0x47, 0xbb, 0x51, 0x2a, 0xfb, 0xae, + 0x3e, 0x1c, 0xba, 0xaa, 0x4c, 0x17, 0x2b, 0x7b, + }, + { + 0x60, 0xbd, 0x6a, 0x33, 0xbe, 0xe6, 0x1d, 0x1a, 0x9b, 0xbf, 0xdd, 0xfe, + 0xe6, 0x0f, 0x7a, 0x18, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe8, 0x8a, 0x2a, 0xee, 0x17, 0xcc, 0x49, 0x16, 0x40, 0xf2, 0xe0, 0xa6, + 0x93, 0xf0, 0x3e, 0xbc, 0x48, 0xa9, 0x57, 0x90, 0x31, 0x86, 0x1d, 0xf3, + 0x1c, 0xdb, 0x42, 0x64, 0x99, 0x7f, 0x8a, 0x64, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5b, 0xea, 0x97, 0xa6, 0xda, 0xae, 0xe5, 0x40, 0xab, 0x6d, 0x41, 0x7c, + 0xa4, 0x58, 0x7c, 0x19, 0x8f, 0x58, 0x9d, 0xb5, 0xac, 0x72, 0xb4, 0xf1, + 0x38, 0x4b, 0x1b, 0x1d, 0x8c, 0x03, 0xec, 0x73, 0xb2, 0x97, 0x93, 0x9f, + 0x5a, 0x8b, 0x82, 0x40, 0xfd, 0x10, 0x33, 0xca, 0xce, 0x0e, 0x97, 0x1e, + 0x3c, 0x3f, 0x49, 0x23, 0x9b, 0x16, 0x85, 0x76, 0xf8, 0x3d, 0xce, 0x89, + 0x53, 0x37, 0x87, 0xfc, 0xb7, 0x25, 0x37, 0xb3, 0x2f, 0x58, 0x5d, 0xf1, + 0x35, 0x50, 0x64, 0xf7, 0xd7, 0x37, 0xb6, 0xc2, 0x52, 0x59, 0x5f, 0x16, + 0xc4, 0x2d, 0x77, 0xb8, 0x37, 0xfb, 0x7d, 0x4d, 0x44, 0xbd, 0x84, 0xdb, + 0xe8, 0x4d, 0x0b, 0xb5, 0xa4, 0x22, 0x44, 0x87, 0xfa, 0xe3, 0xca, 0x26, + 0xe9, 0x30, 0xe5, 0x4c, 0x27, 0xe2, 0xeb, 0xdd, 0xe9, 0x92, 0xe7, 0x6d, + 0xc4, 0xc4, 0x07, 0x77, 0x7a, 0xa4, 0xbd, 0x11, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(68, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_69(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x7e, 0x70, 0x38, 0x1b, 0xfb, 0xa7, 0x80, 0x7b, 0xc7, 0x73, 0xe2, 0xcd, + 0x68, 0x3f, 0x90, 0xc7, 0xad, 0x60, 0x6d, 0xcf, 0x46, 0x27, 0x67, 0x98, + 0x8b, 0x3f, 0x6c, 0x75, 0x8f, 0x5c, 0x79, 0x5d, + }, + { + 0x7e, 0x5a, 0xb4, 0x42, 0x70, 0x29, 0xe9, 0x9d, 0xf2, 0x20, 0x1d, 0x81, + 0xc3, 0xff, 0x28, 0x4e, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe0, 0xdd, 0x5b, 0x4e, 0x7c, 0xa7, 0x2a, 0xfd, 0xe5, 0x3c, 0x16, 0xb8, + 0x22, 0x54, 0x03, 0xbb, 0x6e, 0x74, 0x97, 0x42, 0xf3, 0xe3, 0x88, 0x96, + 0xfb, 0xf8, 0xf1, 0x8b, 0x7c, 0xe6, 0xf7, 0x99, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8a, 0xf2, 0x7c, 0x16, 0x3d, 0x25, 0xec, 0xf4, 0xf5, 0x39, 0x94, 0x4d, + 0x94, 0x50, 0xf5, 0x11, 0x6e, 0xa8, 0xaa, 0x7f, 0x97, 0x36, 0x1c, 0x69, + 0x6f, 0x8d, 0xc7, 0xd8, 0xb3, 0xaf, 0xe6, 0xff, 0xc0, 0x20, 0x14, 0x59, + 0xa1, 0x73, 0x3d, 0x9e, 0xe0, 0x9b, 0x2e, 0x45, 0xf3, 0xb6, 0xcd, 0x5f, + 0x45, 0xd9, 0xf9, 0xf4, 0x5f, 0xdc, 0x66, 0x2b, 0x56, 0x90, 0x59, 0x89, + 0x1f, 0x2e, 0x9e, 0xbc, 0x74, 0x0f, 0x78, 0x40, 0x4a, 0x0b, 0xb1, 0xc4, + 0x6a, 0x6b, 0xfe, 0xee, 0xed, 0x9c, 0x6b, 0x55, 0x2c, 0x5c, 0x46, 0x8a, + 0x49, 0x96, 0xad, 0x41, 0xcf, 0xff, 0x77, 0xae, 0x4d, 0x98, 0x96, 0xcb, + 0x80, 0xaf, 0x27, 0x63, 0x5a, 0x4e, 0x2a, 0x1b, 0x5c, 0x07, 0xc1, 0xb5, + 0x8b, 0x49, 0xc9, 0xa7, 0x68, 0x51, 0x14, 0x4e, 0x69, 0x03, 0x7e, 0x14, + 0xf7, 0xb8, 0x05, 0x16, 0x13, 0x29, 0xca, 0x15, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(69, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_70(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x2e, 0x54, 0x32, 0xac, 0xda, 0xb8, 0xca, 0x81, 0xee, 0x56, 0xf3, 0xe6, + 0x9a, 0x0c, 0x74, 0x8a, 0x72, 0xf8, 0x3e, 0x11, 0xd1, 0x8c, 0x2e, 0xf8, + 0xfc, 0x8a, 0xad, 0x56, 0x8e, 0x19, 0xe9, 0x1c, + }, + { + 0xca, 0x5f, 0x6e, 0xb3, 0x25, 0xe4, 0xa2, 0xb2, 0x4c, 0x00, 0x91, 0x5b, + 0xc3, 0x7d, 0x99, 0x41, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xae, 0x3d, 0x7a, 0xc0, 0x62, 0x2f, 0x7d, 0xc0, 0x69, 0xe5, 0x2c, 0xbd, + 0x15, 0x84, 0x47, 0x29, 0x79, 0xe1, 0xc8, 0xa9, 0x6b, 0xf4, 0x61, 0xc8, + 0xd3, 0x97, 0x6d, 0x8d, 0x53, 0x5c, 0x10, 0xec, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xfd, 0xa5, 0xdb, 0x4b, 0x28, 0xbb, 0xc5, 0xd2, 0xf6, 0xbd, 0x33, 0xac, + 0x98, 0x39, 0x9b, 0xcf, 0xcf, 0xa4, 0x60, 0x37, 0x47, 0x8c, 0xf2, 0x69, + 0xbf, 0x35, 0x9d, 0xb2, 0x28, 0x28, 0x06, 0x62, 0x71, 0x8f, 0x6d, 0x4c, + 0xa4, 0x77, 0xbb, 0x1c, 0xac, 0xa5, 0x67, 0x30, 0x9a, 0xba, 0xab, 0x08, + 0x32, 0xe7, 0x88, 0x58, 0x84, 0xe8, 0x6c, 0x4e, 0x0b, 0x01, 0x7e, 0x86, + 0x77, 0x74, 0x9c, 0x5d, 0xb2, 0xc3, 0x3e, 0x65, 0xfa, 0x53, 0x8d, 0xf4, + 0xae, 0xc4, 0x46, 0xc7, 0xca, 0x72, 0x4a, 0xf1, 0x8e, 0x45, 0x98, 0x36, + 0x01, 0x78, 0x5f, 0x98, 0x00, 0xa0, 0xc5, 0xb2, 0x3f, 0xea, 0xfb, 0xbd, + 0x34, 0x9d, 0x20, 0x4a, 0xe5, 0x4b, 0x40, 0xa0, 0x19, 0xa5, 0x7a, 0x83, + 0x68, 0xf0, 0x7d, 0x70, 0x94, 0x5f, 0x22, 0xbe, 0x24, 0xaa, 0x99, 0x2f, + 0x93, 0x0f, 0x92, 0xa6, 0x26, 0xbb, 0x22, 0xb6, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(70, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_71(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xef, 0xfa, 0xaf, 0x06, 0xcd, 0x99, 0x7b, 0x99, 0x78, 0x33, 0x72, 0xc5, + 0x15, 0x67, 0x2e, 0xde, 0x1a, 0x74, 0x16, 0x22, 0xa2, 0x04, 0x39, 0x53, + 0x45, 0x1c, 0x33, 0x66, 0x8e, 0x8d, 0xf4, 0x65, + }, + { + 0xfb, 0x92, 0x29, 0x10, 0xbc, 0x6c, 0x2a, 0xd0, 0x46, 0x1c, 0x98, 0x09, + 0xd1, 0x8a, 0x23, 0xf9, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x53, 0xce, 0x26, 0xba, 0xbc, 0x29, 0x4d, 0x2f, 0x1b, 0x48, 0xb5, 0x8a, + 0xec, 0xad, 0xab, 0x33, 0x08, 0xd8, 0x71, 0x18, 0x92, 0xcf, 0xa3, 0x93, + 0xf3, 0x58, 0x33, 0x5f, 0xc0, 0xf4, 0x67, 0x4e, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8a, 0xe5, 0x35, 0xa3, 0xcc, 0x00, 0xda, 0x2c, 0x81, 0x7e, 0x7f, 0x38, + 0x9a, 0x9b, 0xc9, 0x97, 0xd8, 0xe7, 0x20, 0xe3, 0x94, 0xbc, 0xd3, 0xa6, + 0xc2, 0x3e, 0xc6, 0x78, 0xed, 0x9d, 0xa4, 0x8d, 0x3d, 0x83, 0xe3, 0x2f, + 0x73, 0xd8, 0x96, 0xda, 0x58, 0x2a, 0x5c, 0x2b, 0x0f, 0x44, 0x12, 0x7b, + 0x3f, 0x7e, 0xd3, 0x6d, 0x91, 0xfc, 0x87, 0x7b, 0xbe, 0x91, 0x33, 0x90, + 0x64, 0x89, 0x0a, 0x4c, 0x2d, 0xb0, 0x5f, 0x16, 0xb5, 0x53, 0x61, 0x1d, + 0x68, 0x72, 0xc8, 0xbf, 0x40, 0x84, 0x34, 0x4c, 0x5d, 0xae, 0x08, 0xca, + 0x48, 0x17, 0x2f, 0x98, 0x22, 0x24, 0x4d, 0x4f, 0xf3, 0x72, 0xe0, 0x4c, + 0xe9, 0x9a, 0xed, 0x28, 0xc3, 0x94, 0x4c, 0x47, 0xfa, 0x43, 0x4e, 0x20, + 0xe9, 0x97, 0x30, 0xba, 0xf2, 0xbe, 0x9e, 0xe8, 0x52, 0x47, 0xf1, 0xb9, + 0x4b, 0x12, 0x9c, 0x3f, 0x6c, 0x3e, 0x0f, 0xe0, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(71, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_72(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x4a, 0x35, 0x42, 0xce, 0xa1, 0xb5, 0xa7, 0xb8, 0x93, 0x85, 0x15, 0x32, + 0x54, 0x98, 0x84, 0xa9, 0xeb, 0xa9, 0x36, 0x95, 0xbe, 0x8d, 0x76, 0x76, + 0x1d, 0xb6, 0x98, 0x31, 0xbd, 0x10, 0x53, 0xee, + }, + { + 0xff, 0x03, 0x20, 0xc4, 0x7e, 0x47, 0xb4, 0x40, 0x71, 0x8b, 0x80, 0xab, + 0x61, 0x6d, 0x7f, 0xff, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x86, 0x9a, 0xe8, 0xff, 0x94, 0x9a, 0x10, 0xc9, 0x3c, 0x05, 0xd6, 0x20, + 0xe4, 0xc4, 0xf1, 0x3d, 0x03, 0x76, 0xee, 0x1e, 0x00, 0xc7, 0x1b, 0xba, + 0x58, 0x83, 0xb3, 0xbc, 0x41, 0xf5, 0x24, 0x7b, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xad, 0xda, 0x83, 0xc6, 0x11, 0x88, 0x3e, 0x01, 0xf9, 0x58, 0xfe, 0xbf, + 0xf1, 0x05, 0x2b, 0x65, 0x8b, 0x0c, 0x84, 0xf8, 0x57, 0xad, 0x8d, 0x7d, + 0x18, 0xde, 0x89, 0x7d, 0xe2, 0xa8, 0xee, 0xaf, 0x39, 0x53, 0xd9, 0x40, + 0x7c, 0xbc, 0x4c, 0x05, 0x9c, 0x9f, 0xf9, 0xbf, 0xe6, 0x77, 0x44, 0xe1, + 0x34, 0x06, 0xcb, 0xfb, 0x09, 0xed, 0x31, 0xdc, 0x2f, 0xbc, 0xd9, 0x62, + 0x61, 0x29, 0xd0, 0xb6, 0xe4, 0xa8, 0x0a, 0xc3, 0xc1, 0xb2, 0x86, 0xd8, + 0x1f, 0x6f, 0x28, 0x18, 0x3a, 0x3e, 0x8c, 0xe2, 0x66, 0x68, 0x60, 0x05, + 0x60, 0x08, 0x4f, 0x3a, 0xde, 0xd9, 0x4e, 0xe5, 0x7d, 0xe1, 0x86, 0x57, + 0xf4, 0x43, 0x50, 0xf9, 0x75, 0x32, 0xa7, 0xc2, 0x5d, 0xcb, 0x99, 0xa8, + 0x68, 0x3a, 0xc3, 0xd6, 0x32, 0xa3, 0x76, 0x18, 0xeb, 0x9e, 0x2b, 0x18, + 0x54, 0x5c, 0x00, 0xb0, 0xc2, 0xcd, 0xc3, 0xc0, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(72, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_73(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xc5, 0x02, 0xa0, 0x09, 0xeb, 0x41, 0xc8, 0xf8, 0x22, 0x06, 0x66, 0xd4, + 0xe2, 0x33, 0x54, 0xb3, 0xd0, 0x86, 0xc8, 0xf6, 0xe0, 0x96, 0x28, 0xd2, + 0xa9, 0xbb, 0xe0, 0x72, 0x77, 0x0c, 0x99, 0xee, + }, + { + 0xbb, 0xfc, 0xb4, 0x61, 0x3c, 0x45, 0x03, 0x26, 0x8b, 0xc9, 0x07, 0x45, + 0xdf, 0x3c, 0xc8, 0x90, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x6d, 0xa4, 0xc1, 0x2b, 0x0a, 0xa1, 0x28, 0xa5, 0x8f, 0xee, 0xb8, 0x7a, + 0xbb, 0xea, 0x04, 0xee, 0xcf, 0xb2, 0xb4, 0x3c, 0x62, 0x93, 0xb8, 0x86, + 0x3d, 0xe3, 0x16, 0xae, 0x6e, 0xd2, 0x22, 0x21, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xc2, 0xa8, 0x78, 0x4f, 0xbc, 0xe4, 0xfa, 0x6e, 0x15, 0x84, 0x4f, 0xdd, + 0x8a, 0x84, 0x41, 0xd6, 0xb5, 0x6e, 0xbe, 0x6c, 0x0d, 0xb5, 0x76, 0xd6, + 0x81, 0xe0, 0x2b, 0xdb, 0x45, 0x9e, 0x4b, 0xaa, 0xdd, 0xe1, 0x7b, 0xd0, + 0xb8, 0x7d, 0xfa, 0xfc, 0x9f, 0x92, 0x94, 0x1d, 0x7c, 0xa8, 0x99, 0xa1, + 0x3f, 0x7e, 0x19, 0xeb, 0xd4, 0x92, 0xb3, 0x47, 0xf7, 0x75, 0x0d, 0x7c, + 0x43, 0xe6, 0x70, 0x28, 0x65, 0x47, 0x48, 0x57, 0x2d, 0xc9, 0x1d, 0x20, + 0x02, 0xb1, 0x44, 0x27, 0x18, 0x7c, 0xf3, 0x3d, 0x42, 0x1a, 0x56, 0xef, + 0xef, 0xbd, 0x62, 0x1a, 0x84, 0xde, 0x1e, 0x56, 0x64, 0xdf, 0x1c, 0xb2, + 0xe7, 0xef, 0xc3, 0x6b, 0xce, 0xf0, 0x3a, 0xca, 0xe1, 0x3b, 0x05, 0xea, + 0x10, 0x59, 0x76, 0xf8, 0x40, 0xea, 0x75, 0x9d, 0x68, 0x00, 0x4b, 0x40, + 0x43, 0xe8, 0xca, 0x76, 0xd5, 0x2c, 0x73, 0x66, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(73, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_74(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x30, 0x4f, 0x12, 0x9a, 0xfb, 0x5b, 0xa1, 0xe0, 0x62, 0xbd, 0x6c, 0x0d, + 0x85, 0x9e, 0x71, 0x61, 0xe3, 0xb9, 0xea, 0x53, 0xef, 0x52, 0x6f, 0x00, + 0x32, 0x95, 0x33, 0xb6, 0xbe, 0x12, 0xfa, 0xaf, + }, + { + 0x58, 0x56, 0x5e, 0x9d, 0x77, 0x6c, 0x89, 0xab, 0xf6, 0xcd, 0xa5, 0xe7, + 0x7c, 0xe7, 0xd2, 0x7b, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x19, 0x80, 0xa2, 0xd6, 0x5b, 0x26, 0xb7, 0xed, 0x3b, 0xfc, 0x2b, 0xa9, + 0x76, 0xf1, 0x4f, 0x14, 0x7d, 0xdb, 0x7f, 0xb1, 0x8c, 0x85, 0x43, 0xd0, + 0x46, 0x86, 0xe6, 0xad, 0xc0, 0x20, 0xcf, 0x72, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8c, 0xda, 0x68, 0xca, 0xf5, 0x7c, 0x12, 0xdd, 0x0a, 0x2b, 0x62, 0x8f, + 0xe8, 0x75, 0xd5, 0xe0, 0xbb, 0xa5, 0x09, 0x81, 0x41, 0x5a, 0x4a, 0xe2, + 0xd5, 0x88, 0x06, 0xaf, 0x4c, 0x23, 0xf0, 0x59, 0x78, 0xe3, 0x9e, 0x56, + 0x62, 0x69, 0x07, 0x6c, 0xd4, 0x3e, 0x36, 0xea, 0xa1, 0x02, 0x5e, 0x35, + 0x13, 0x95, 0x51, 0x4a, 0xe5, 0x07, 0x11, 0xb1, 0x87, 0xed, 0xe5, 0xcf, + 0xd8, 0x45, 0x8a, 0x7b, 0x8a, 0x7d, 0x97, 0x88, 0xc2, 0x12, 0x0d, 0x1d, + 0x71, 0xf6, 0x1e, 0xa9, 0x5d, 0x84, 0xa7, 0xff, 0x1e, 0x04, 0xf5, 0x14, + 0xe8, 0x44, 0x8b, 0xa2, 0xea, 0x6b, 0x95, 0x6a, 0xea, 0xfd, 0xc3, 0xeb, + 0xb6, 0xc1, 0xcd, 0x0c, 0x7b, 0x7e, 0xc7, 0x6b, 0x95, 0x8e, 0xef, 0xb8, + 0x12, 0xec, 0xb3, 0xe8, 0x6b, 0x33, 0xa4, 0xd3, 0xa7, 0xb2, 0x97, 0x7f, + 0x66, 0xb2, 0x14, 0x08, 0x96, 0x62, 0xd1, 0x4a, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(74, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_75(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xc5, 0x58, 0x92, 0x6a, 0x4d, 0xbb, 0x9f, 0x41, 0xe7, 0x56, 0x89, 0xd9, + 0xc8, 0xae, 0xc8, 0x67, 0x97, 0xc2, 0x9f, 0x8c, 0x77, 0xe3, 0x56, 0xf0, + 0x33, 0x1b, 0xed, 0x78, 0x8b, 0x76, 0xe9, 0xb7, + }, + { + 0xcf, 0x83, 0xe7, 0x71, 0x58, 0x26, 0xfd, 0x14, 0x89, 0xcc, 0x30, 0x54, + 0xd3, 0xcd, 0x57, 0x37, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd1, 0x20, 0x7c, 0x7b, 0x91, 0x4f, 0x5e, 0x87, 0x3e, 0xa0, 0xcf, 0x6f, + 0x06, 0xdb, 0xd0, 0x2d, 0x59, 0x49, 0x4f, 0x6c, 0x8d, 0x4c, 0x9a, 0xef, + 0x5a, 0xd1, 0x80, 0xc9, 0xbb, 0xbe, 0xe2, 0x08, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd3, 0xa7, 0xd7, 0x8c, 0xfe, 0x76, 0xff, 0x97, 0xbc, 0x54, 0xf7, 0xf6, + 0x94, 0xf7, 0x2f, 0x31, 0x24, 0x41, 0xd8, 0x60, 0x8d, 0x3c, 0x15, 0x13, + 0xfd, 0x28, 0xe9, 0x47, 0x42, 0xcb, 0x19, 0x68, 0x3a, 0x02, 0x70, 0x83, + 0x9b, 0x02, 0x6c, 0xee, 0x52, 0xe4, 0x92, 0x4d, 0xee, 0x99, 0x9e, 0xe8, + 0xcd, 0x7d, 0xd0, 0x1e, 0xa4, 0x45, 0xcf, 0x91, 0x00, 0x87, 0x98, 0xb8, + 0xed, 0x64, 0xc8, 0x45, 0x8d, 0x86, 0x78, 0xc3, 0x44, 0xd4, 0xe3, 0xfe, + 0x32, 0x01, 0xc1, 0xaf, 0x2f, 0xae, 0x3b, 0xea, 0x82, 0xea, 0x3a, 0xf0, + 0xcd, 0xac, 0x8e, 0x77, 0xb5, 0xe4, 0xd7, 0xc2, 0xb0, 0x84, 0xe4, 0x16, + 0xe5, 0x32, 0x23, 0x66, 0xad, 0x13, 0xe3, 0x6b, 0x45, 0x5f, 0x04, 0x7b, + 0xa4, 0x64, 0xcf, 0xf2, 0x87, 0xaf, 0x37, 0x22, 0x97, 0xc6, 0x8b, 0x51, + 0xaa, 0x47, 0x01, 0x90, 0x19, 0x43, 0xaa, 0xc8, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(75, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_76(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x63, 0x3d, 0x32, 0xe3, 0x00, 0x5f, 0x78, 0x11, 0x47, 0x23, 0xb3, 0xea, + 0x5a, 0xc1, 0x21, 0xba, 0x74, 0xaa, 0x00, 0xc5, 0x2d, 0x93, 0x96, 0x67, + 0xe3, 0x0c, 0x33, 0x51, 0xb3, 0x85, 0x49, 0xf7, + }, + { + 0x37, 0xaf, 0xff, 0x50, 0x4a, 0x2d, 0x8a, 0xc1, 0x68, 0xc6, 0x8e, 0x24, + 0xd0, 0xfe, 0x66, 0xf6, + }, + { + 0x9f, 0x16, 0x99, 0xc9, 0x9d, 0x60, 0xb0, 0x85, 0xbc, 0x61, 0xcb, 0x11, + 0x0e, 0xf8, 0xab, 0x59, 0x0d, 0x82, 0xa9, 0x70, 0x02, 0x1c, 0x3c, 0x6a, + 0x5d, 0x48, 0x02, 0x1c, 0x45, 0xde, 0x49, 0x56, + }, + { + 0x3e, 0x33, 0x47, 0xc5, 0x47, 0xf1, 0x7f, 0x4d, 0x0b, 0x9f, 0x46, 0x40, + 0x5a, 0x54, 0xee, 0xdd, 0x7e, 0x98, 0x0d, 0x06, 0xa2, 0x15, 0xec, 0x15, + 0xe8, 0x93, 0x16, 0xab, 0x74, 0x3b, 0x75, 0x47, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x6e, 0x38, 0xe8, 0x29, 0x62, 0xd7, 0x07, 0xce, 0x9a, 0x6a, 0xc3, 0x83, + 0xa7, 0x38, 0xa7, 0x48, 0xf9, 0x75, 0xeb, 0x78, 0x56, 0x11, 0xfa, 0xd5, + 0xe3, 0xf5, 0xa4, 0xfe, 0x44, 0xd7, 0xb5, 0x9a, 0x98, 0x13, 0x7a, 0x2b, + 0xcd, 0xc3, 0x5f, 0x9e, 0xe9, 0xa1, 0xe2, 0x1b, 0xb1, 0x7d, 0xf1, 0x66, + 0x5c, 0xd1, 0x39, 0x76, 0x25, 0xa1, 0x77, 0x24, 0x7e, 0x2e, 0x32, 0x9a, + 0x66, 0x01, 0x40, 0x63, 0x61, 0x41, 0x56, 0x06, 0x10, 0xa3, 0x68, 0xbf, + 0xd4, 0x99, 0xc2, 0xe2, 0x5b, 0xe3, 0x18, 0xaa, 0x4d, 0xa9, 0xe7, 0xa3, + 0x52, 0xd1, 0x15, 0xdb, 0x82, 0x82, 0xed, 0x8d, 0x79, 0xec, 0xf9, 0xcd, + 0x82, 0x03, 0x60, 0xd3, 0xd2, 0xd1, 0xa5, 0x8a, 0x93, 0xe0, 0x40, 0xf5, + 0x55, 0x48, 0x87, 0xce, 0x6c, 0x98, 0x58, 0xbc, 0x2b, 0xb1, 0x02, 0x24, + 0x99, 0x80, 0xa8, 0x58, 0x49, 0x8a, 0xbc, 0xda, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(76, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_77(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xcb, 0x20, 0x15, 0x2e, 0x99, 0xd8, 0xca, 0x5e, 0x80, 0x95, 0xa1, 0x3e, + 0x72, 0xe0, 0xc1, 0xbb, 0x9e, 0x6c, 0xbe, 0xad, 0xbd, 0x0b, 0xf4, 0xe7, + 0x0f, 0xc6, 0xfa, 0x3c, 0x81, 0xec, 0x5d, 0x0f, + }, + { + 0x0a, 0x55, 0xd4, 0x33, 0xd3, 0x74, 0x4a, 0x2f, 0x38, 0x19, 0x39, 0xbe, + 0x85, 0xc9, 0x7a, 0x98, + }, + { + 0xb5, 0xbd, 0x74, 0x29, 0x59, 0x1e, 0x5e, 0x29, 0x14, 0x53, 0x2a, 0x7d, + 0xea, 0x75, 0xff, 0x76, 0xca, 0xa3, 0x9f, 0x15, 0x27, 0x9c, 0x73, 0x09, + 0x2c, 0x2c, 0xac, 0x3b, 0x0d, 0x28, 0xc1, 0x3b, + }, + { + 0xd0, 0x8c, 0xa9, 0x6d, 0x74, 0x5f, 0x7e, 0x3a, 0x9f, 0x2a, 0xcb, 0xc1, + 0xe8, 0x00, 0xa9, 0x81, 0x95, 0x52, 0x2a, 0x4f, 0x7c, 0x60, 0x7a, 0xad, + 0x62, 0xf3, 0x8b, 0x1f, 0x63, 0x35, 0x4b, 0xd1, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x03, 0xe8, 0xcd, 0x60, 0x76, 0x82, 0x62, 0xcf, 0x4c, 0xc2, 0xf2, 0x95, + 0x50, 0x6c, 0x24, 0xf0, 0x6f, 0xb3, 0xfd, 0x3a, 0x88, 0x9c, 0x71, 0x52, + 0x14, 0x51, 0xdf, 0x6f, 0x2e, 0xfa, 0x07, 0x47, 0xff, 0xb8, 0x75, 0x78, + 0xb7, 0x1b, 0xcf, 0xc3, 0x7d, 0x3a, 0x43, 0xf8, 0x5a, 0xb4, 0xe5, 0xfc, + 0x02, 0xd2, 0x1a, 0x90, 0xe8, 0x5a, 0xf1, 0x8d, 0x6d, 0x75, 0xe9, 0xfa, + 0x95, 0xf7, 0xf9, 0x29, 0x42, 0xa2, 0x93, 0xda, 0x5d, 0x31, 0xa6, 0xb7, + 0x77, 0xf1, 0x10, 0xff, 0x86, 0x27, 0x91, 0x42, 0x8b, 0xa0, 0x1b, 0x3c, + 0x1b, 0x2f, 0xb4, 0xb2, 0x36, 0x63, 0x18, 0xd2, 0x44, 0xa9, 0x1e, 0xc1, + 0x30, 0xf4, 0xc0, 0xbd, 0xb8, 0xc4, 0x0c, 0xb7, 0xa6, 0x23, 0xe5, 0xed, + 0x02, 0x0b, 0xb3, 0x05, 0xa3, 0x8b, 0x13, 0x47, 0x12, 0x15, 0x1b, 0x48, + 0x91, 0xda, 0x7f, 0xfb, 0x06, 0x91, 0x2f, 0x4b, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(77, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_78(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xbd, 0xcb, 0xcf, 0x6d, 0x34, 0x75, 0xac, 0x89, 0x03, 0xdd, 0x32, 0xcb, + 0x12, 0x54, 0x36, 0xa6, 0xf4, 0xce, 0x74, 0x64, 0x49, 0x60, 0x43, 0xa1, + 0x80, 0xb2, 0x60, 0xd2, 0xa0, 0x0e, 0xed, 0xa1, + }, + { + 0x4e, 0x63, 0xef, 0x1d, 0xd0, 0x4d, 0x3e, 0x6c, 0xa8, 0xa8, 0x09, 0x9d, + 0x7e, 0x3d, 0xa0, 0x95, + }, + { + 0xe0, 0xb7, 0x81, 0x6c, 0xae, 0x86, 0x74, 0xb8, 0x73, 0x08, 0x54, 0x1f, + 0xdd, 0x65, 0xc0, 0xf8, 0x11, 0xb7, 0x80, 0x8f, 0x3f, 0x2f, 0xc1, 0x5f, + 0x57, 0x7d, 0x64, 0x74, 0x8e, 0xe3, 0x6d, 0x4b, + }, + { + 0x04, 0x1d, 0x73, 0x1b, 0x34, 0x97, 0xb4, 0x19, 0x09, 0xde, 0xec, 0xaf, + 0xff, 0x8b, 0x71, 0x16, 0x08, 0x5d, 0x8e, 0xf2, 0x8c, 0x32, 0xf4, 0x23, + 0x3f, 0x6c, 0x66, 0x0e, 0x77, 0xa9, 0x9b, 0xb6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xd1, 0x0f, 0x8e, 0x09, 0xba, 0x93, 0x52, 0x69, 0xd8, 0xc3, 0x87, 0x62, + 0xad, 0xca, 0xf2, 0x83, 0x08, 0xd2, 0x5d, 0xce, 0xcc, 0x19, 0xff, 0xdb, + 0xf7, 0x93, 0xa9, 0xc6, 0x75, 0x85, 0xcb, 0x79, 0x1d, 0xf6, 0x5a, 0x24, + 0xda, 0x8b, 0xa2, 0xb7, 0x79, 0x41, 0xf7, 0x01, 0xde, 0x86, 0x3b, 0xe3, + 0xd6, 0xf3, 0xc9, 0xd1, 0x3f, 0x44, 0x45, 0x97, 0x19, 0x38, 0x7b, 0x51, + 0x36, 0x53, 0x46, 0x63, 0x86, 0x2b, 0x70, 0xc7, 0xdc, 0xf9, 0x91, 0x31, + 0xde, 0x59, 0x25, 0x30, 0xb3, 0xce, 0xdc, 0x61, 0x68, 0x98, 0xd3, 0x65, + 0x6e, 0x20, 0x64, 0xd8, 0x79, 0x14, 0x9d, 0xb2, 0x54, 0xd2, 0x6e, 0x72, + 0xc5, 0x46, 0x6a, 0xd5, 0x5b, 0x1a, 0xc6, 0xfe, 0x52, 0x43, 0x86, 0xa0, + 0x99, 0xaa, 0x64, 0x2a, 0xd0, 0x96, 0xa0, 0x93, 0x3f, 0x92, 0xdb, 0x03, + 0xe9, 0x41, 0x70, 0xe0, 0x5d, 0xa5, 0x00, 0xe5, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(78, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_79(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x0c, 0xf0, 0x73, 0x1c, 0x47, 0xca, 0x73, 0xe8, 0xc4, 0x29, 0x42, 0xcc, + 0x61, 0xf9, 0x98, 0xf5, 0x34, 0x2e, 0x31, 0x8c, 0xb8, 0xed, 0x3b, 0x18, + 0x69, 0x02, 0x0e, 0x3d, 0xab, 0x1e, 0x12, 0x67, + }, + { + 0x60, 0x4c, 0x64, 0x15, 0x4f, 0x91, 0x4e, 0xd0, 0xcf, 0x63, 0xc8, 0x61, + 0x65, 0x3b, 0x78, 0xd4, + }, + { + 0x30, 0x50, 0xb2, 0xdf, 0x2f, 0x59, 0x76, 0x3e, 0x44, 0x3c, 0xaa, 0x92, + 0x5a, 0x54, 0xde, 0x1e, 0x5c, 0xed, 0x87, 0x59, 0xb5, 0x54, 0xb5, 0xf0, + 0xf6, 0x8c, 0xb0, 0x1b, 0x41, 0x50, 0xf9, 0x99, + }, + { + 0xed, 0xa0, 0x82, 0xed, 0xfa, 0xf4, 0xf9, 0x76, 0x6d, 0xe2, 0x9a, 0xe2, + 0xcb, 0x93, 0x0f, 0xb1, 0xbc, 0x26, 0xbd, 0xe6, 0xd1, 0x8a, 0xb1, 0x6f, + 0x66, 0xfb, 0xf4, 0xb0, 0x6d, 0x3e, 0x74, 0x80, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x39, 0xb3, 0xf4, 0x7c, 0x02, 0x4b, 0xc8, 0x4a, 0xad, 0x80, 0x91, 0x13, + 0x6d, 0x34, 0x1e, 0xba, 0x3a, 0x89, 0xd0, 0x65, 0x77, 0xaa, 0x4f, 0xd3, + 0xd2, 0x4f, 0x8b, 0x7a, 0x5b, 0xe4, 0x28, 0x0f, 0xdf, 0x62, 0x35, 0x34, + 0x90, 0xd5, 0xf6, 0x6c, 0x1a, 0x7d, 0x57, 0xcf, 0x19, 0x8a, 0x63, 0x37, + 0x56, 0xc0, 0x90, 0x71, 0x86, 0xa7, 0x1a, 0x4f, 0xea, 0x41, 0xc3, 0xfa, + 0x42, 0xef, 0xee, 0xfb, 0x0a, 0xc2, 0x85, 0xea, 0x85, 0x87, 0xf1, 0xa8, + 0xd8, 0xfb, 0xb7, 0x83, 0xae, 0x62, 0x7c, 0x1e, 0x85, 0x8f, 0xfb, 0xe0, + 0x51, 0xd6, 0xb7, 0xa2, 0xa5, 0x18, 0xa2, 0x4e, 0x71, 0xd5, 0x54, 0xe8, + 0xa0, 0xda, 0x3d, 0x54, 0xbc, 0x69, 0xe4, 0xca, 0x94, 0x0b, 0x7c, 0xa3, + 0x20, 0xc4, 0xbc, 0x44, 0xdf, 0x1e, 0x47, 0x6e, 0x05, 0xe4, 0x89, 0xa2, + 0xc6, 0x68, 0x70, 0x2b, 0x0b, 0xb8, 0x91, 0x3d, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(79, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_80(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x97, 0x15, 0x5a, 0x62, 0x4e, 0xe4, 0x2b, 0x97, 0x4c, 0x4b, 0xc9, 0xe0, + 0xb9, 0xa7, 0x37, 0xeb, 0x79, 0x0c, 0xde, 0x2f, 0x0a, 0x93, 0xf8, 0xef, + 0x2c, 0x6f, 0xe7, 0x20, 0x15, 0xc5, 0x27, 0x6b, + }, + { + 0x44, 0x4d, 0xf2, 0xbe, 0xae, 0x4a, 0xe6, 0xe9, 0xa6, 0x40, 0x41, 0x6f, + 0xc3, 0x94, 0x8d, 0xde, + }, + { + 0x62, 0x5c, 0x7e, 0xf0, 0xfa, 0x30, 0xe0, 0xcb, 0x5c, 0x28, 0xff, 0x3a, + 0x23, 0x96, 0x63, 0x93, 0x24, 0x29, 0x2b, 0x20, 0x06, 0x9e, 0xcb, 0x1c, + 0x01, 0x63, 0xd9, 0x66, 0xf2, 0x52, 0x0e, 0x61, + }, + { + 0x40, 0x1b, 0x91, 0xbb, 0xd7, 0x26, 0xeb, 0x24, 0xeb, 0x19, 0xb4, 0xf3, + 0x62, 0x88, 0x19, 0x2a, 0xe0, 0x71, 0x35, 0x91, 0x7d, 0xec, 0x75, 0xb7, + 0xf7, 0x75, 0x81, 0x77, 0x76, 0x72, 0x98, 0xb7, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x8b, 0x1c, 0x56, 0xcd, 0x41, 0x5d, 0xdf, 0x12, 0x3b, 0xc5, 0xbb, 0x32, + 0x7f, 0x0e, 0xc4, 0xcf, 0x53, 0xa6, 0x49, 0x83, 0x1d, 0x7c, 0x09, 0x20, + 0xe7, 0x42, 0x03, 0x3c, 0xe1, 0x83, 0xa4, 0x42, 0x3c, 0x4b, 0x16, 0x2e, + 0xac, 0xa3, 0x15, 0x7c, 0xb1, 0x94, 0xdc, 0xe0, 0x6a, 0x54, 0x3b, 0xf1, + 0x55, 0x16, 0x4c, 0x70, 0x41, 0x75, 0x0f, 0xb3, 0xaf, 0xc7, 0x78, 0x92, + 0xbd, 0x7b, 0x45, 0x2a, 0x20, 0xb6, 0x48, 0x90, 0x18, 0xe5, 0x36, 0x9f, + 0xce, 0x4e, 0x7e, 0xb7, 0x93, 0x54, 0xea, 0x8a, 0x03, 0x38, 0x80, 0xa6, + 0xdb, 0x0a, 0x79, 0xee, 0x0c, 0x1c, 0xa1, 0x5d, 0x80, 0x75, 0x12, 0x31, + 0x2c, 0x3f, 0x2d, 0x82, 0xbd, 0xf0, 0x06, 0x83, 0x64, 0xcc, 0x3e, 0xae, + 0x76, 0x3b, 0xe2, 0x4e, 0xdb, 0x39, 0x35, 0x6d, 0xc1, 0xa6, 0xd1, 0xc5, + 0xeb, 0x09, 0x3c, 0xde, 0x4b, 0xf9, 0xa5, 0x89, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(80, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_81(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x88, 0xe9, 0xbc, 0x0e, 0x56, 0xbb, 0xbf, 0xe8, 0xc0, 0x7f, 0x31, 0x1b, + 0x95, 0x5d, 0x2b, 0x87, 0x7f, 0xe7, 0x04, 0x7f, 0x3f, 0x85, 0xac, 0x83, + 0xf9, 0xda, 0x68, 0xac, 0x2a, 0xbe, 0x36, 0xe2, + }, + { + 0x2c, 0xf7, 0x59, 0x3a, 0x98, 0x12, 0x25, 0x25, 0xc2, 0x81, 0xd3, 0xce, + 0xc1, 0xe2, 0xb9, 0x4c, + }, + { + 0x0d, 0x28, 0x96, 0x1b, 0x6a, 0xba, 0xd3, 0x01, 0x91, 0xb2, 0x14, 0x70, + 0xba, 0x1e, 0xe0, 0x0d, 0xa1, 0x70, 0x37, 0x90, 0xdd, 0x8a, 0x15, 0x53, + 0x73, 0x97, 0xc7, 0x3e, 0x80, 0xeb, 0x7f, 0xbc, + }, + { + 0xe3, 0x28, 0x52, 0xb8, 0x1c, 0x80, 0xf3, 0x7d, 0x79, 0xcf, 0xfd, 0x3c, + 0xae, 0x78, 0x59, 0x10, 0xe7, 0x92, 0x32, 0x81, 0x3d, 0x17, 0x4a, 0x2d, + 0x14, 0xf0, 0xbf, 0x27, 0x5f, 0x31, 0x29, 0x4b, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x4a, 0x6b, 0x13, 0xbd, 0xe6, 0xcb, 0xf8, 0x66, 0xd1, 0xb6, 0x09, 0x42, + 0x48, 0x8c, 0xef, 0x40, 0x86, 0x36, 0x7f, 0xd4, 0xe2, 0x44, 0x5f, 0x73, + 0xed, 0xef, 0x03, 0x28, 0xf6, 0x94, 0x1d, 0x40, 0x84, 0xa4, 0x46, 0x98, + 0x62, 0x81, 0x2f, 0xf6, 0xe4, 0xd9, 0xe4, 0x19, 0x2e, 0x29, 0xd5, 0x9d, + 0x56, 0x2e, 0x5d, 0xaf, 0xa0, 0xae, 0x10, 0x94, 0x4f, 0x8b, 0x62, 0xad, + 0x15, 0xa8, 0xf4, 0x83, 0xd6, 0xd1, 0x0e, 0xed, 0x6c, 0x4f, 0xe4, 0x26, + 0x45, 0x58, 0x7b, 0x61, 0x25, 0xd8, 0x63, 0x65, 0x37, 0x10, 0xbd, 0x6a, + 0x21, 0x27, 0x7a, 0xe4, 0x49, 0xb7, 0xd2, 0xa9, 0x79, 0x78, 0x29, 0x74, + 0xa7, 0x31, 0xda, 0x60, 0x1b, 0x29, 0xbc, 0x8e, 0x31, 0xfa, 0x12, 0x1b, + 0x8b, 0x7e, 0x95, 0xd1, 0xeb, 0x30, 0xa7, 0x5b, 0x3d, 0x4f, 0xb2, 0x13, + 0x1e, 0x17, 0xfd, 0xea, 0xa0, 0x39, 0x5e, 0xa6, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(81, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_82(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xdf, 0x81, 0x88, 0xfe, 0x2b, 0x7b, 0xc5, 0xed, 0x26, 0xf7, 0x47, 0xc9, + 0x3e, 0xd4, 0x80, 0x24, 0xe3, 0xed, 0x62, 0x75, 0x30, 0x10, 0x7d, 0x94, + 0x90, 0x6b, 0xb2, 0xde, 0xbd, 0x4f, 0xb9, 0x2b, + }, + { + 0x0d, 0xd7, 0x50, 0xc7, 0x4f, 0x83, 0x63, 0xc1, 0x4c, 0x17, 0x2b, 0x40, + 0x98, 0xf5, 0x20, 0x58, + }, + { + 0x8a, 0x9b, 0xa6, 0xbd, 0xb3, 0x05, 0x9e, 0xc8, 0x8b, 0xb2, 0x9e, 0x1c, + 0x51, 0x60, 0x51, 0xf8, 0xf9, 0x58, 0xb3, 0xc7, 0x75, 0x1f, 0xb3, 0x7a, + 0x61, 0x6e, 0x9d, 0x4a, 0x6c, 0xf1, 0x7a, 0x79, + }, + { + 0x1b, 0x21, 0x45, 0xc0, 0xeb, 0x75, 0x77, 0x50, 0x30, 0xd1, 0x68, 0x1c, + 0x84, 0x8b, 0x92, 0x49, 0xda, 0xcb, 0x81, 0x37, 0xa3, 0xa0, 0xfe, 0x26, + 0x54, 0x4d, 0x17, 0xa2, 0x37, 0x4a, 0x51, 0x82, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb9, 0x25, 0xc2, 0x7c, 0x1b, 0x2a, 0x82, 0xe6, 0x96, 0x9a, 0x90, 0xfe, + 0x4e, 0x4b, 0x6f, 0x27, 0xc3, 0x69, 0xe8, 0x2b, 0x4b, 0x03, 0x47, 0x9a, + 0x9a, 0x15, 0x2a, 0xca, 0x12, 0x88, 0xb2, 0x62, 0x42, 0x0f, 0xaa, 0x6c, + 0x62, 0xda, 0x1f, 0x22, 0x5d, 0xc7, 0xf3, 0x12, 0x5d, 0x42, 0x88, 0x58, + 0x50, 0x78, 0x8b, 0x26, 0x44, 0x10, 0xc8, 0x14, 0x9e, 0xab, 0xf6, 0xba, + 0x16, 0x4c, 0x17, 0x32, 0xa2, 0xb6, 0x0b, 0x77, 0xa5, 0x25, 0xec, 0x74, + 0x5b, 0xac, 0x6e, 0xda, 0x51, 0xec, 0x7d, 0x88, 0xd1, 0x1b, 0x40, 0xc2, + 0xe1, 0x28, 0x54, 0xd3, 0x92, 0xe7, 0xc6, 0xaf, 0x2f, 0xff, 0x7a, 0xaf, + 0x15, 0x44, 0xab, 0x30, 0x6a, 0xc3, 0x1b, 0x6d, 0x97, 0x1b, 0x70, 0xa8, + 0x2a, 0x67, 0x2c, 0x81, 0xe9, 0x28, 0x20, 0x4d, 0x04, 0x96, 0x0e, 0xbf, + 0xf5, 0xbf, 0x5e, 0x38, 0xaa, 0x89, 0x7f, 0x23, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(82, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_83(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x6a, 0xeb, 0x84, 0xcf, 0x5f, 0x72, 0x98, 0x2b, 0xf7, 0xb1, 0xef, 0x4c, + 0xa1, 0x6f, 0x8a, 0x27, 0x96, 0x5c, 0x35, 0xb2, 0xa5, 0x55, 0x61, 0x94, + 0x6c, 0x6d, 0x2c, 0xf6, 0xa6, 0xf9, 0xe4, 0x1e, + }, + { + 0x82, 0x76, 0x07, 0xb8, 0x06, 0xdf, 0x2c, 0x42, 0x37, 0x41, 0x20, 0x9b, + 0xed, 0x59, 0xb4, 0xeb, + }, + { + 0xc2, 0x53, 0x73, 0xb6, 0x1d, 0x8d, 0x58, 0x2f, 0xc2, 0x68, 0xcb, 0xd6, + 0x49, 0x3a, 0x91, 0x61, 0xee, 0xbe, 0xde, 0x96, 0xc4, 0x3b, 0x02, 0x95, + 0x28, 0x1c, 0xc8, 0xac, 0x47, 0x38, 0x24, 0xe7, + }, + { + 0x57, 0x54, 0x81, 0x26, 0x38, 0x1e, 0xd8, 0x62, 0x67, 0x05, 0xd3, 0x53, + 0x71, 0x22, 0x80, 0x0c, 0x4c, 0xd9, 0xef, 0x81, 0x32, 0x04, 0x4d, 0xfd, + 0x0f, 0x8d, 0x27, 0xd5, 0xeb, 0xce, 0x55, 0xd1, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb2, 0x0c, 0x3a, 0xe8, 0x13, 0x3b, 0x87, 0x20, 0x49, 0x8c, 0x17, 0xfc, + 0xa0, 0xb9, 0xa2, 0xf7, 0x04, 0x57, 0x26, 0xfd, 0xc1, 0x5e, 0x71, 0xa6, + 0xd3, 0x9e, 0x18, 0x95, 0x49, 0xb0, 0x2d, 0x39, 0x92, 0xa7, 0x4b, 0xfa, + 0x9d, 0x68, 0xec, 0xca, 0x5f, 0xf1, 0x71, 0x89, 0x0e, 0xe5, 0xba, 0xfc, + 0x4e, 0x59, 0xbf, 0xc6, 0x62, 0xfd, 0xb2, 0x45, 0x8e, 0xf2, 0x44, 0xe5, + 0x4e, 0x03, 0xfa, 0x43, 0xa0, 0x61, 0x67, 0x97, 0xbd, 0xca, 0x83, 0xb6, + 0xef, 0x8f, 0x36, 0xda, 0xd2, 0x80, 0xc9, 0xdf, 0xb1, 0xca, 0x56, 0xd3, + 0xaa, 0x5e, 0x2d, 0xa3, 0x2a, 0xaf, 0xe2, 0xf6, 0x89, 0xf5, 0x1a, 0x43, + 0xc7, 0x54, 0x7d, 0x24, 0xed, 0x94, 0xd0, 0x2a, 0x56, 0x7f, 0x78, 0x55, + 0xaa, 0xaf, 0xc8, 0xb6, 0x94, 0xea, 0x5f, 0x0b, 0xb5, 0x60, 0x2f, 0x72, + 0xda, 0xbf, 0x86, 0x56, 0xe7, 0x43, 0x58, 0xb2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(83, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_84(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x49, 0xce, 0xab, 0x47, 0xef, 0x95, 0x58, 0x5a, 0xaa, 0xeb, 0x98, 0x06, + 0x4c, 0x61, 0xe8, 0xa2, 0x89, 0xee, 0xe5, 0x41, 0x2f, 0x4a, 0xf1, 0xfb, + 0x6e, 0x48, 0xa1, 0x23, 0x58, 0xf9, 0xcf, 0x67, + }, + { + 0xd4, 0x8e, 0x4a, 0x8a, 0x61, 0x2c, 0xac, 0x57, 0xfe, 0x7b, 0xc1, 0x78, + 0x8c, 0x64, 0x83, 0x6b, + }, + { + 0x62, 0x1e, 0x31, 0x3b, 0x13, 0x34, 0x80, 0xd5, 0xc4, 0x71, 0xba, 0xe8, + 0xda, 0x09, 0x7a, 0x03, 0x33, 0xb2, 0xb2, 0xea, 0x23, 0xf8, 0x3c, 0x1b, + 0x10, 0x28, 0x50, 0xd4, 0x11, 0xd1, 0x51, 0x5c, + }, + { + 0x84, 0x40, 0x7b, 0x20, 0xd0, 0xad, 0xc2, 0x2c, 0x07, 0xbf, 0x24, 0x94, + 0x08, 0x0a, 0xd2, 0x86, 0x93, 0x8b, 0x21, 0x28, 0xf8, 0x24, 0xda, 0xe3, + 0xe4, 0x4d, 0x3c, 0x71, 0x81, 0x87, 0x02, 0xc0, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xdf, 0xb9, 0xcc, 0xd2, 0x74, 0x93, 0x63, 0xfd, 0x99, 0x3d, 0xf5, 0xdb, + 0x53, 0x82, 0x6d, 0xc3, 0x6a, 0xdf, 0x4e, 0x04, 0x08, 0x78, 0xf6, 0x85, + 0x15, 0x14, 0x46, 0x6d, 0xd7, 0x21, 0x4b, 0xa7, 0x0d, 0x35, 0xf4, 0x74, + 0xb2, 0x2d, 0x5d, 0x18, 0x0d, 0x71, 0xf8, 0xca, 0x00, 0x49, 0xfc, 0x90, + 0x15, 0x6d, 0x6d, 0x79, 0x67, 0x08, 0x28, 0x0c, 0xe1, 0xd2, 0x25, 0x18, + 0x4b, 0x06, 0xdb, 0xe3, 0xd7, 0x98, 0xb7, 0xb9, 0x02, 0x85, 0x62, 0xd2, + 0x22, 0xf1, 0x1e, 0xe8, 0xfe, 0xd9, 0xa9, 0x55, 0x87, 0xa6, 0x53, 0x6e, + 0x90, 0x7a, 0xde, 0xe3, 0x10, 0x2b, 0x2f, 0x3d, 0x92, 0xdb, 0x24, 0x67, + 0x37, 0xa9, 0xbc, 0x71, 0xaa, 0xaa, 0x4f, 0x40, 0xcd, 0xa3, 0x3d, 0x33, + 0xa3, 0x37, 0x9d, 0x2e, 0x8b, 0xfe, 0xd1, 0x76, 0x0e, 0xc1, 0x28, 0x01, + 0xe7, 0x2a, 0x38, 0x4b, 0x74, 0x8f, 0xfa, 0xf5, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(84, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_85(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xf3, 0x22, 0xb2, 0x58, 0xc6, 0x29, 0x51, 0xd3, 0x7b, 0xa6, 0x80, 0xab, + 0xc4, 0x9a, 0x61, 0x98, 0x3f, 0x3f, 0xd8, 0x99, 0x73, 0x94, 0x0c, 0x1d, + 0x4f, 0x07, 0x65, 0xc9, 0x5d, 0x0d, 0x70, 0x78, + }, + { + 0x0b, 0x79, 0xd5, 0xbe, 0xfe, 0x42, 0x85, 0xa7, 0x3e, 0xa4, 0xb4, 0x8e, + 0x2b, 0xa1, 0x85, 0xc1, + }, + { + 0x05, 0x32, 0xbc, 0x7e, 0x99, 0x70, 0x90, 0x06, 0xaa, 0x19, 0x1b, 0x37, + 0x9a, 0xce, 0xfa, 0x16, 0x45, 0xc6, 0x7d, 0x2f, 0x5b, 0x61, 0xf1, 0x3f, + 0x36, 0xf8, 0x68, 0xbc, 0xe4, 0x44, 0xa5, 0x29, + }, + { + 0x2e, 0x4e, 0x16, 0x74, 0x8e, 0xbf, 0x36, 0x59, 0x02, 0xd9, 0x10, 0xa0, + 0x1d, 0x9c, 0xa2, 0x4a, 0xeb, 0x8e, 0x3e, 0x54, 0x58, 0xed, 0xfd, 0x88, + 0xf6, 0xb9, 0x09, 0xc1, 0xff, 0xc7, 0x46, 0x8c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x85, 0x5e, 0xe8, 0xe0, 0x06, 0x0c, 0xb8, 0xb4, 0xfc, 0x56, 0x92, 0x07, + 0x3f, 0x62, 0xcc, 0x3e, 0x19, 0xa1, 0x9b, 0x89, 0xdf, 0x2d, 0xf9, 0x7c, + 0x2a, 0x21, 0x87, 0x9d, 0x74, 0x57, 0x1d, 0x33, 0x62, 0xec, 0xdd, 0x1a, + 0xd9, 0xe4, 0x64, 0x58, 0xe3, 0x5f, 0x5f, 0x35, 0x80, 0xe7, 0x66, 0x06, + 0x7e, 0x3d, 0x8f, 0x72, 0x58, 0xd8, 0xee, 0xcb, 0x17, 0xa0, 0x75, 0xf7, + 0xdc, 0x75, 0x23, 0xa4, 0x78, 0xb5, 0xd1, 0x77, 0xf6, 0x73, 0x65, 0x9e, + 0x38, 0x87, 0x67, 0x0e, 0xdf, 0x6e, 0x8f, 0x0f, 0xf7, 0x5e, 0x26, 0xd4, + 0x1a, 0xdf, 0xee, 0x6a, 0xe2, 0x8f, 0xbe, 0x5c, 0x2e, 0x24, 0x7e, 0x10, + 0x36, 0x24, 0x1e, 0x1f, 0x5b, 0xf3, 0x16, 0xfb, 0xd9, 0xad, 0xb3, 0xc1, + 0x59, 0x30, 0xe8, 0x42, 0x5a, 0xe7, 0x50, 0x24, 0xc2, 0x77, 0x02, 0x99, + 0x72, 0xf0, 0xd6, 0xc6, 0x45, 0xb4, 0xa1, 0x17, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(85, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_86(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x33, 0xa6, 0x8b, 0xad, 0x0f, 0xa3, 0x44, 0xfd, 0x6a, 0x46, 0xf7, 0x5f, + 0x04, 0x28, 0xcb, 0xdf, 0x27, 0x11, 0xd3, 0xf0, 0xc7, 0xef, 0x0f, 0x6a, + 0x39, 0x50, 0x73, 0xed, 0x70, 0x89, 0x7b, 0xaa, + }, + { + 0x18, 0x92, 0x79, 0x9f, 0xeb, 0x41, 0x0b, 0x9d, 0xd6, 0xe6, 0x9b, 0xf4, + 0x40, 0x3e, 0xfc, 0x20, + }, + { + 0x67, 0x7e, 0xcc, 0xd0, 0xc6, 0xe0, 0x1a, 0x26, 0x3f, 0xc7, 0xd2, 0xe2, + 0xc2, 0xd0, 0xc6, 0x29, 0x4a, 0x30, 0x7b, 0xf3, 0xee, 0x1b, 0xa3, 0x53, + 0x72, 0xc2, 0x16, 0x6d, 0x04, 0x04, 0x29, 0x72, + }, + { + 0xa6, 0x44, 0x7d, 0xdb, 0xfa, 0xf7, 0xea, 0x07, 0xe1, 0x0a, 0x95, 0xdb, + 0x1f, 0xae, 0x3e, 0xa8, 0x6d, 0x10, 0x3c, 0xfc, 0xdd, 0xa5, 0x50, 0xf1, + 0x10, 0x1b, 0x02, 0xdd, 0xc5, 0xac, 0x46, 0x0c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x22, 0x91, 0x43, 0x3d, 0xf6, 0xfa, 0x57, 0x25, 0x89, 0xc3, 0xa6, 0x51, + 0x3f, 0x38, 0x1a, 0xf4, 0x21, 0x27, 0x87, 0x49, 0x9b, 0xad, 0x08, 0x64, + 0xcb, 0x36, 0xd0, 0xeb, 0xee, 0x3b, 0x56, 0xe3, 0x40, 0xab, 0x7b, 0xdb, + 0x9f, 0x3b, 0x0e, 0x0d, 0x61, 0xdb, 0xa6, 0xb0, 0x14, 0x35, 0x77, 0x21, + 0x08, 0xbd, 0x89, 0x21, 0xcf, 0xc0, 0x0b, 0xeb, 0xd2, 0x07, 0x66, 0x94, + 0x41, 0x84, 0x04, 0x6a, 0x84, 0xf5, 0x6c, 0x43, 0x19, 0x69, 0x58, 0x80, + 0xd2, 0x43, 0x45, 0xac, 0xc6, 0x4f, 0x85, 0x79, 0xd3, 0xca, 0x30, 0xc1, + 0xf5, 0x4e, 0x41, 0x1c, 0xff, 0x51, 0x5e, 0xd7, 0x2a, 0x8f, 0xca, 0xa5, + 0xd2, 0xa1, 0x5f, 0xc2, 0x52, 0x6d, 0x5d, 0x11, 0x6f, 0xa1, 0x78, 0x3f, + 0xff, 0x6d, 0x70, 0xd1, 0x56, 0xb6, 0xe3, 0x3b, 0xf3, 0x1d, 0x21, 0x0d, + 0x3e, 0xe7, 0x9c, 0x44, 0xb7, 0x3e, 0xaa, 0x7e, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(86, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_87(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x31, 0x36, 0xf4, 0x42, 0xdd, 0x3c, 0xdc, 0x24, 0x95, 0x38, 0xbd, 0x5f, + 0x0e, 0xb3, 0x55, 0xc7, 0x67, 0x0a, 0xdd, 0x64, 0x27, 0xd1, 0xe1, 0x80, + 0x31, 0x7b, 0x7d, 0x64, 0x96, 0x78, 0x0b, 0x83, + }, + { + 0x83, 0x65, 0x57, 0x29, 0x4d, 0x84, 0x4f, 0x21, 0x80, 0xd3, 0x7a, 0xc0, + 0x57, 0xcb, 0xb8, 0x69, + }, + { + 0x48, 0x34, 0xc6, 0x8e, 0x72, 0xe2, 0x5a, 0xce, 0xc7, 0xce, 0x57, 0x7e, + 0xfd, 0x4d, 0xc9, 0x74, 0x6b, 0x8a, 0xbb, 0x89, 0xa4, 0x46, 0xad, 0x39, + 0xdb, 0x70, 0x42, 0xce, 0xb6, 0xda, 0x9c, 0xde, + }, + { + 0xc6, 0x6a, 0x48, 0x65, 0xfb, 0x9b, 0x0f, 0x86, 0xf0, 0x69, 0x6d, 0x4a, + 0x2e, 0x1e, 0xa5, 0xf7, 0xa3, 0x93, 0x15, 0x7d, 0x09, 0x69, 0x29, 0xdf, + 0xf4, 0x5f, 0x64, 0xe7, 0x45, 0xd0, 0x6a, 0x3c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xed, 0xb8, 0x11, 0x68, 0x13, 0x0e, 0xc4, 0x33, 0x01, 0x6e, 0x07, 0x42, + 0x93, 0x74, 0x07, 0x31, 0x37, 0xe0, 0xec, 0x1d, 0x14, 0x64, 0xe6, 0x3a, + 0xd2, 0xdd, 0x24, 0xbf, 0xe5, 0xcb, 0x76, 0x3a, 0xa8, 0x79, 0x3d, 0x8f, + 0xb3, 0x2e, 0xb2, 0xc7, 0x0e, 0xb6, 0x70, 0x53, 0x7f, 0xce, 0x9f, 0x7e, + 0x53, 0xc4, 0x2d, 0x4b, 0xd8, 0x5d, 0xbe, 0x0b, 0x2f, 0x50, 0xf4, 0x40, + 0xcb, 0x13, 0x2c, 0xe6, 0xcc, 0x46, 0xfa, 0xe1, 0x08, 0x69, 0xda, 0x2a, + 0xe6, 0xab, 0x8c, 0x10, 0xc3, 0xa1, 0xff, 0x2e, 0x45, 0x29, 0xe4, 0x6c, + 0x8f, 0x84, 0x3e, 0x0c, 0xf9, 0x31, 0xb7, 0x70, 0xec, 0xf0, 0xd0, 0x63, + 0x9f, 0x1a, 0x5d, 0x93, 0x94, 0x29, 0x96, 0x01, 0x71, 0x4c, 0xdd, 0xab, + 0xea, 0x3d, 0x00, 0x4d, 0x24, 0xda, 0x00, 0x56, 0x66, 0x51, 0x48, 0x48, + 0xd2, 0xfe, 0x0a, 0x1c, 0x07, 0xc7, 0x8f, 0x11, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(87, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_88(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x2e, 0x9b, 0xeb, 0x64, 0xfb, 0x0f, 0xd6, 0xfe, 0xa5, 0x9b, 0x58, 0x73, + 0xdc, 0x0a, 0x94, 0x6e, 0x8a, 0xf6, 0x8a, 0xfb, 0xf8, 0xf1, 0x63, 0x58, + 0x12, 0x4b, 0x4a, 0x56, 0x79, 0xa1, 0xa8, 0xdb, + }, + { + 0x05, 0xfa, 0xc5, 0x86, 0xd8, 0x8f, 0x7d, 0xdd, 0x6f, 0xd8, 0x49, 0xe5, + 0xbd, 0x93, 0x32, 0xe1, + }, + { + 0x81, 0xa6, 0x57, 0xd8, 0x96, 0xe2, 0x94, 0xdb, 0x49, 0x77, 0xb5, 0x26, + 0x53, 0xb8, 0xea, 0x29, 0xc8, 0x9e, 0xb2, 0xcd, 0xfd, 0xd9, 0x95, 0x67, + 0x6c, 0x81, 0x35, 0xba, 0x6e, 0x8d, 0xd3, 0x1f, + }, + { + 0x0c, 0xc8, 0x1f, 0x75, 0x7d, 0x01, 0x42, 0x73, 0x66, 0xbb, 0x76, 0x4b, + 0x40, 0x37, 0x8c, 0x10, 0x24, 0xcf, 0x88, 0x13, 0x6b, 0xcc, 0x36, 0x24, + 0x3c, 0xdf, 0x11, 0x1c, 0x28, 0xd9, 0x76, 0xf8, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xde, 0x24, 0x72, 0x30, 0xbc, 0x5e, 0x80, 0x5a, 0x67, 0x88, 0xa4, 0xce, + 0x2b, 0xdd, 0x42, 0x87, 0x04, 0xc0, 0x76, 0x68, 0x63, 0x1f, 0x85, 0x91, + 0x78, 0x12, 0xcb, 0x04, 0xef, 0x3b, 0x76, 0x92, 0xe7, 0x26, 0x3a, 0x43, + 0x3a, 0x66, 0xcb, 0x78, 0x50, 0x4a, 0xdb, 0x04, 0xf5, 0xb6, 0x03, 0x95, + 0x68, 0x47, 0x83, 0xf4, 0x1a, 0x3c, 0x93, 0x7a, 0xd0, 0xe1, 0x0c, 0xb6, + 0x9c, 0x4e, 0x80, 0x95, 0x47, 0x7f, 0xf4, 0x37, 0x8b, 0x8a, 0x3a, 0xe0, + 0x6c, 0x9a, 0x03, 0xe9, 0x85, 0xbf, 0x14, 0xb9, 0x99, 0xd2, 0x76, 0xa4, + 0x5c, 0x27, 0x76, 0x2b, 0x4c, 0x09, 0xc5, 0x38, 0x72, 0xfe, 0xfc, 0xff, + 0xf0, 0x34, 0x96, 0xc1, 0xc8, 0x83, 0x3d, 0xaa, 0x4b, 0xb6, 0x09, 0x28, + 0xb4, 0x4a, 0x6c, 0x63, 0xaa, 0x44, 0x04, 0x03, 0x51, 0x53, 0x65, 0x90, + 0x7e, 0xd4, 0xd6, 0xcc, 0x87, 0x87, 0xb8, 0x92, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(88, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_89(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x51, 0x15, 0xf6, 0x8f, 0xf0, 0x85, 0x32, 0xab, 0xc3, 0x07, 0x7b, 0x0a, + 0x49, 0xf9, 0xeb, 0x9c, 0x29, 0x02, 0xfa, 0xb5, 0x23, 0x43, 0x9f, 0xb6, + 0x89, 0x15, 0x7f, 0xf9, 0xf0, 0x39, 0x97, 0xaf, + }, + { + 0x41, 0xdf, 0x1a, 0xc0, 0x1f, 0x8c, 0xa0, 0x29, 0xff, 0xf6, 0x03, 0x4d, + 0x57, 0xd0, 0x93, 0xd0, + }, + { + 0x1e, 0x92, 0xf8, 0xea, 0xb8, 0x16, 0x68, 0x25, 0x91, 0x5a, 0x56, 0xbb, + 0xb0, 0x0c, 0x4b, 0x25, 0x77, 0xcd, 0xc9, 0x9c, 0x36, 0x12, 0x62, 0x69, + 0xfc, 0xfe, 0xd6, 0x82, 0xb1, 0x2b, 0x06, 0xed, + }, + { + 0x0b, 0x24, 0x5e, 0x6e, 0x6e, 0xd2, 0x3e, 0x17, 0x1a, 0x02, 0xd5, 0x2f, + 0x1f, 0x1a, 0x52, 0x0e, 0xd5, 0x0d, 0x67, 0xae, 0xdc, 0xf9, 0x99, 0xa9, + 0x06, 0x3e, 0xae, 0x51, 0xb3, 0xb3, 0x3e, 0x08, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5b, 0x1e, 0xde, 0x46, 0xc5, 0x8a, 0x3d, 0x79, 0xcf, 0x63, 0x05, 0xae, + 0x59, 0xfc, 0xde, 0xdd, 0x1f, 0x88, 0xf1, 0xfe, 0x35, 0x14, 0xf6, 0xb8, + 0x16, 0x67, 0xeb, 0x65, 0x91, 0x72, 0xa1, 0x20, 0xb7, 0x0d, 0x12, 0x8d, + 0x23, 0xcd, 0xcf, 0x2a, 0xdd, 0xb9, 0xb9, 0x7c, 0xda, 0x13, 0x7a, 0xe3, + 0x02, 0xbc, 0x99, 0x3e, 0x9e, 0x40, 0x5b, 0x50, 0x85, 0xd8, 0xa0, 0xdf, + 0x2e, 0x4b, 0x9e, 0x0f, 0x4a, 0xcc, 0x64, 0x4a, 0x0b, 0xd4, 0x9c, 0xf6, + 0x0d, 0xd2, 0x17, 0x0c, 0x0e, 0xab, 0x8d, 0xf5, 0x37, 0x39, 0x78, 0xd8, + 0x9e, 0x41, 0x5f, 0xf6, 0x89, 0x10, 0x80, 0xae, 0xed, 0xed, 0xe6, 0x26, + 0x6e, 0xf1, 0x22, 0xd4, 0x48, 0xa0, 0xb2, 0x05, 0x74, 0xcc, 0x51, 0x1c, + 0x3b, 0xdf, 0x35, 0x38, 0x4f, 0x58, 0x87, 0x8a, 0x04, 0xeb, 0xcc, 0x86, + 0x2f, 0x2f, 0x1d, 0xd3, 0xc9, 0x3a, 0x10, 0x1a, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(89, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_90(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xdc, 0x59, 0x04, 0xbd, 0x75, 0x2c, 0x66, 0xe0, 0x25, 0x07, 0x26, 0x22, + 0x82, 0x4e, 0x4e, 0x78, 0x9d, 0xfa, 0xfe, 0xdc, 0xba, 0xad, 0x33, 0x56, + 0xa3, 0x44, 0x95, 0x3e, 0x00, 0x2f, 0xf8, 0x45, + }, + { + 0x1a, 0xa5, 0x63, 0x88, 0x3b, 0xba, 0x44, 0x4c, 0x88, 0x50, 0x0e, 0xcf, + 0xcc, 0xa2, 0xaf, 0x94, + }, + { + 0xab, 0x75, 0x4f, 0x51, 0xc0, 0x3f, 0x29, 0xeb, 0x77, 0x03, 0xca, 0x5e, + 0x4c, 0x8b, 0x10, 0xe1, 0x68, 0x49, 0x4a, 0x1f, 0x09, 0xb5, 0x44, 0x17, + 0x5b, 0xd8, 0x7b, 0x68, 0x7b, 0xf6, 0x9f, 0x7d, + }, + { + 0xbb, 0xba, 0x28, 0x0c, 0x3e, 0x22, 0x07, 0x21, 0x2f, 0x18, 0xf7, 0x8d, + 0xba, 0x28, 0x62, 0x92, 0x0c, 0x2e, 0x1b, 0x69, 0xb8, 0xc9, 0x53, 0x1d, + 0xcf, 0x8a, 0x5c, 0x98, 0x1b, 0xf4, 0x38, 0x65, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x2f, 0x7d, 0x00, 0x53, 0xb5, 0x08, 0x3a, 0xe0, 0x49, 0x52, 0x4f, 0x18, + 0xa2, 0x5d, 0x07, 0x83, 0xdb, 0xff, 0xd2, 0xe5, 0x31, 0xf6, 0x73, 0xf8, + 0x7b, 0xbc, 0x28, 0x71, 0xc0, 0xc4, 0xbf, 0xcc, 0xbe, 0xb5, 0x44, 0xa0, + 0x9d, 0xc2, 0x08, 0xcf, 0xc7, 0x58, 0x2b, 0x48, 0x84, 0xc9, 0x94, 0xbf, + 0x84, 0xaa, 0xed, 0x1b, 0x55, 0xcd, 0x88, 0xe9, 0x56, 0x43, 0x02, 0x08, + 0x8c, 0xb5, 0x49, 0x92, 0xc4, 0x00, 0x26, 0xca, 0xcd, 0xd0, 0x28, 0x31, + 0x92, 0x6d, 0x11, 0xbf, 0x19, 0x94, 0xe0, 0x8e, 0xf2, 0xe9, 0x40, 0xf1, + 0xa7, 0xac, 0xc1, 0xcb, 0x3b, 0xdd, 0x4a, 0x3a, 0xfb, 0x2e, 0xe3, 0xa7, + 0xde, 0xfe, 0xfb, 0x6b, 0xa8, 0x7a, 0x5e, 0xf1, 0x82, 0x8c, 0x84, 0x02, + 0x86, 0x63, 0x1c, 0xf1, 0xc8, 0x84, 0x22, 0xba, 0x90, 0xe3, 0x95, 0x4b, + 0x42, 0x1b, 0x0a, 0x86, 0x9a, 0x9f, 0xde, 0xe1, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(90, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_91(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xea, 0x28, 0x92, 0x6c, 0xd5, 0xdf, 0x4f, 0xef, 0xd5, 0x72, 0xc9, 0x10, + 0x3d, 0x87, 0xff, 0xb0, 0x4f, 0x59, 0x9d, 0xa9, 0x5e, 0x1e, 0x6f, 0xec, + 0xb8, 0x4f, 0x53, 0xf7, 0x3f, 0xd0, 0x0d, 0x6c, + }, + { + 0xcb, 0x40, 0xe1, 0x66, 0x55, 0xb9, 0xa2, 0xc7, 0x1e, 0x8e, 0x36, 0x77, + 0xb9, 0xea, 0x6c, 0x6f, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x3d, 0x2d, 0x1d, 0xb8, 0x8b, 0x84, 0x62, 0x78, 0x7a, 0x55, 0x76, 0xc9, + 0x5f, 0xd6, 0x60, 0x73, 0x4f, 0xb6, 0x81, 0xf8, 0x94, 0xe8, 0xef, 0xc4, + 0x7e, 0x3b, 0xe3, 0xbf, 0xc3, 0x09, 0x8e, 0x40, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe9, 0x29, 0xc6, 0xe7, 0x49, 0xc5, 0x17, 0x50, 0x31, 0xdc, 0xc9, 0x26, + 0xbc, 0xe8, 0xd5, 0x29, 0x14, 0x7b, 0x5e, 0x94, 0x0f, 0x61, 0xd0, 0xba, + 0x1f, 0x02, 0x83, 0x1c, 0x80, 0xc2, 0x7a, 0x23, 0xcd, 0x4b, 0x5f, 0xfb, + 0x50, 0x7c, 0x7d, 0x09, 0xa7, 0x7e, 0x4c, 0x84, 0x27, 0xe2, 0x90, 0x10, + 0xcf, 0x1c, 0x80, 0x21, 0xa8, 0x0c, 0xa2, 0x95, 0x04, 0xca, 0xa3, 0x50, + 0xa2, 0x7d, 0x6c, 0xa4, 0x55, 0x4f, 0xe4, 0xd8, 0xb0, 0x23, 0x55, 0x54, + 0xf2, 0x51, 0xa5, 0x9e, 0xc6, 0x72, 0x9d, 0x80, 0x2b, 0x47, 0x30, 0x83, + 0xb0, 0xbd, 0x6c, 0xa8, 0x3f, 0x6d, 0x94, 0x5b, 0x3d, 0x1d, 0xe2, 0xb7, + 0x06, 0xbd, 0xcc, 0x3b, 0x50, 0xdd, 0xef, 0x57, 0x84, 0x7f, 0xff, 0x88, + 0xa4, 0x49, 0x85, 0x86, 0xca, 0x6a, 0xfe, 0x65, 0xe7, 0x6c, 0x2d, 0x97, + 0xf8, 0x7d, 0xde, 0xa6, 0x6f, 0x55, 0x63, 0xe3, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(91, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_92(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xbc, 0x3c, 0x34, 0x69, 0x28, 0x92, 0x91, 0x69, 0xc7, 0xa0, 0x0c, 0x6f, + 0x53, 0x2f, 0x7e, 0xb1, 0xc4, 0xa7, 0x7d, 0x42, 0x19, 0x3b, 0x65, 0x69, + 0x7b, 0xdd, 0xe5, 0xfe, 0x59, 0xae, 0x45, 0x20, + }, + { + 0x1b, 0x2b, 0xa3, 0x3d, 0xa4, 0x9d, 0x3f, 0x6c, 0xf8, 0x40, 0x39, 0xcd, + 0x99, 0xcc, 0xe5, 0x0f, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb4, 0x25, 0x4a, 0xab, 0x62, 0xc4, 0x15, 0xd8, 0x32, 0x3d, 0x55, 0x6a, + 0xec, 0xa6, 0x14, 0x17, 0xb4, 0x1b, 0x09, 0x04, 0x65, 0x48, 0x0d, 0xb8, + 0xfb, 0x86, 0x4f, 0x57, 0x8f, 0x56, 0x7b, 0x3d, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x26, 0x02, 0xfc, 0xc0, 0xfc, 0xdb, 0x71, 0x04, 0x6d, 0xa4, 0x22, 0x6e, + 0x12, 0x77, 0xd5, 0xdf, 0x89, 0x22, 0x54, 0x73, 0xe4, 0x56, 0x4f, 0x04, + 0x7e, 0x60, 0x61, 0x0d, 0x98, 0x1a, 0x18, 0xe2, 0xb4, 0x4d, 0x79, 0xa9, + 0x3c, 0xd8, 0x64, 0xb8, 0x0f, 0xd3, 0x77, 0x68, 0x5f, 0xb4, 0x19, 0x8e, + 0xce, 0x5b, 0x22, 0x11, 0xae, 0xba, 0x57, 0xff, 0x49, 0xfd, 0xb6, 0x12, + 0x82, 0x62, 0xe2, 0x83, 0x6e, 0x7e, 0x81, 0x66, 0xf3, 0xc3, 0xd5, 0xa9, + 0x3c, 0x68, 0x6a, 0x9b, 0x70, 0xaa, 0x73, 0x9c, 0x66, 0xf8, 0x5f, 0x84, + 0xc4, 0x4c, 0x31, 0x46, 0x62, 0xd7, 0xaf, 0x17, 0xad, 0x62, 0x5e, 0x55, + 0xb6, 0xb4, 0x80, 0x1f, 0x0d, 0xda, 0xd8, 0xe6, 0x36, 0x85, 0x4d, 0x22, + 0x8f, 0x01, 0xba, 0x8f, 0x2f, 0x81, 0x20, 0x76, 0x20, 0x52, 0xd2, 0x89, + 0x48, 0x19, 0xa9, 0xfb, 0xc7, 0x6d, 0x6e, 0x6f, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(92, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_93(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x0b, 0xa0, 0x38, 0xbd, 0xb7, 0xad, 0x7b, 0xbe, 0x77, 0xa6, 0xc7, 0xda, + 0xa3, 0x3a, 0x2b, 0xdf, 0xd9, 0xa1, 0xa5, 0xf3, 0x1c, 0xd2, 0xe7, 0x53, + 0x77, 0xc7, 0x78, 0xf4, 0x92, 0xf5, 0xb3, 0xcb, + }, + { + 0x17, 0xa1, 0x34, 0x23, 0x4a, 0x30, 0xe0, 0x91, 0x70, 0x89, 0x9c, 0x11, + 0x5b, 0x43, 0xca, 0x16, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xdb, 0x02, 0x0e, 0x00, 0xba, 0xce, 0x41, 0x7b, 0xa7, 0x68, 0x7e, 0x82, + 0x9c, 0x1f, 0xfc, 0x91, 0xd2, 0x2e, 0xf9, 0x3b, 0x27, 0xbf, 0xe1, 0x10, + 0x77, 0x32, 0xcf, 0xe0, 0x82, 0xa0, 0x5c, 0xf6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x01, 0x79, 0x2f, 0x59, 0xd0, 0xa6, 0x3d, 0xef, 0xd8, 0x7d, 0x13, 0x18, + 0x8b, 0x1a, 0xec, 0xa9, 0x8c, 0x03, 0xb1, 0x1b, 0x7d, 0xd6, 0x69, 0x83, + 0x28, 0x17, 0x2d, 0xfb, 0x65, 0xcc, 0xb6, 0x95, 0xa1, 0xba, 0xa5, 0x8e, + 0x44, 0xfd, 0x75, 0x23, 0xfd, 0x17, 0x6d, 0x27, 0x06, 0x64, 0x33, 0x7e, + 0x59, 0x8a, 0xa4, 0x53, 0x64, 0x3c, 0xe3, 0xc6, 0xeb, 0xad, 0xed, 0xec, + 0x63, 0x11, 0xe2, 0xe1, 0xa6, 0xed, 0x22, 0x52, 0x47, 0x74, 0x01, 0x04, + 0x12, 0x53, 0xd3, 0xaf, 0xba, 0xda, 0xc0, 0x6e, 0x4d, 0x06, 0xf4, 0x6d, + 0xc3, 0xd7, 0xac, 0xe2, 0x87, 0xee, 0x3e, 0x23, 0x28, 0x6b, 0x28, 0x85, + 0x2e, 0xe0, 0xcf, 0x1e, 0x7a, 0xb3, 0xad, 0xb0, 0xff, 0x10, 0x07, 0xd0, + 0x77, 0x16, 0xb0, 0x9c, 0x22, 0xeb, 0x13, 0x80, 0xbb, 0xd0, 0xe8, 0xda, + 0xc4, 0x82, 0xdf, 0x48, 0x0d, 0x41, 0x58, 0x1d, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(93, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_94(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x2b, 0x37, 0xc7, 0x0c, 0x56, 0xa2, 0xa1, 0xc3, 0xd5, 0x15, 0x0e, 0xdc, + 0x4c, 0x31, 0x80, 0x7e, 0x17, 0x97, 0x3f, 0x4a, 0xfd, 0x85, 0x32, 0x18, + 0xe9, 0x94, 0x03, 0xd8, 0xdd, 0x9f, 0x19, 0x5f, + }, + { + 0xa5, 0x11, 0x0c, 0x3a, 0x0f, 0x45, 0xba, 0x13, 0xb8, 0xea, 0x3f, 0x77, + 0xf3, 0x33, 0x58, 0x49, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x14, 0x50, 0xbb, 0xf9, 0xf6, 0xb6, 0x83, 0x30, 0xfa, 0x6c, 0x3e, 0xeb, + 0x20, 0x18, 0x5e, 0xcb, 0xb3, 0x0c, 0x4c, 0xcb, 0x4b, 0x7b, 0x5e, 0xe3, + 0x27, 0x12, 0x63, 0xa6, 0x43, 0xd4, 0xf3, 0xe9, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x57, 0x14, 0xe0, 0x8e, 0xcb, 0x34, 0xe5, 0x1c, 0x1b, 0x5b, 0x91, 0x40, + 0x5c, 0x81, 0x2e, 0x80, 0x10, 0x72, 0x9b, 0x69, 0x95, 0xb6, 0xcc, 0x90, + 0x14, 0x80, 0x9c, 0x47, 0xc3, 0xb6, 0xba, 0xf1, 0x10, 0x13, 0x45, 0x75, + 0x14, 0x6c, 0x6b, 0xb4, 0x3d, 0x20, 0xfe, 0x16, 0x38, 0x6d, 0x10, 0x05, + 0xb5, 0x64, 0x1b, 0xdc, 0x12, 0xb6, 0x45, 0x4f, 0x3b, 0xb7, 0x45, 0x88, + 0xb6, 0x16, 0xc6, 0x54, 0xbd, 0xca, 0x84, 0xf0, 0x71, 0x36, 0x4e, 0xfd, + 0x8d, 0x1e, 0xe6, 0x66, 0xcd, 0x60, 0xe4, 0xe2, 0xa8, 0xa3, 0xde, 0x99, + 0xe3, 0xf5, 0x6a, 0x72, 0x71, 0x4d, 0xb0, 0x4f, 0x15, 0xaa, 0x03, 0x76, + 0xac, 0xa8, 0xb1, 0x2d, 0x50, 0x31, 0x8c, 0x12, 0x8e, 0x1f, 0x4c, 0xe2, + 0x58, 0x40, 0x09, 0xed, 0x4d, 0x7e, 0x57, 0x54, 0x4a, 0xba, 0x9d, 0x63, + 0x12, 0x69, 0xef, 0xf9, 0x95, 0x31, 0x99, 0x23, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(94, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_95(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xab, 0x79, 0xf1, 0xff, 0x8a, 0x69, 0xc7, 0xf7, 0xeb, 0x33, 0xe5, 0x7f, + 0x03, 0xc5, 0xfd, 0x84, 0x58, 0xc0, 0xaf, 0xa9, 0xd2, 0x73, 0x88, 0xb7, + 0x84, 0x20, 0xa1, 0xac, 0x8d, 0x98, 0xbe, 0x68, + }, + { + 0xb3, 0x6b, 0x72, 0xa0, 0x4b, 0xbd, 0xd2, 0x85, 0x96, 0x8d, 0x73, 0x05, + 0xd3, 0x56, 0xf8, 0xff, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5c, 0xe8, 0x78, 0x3b, 0x45, 0x3b, 0xa8, 0x56, 0x7e, 0x7b, 0x6d, 0x7a, + 0x63, 0xac, 0xe5, 0xb4, 0xea, 0xf8, 0x75, 0x62, 0x42, 0x0e, 0x72, 0x9f, + 0xae, 0x94, 0x39, 0xce, 0x3a, 0x68, 0xdc, 0x86, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x9d, 0x10, 0x40, 0x4b, 0x95, 0x2e, 0x37, 0xc1, 0xd7, 0x00, 0x7b, 0xea, + 0xb7, 0xf8, 0xf1, 0xfa, 0xf2, 0x36, 0x17, 0x00, 0xf1, 0x38, 0x8b, 0xeb, + 0xfa, 0x83, 0xd8, 0x57, 0xac, 0xbd, 0x65, 0x20, 0x94, 0x7a, 0x4a, 0x06, + 0x9f, 0x80, 0x27, 0x8d, 0xae, 0x1d, 0x5a, 0x8e, 0xef, 0xf9, 0xd6, 0x9f, + 0x63, 0x30, 0x18, 0x31, 0x0e, 0x2a, 0x16, 0xac, 0xb9, 0x08, 0xb3, 0xb0, + 0x29, 0xb5, 0xbb, 0xef, 0x71, 0xf2, 0xa0, 0x59, 0x70, 0xf5, 0x44, 0xad, + 0xcf, 0xa6, 0xe7, 0x07, 0x79, 0x9f, 0xc1, 0xe6, 0xb7, 0x8b, 0x96, 0xea, + 0x1a, 0x57, 0x4f, 0x34, 0xd4, 0x49, 0x94, 0xe6, 0x8d, 0x1c, 0x40, 0xbc, + 0x2f, 0x39, 0x7a, 0xe1, 0xa4, 0x87, 0x28, 0xa9, 0x2b, 0x8b, 0x4d, 0x46, + 0xe3, 0x47, 0x22, 0xdd, 0xf2, 0x4d, 0xd3, 0xa0, 0x35, 0x26, 0x2e, 0x90, + 0xc5, 0xbf, 0xfe, 0x04, 0x89, 0x6b, 0x56, 0x58, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(95, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_96(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x05, 0xfa, 0xe5, 0xa2, 0x08, 0x03, 0xa1, 0x44, 0x21, 0x11, 0xac, 0x0b, + 0xd1, 0x81, 0x01, 0x86, 0x31, 0x9d, 0x72, 0x1d, 0x29, 0x46, 0xec, 0xa2, + 0x64, 0xfb, 0x31, 0xac, 0x8d, 0x8c, 0xbd, 0xa8, + }, + { + 0x97, 0xc4, 0x1c, 0xa6, 0x69, 0xe2, 0x23, 0xee, 0xcf, 0xb2, 0x65, 0x99, + 0x41, 0xff, 0xa1, 0xbc, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xdf, 0x4f, 0x01, 0xea, 0x4a, 0x91, 0xaa, 0x2e, 0xb6, 0x51, 0x55, 0xf1, + 0x53, 0xdc, 0xa7, 0x0a, 0xfc, 0xe9, 0x8f, 0xf5, 0x6b, 0xff, 0x2a, 0x1c, + 0x94, 0x11, 0x78, 0xc2, 0xc2, 0xdb, 0xe9, 0x18, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf3, 0xeb, 0x85, 0xc1, 0x68, 0x37, 0x79, 0x31, 0xa2, 0xf6, 0x77, 0xf1, + 0x06, 0x4c, 0x82, 0xde, 0x81, 0x5e, 0xff, 0x75, 0x70, 0x1b, 0x03, 0x16, + 0x06, 0x09, 0x87, 0x94, 0xee, 0xa7, 0x16, 0x96, 0x80, 0x54, 0x85, 0xf7, + 0x77, 0xad, 0xe2, 0xf2, 0x50, 0xe4, 0x8f, 0xd5, 0x8d, 0x23, 0x58, 0xaa, + 0x8e, 0xeb, 0xff, 0x59, 0x7d, 0x39, 0x6a, 0x7a, 0xfc, 0xf3, 0x8b, 0xe6, + 0x5e, 0x0e, 0x78, 0x40, 0x5d, 0x35, 0xee, 0x3d, 0x8d, 0xd2, 0x98, 0x5c, + 0xd6, 0x2c, 0x26, 0xca, 0xc1, 0xbd, 0x0d, 0x9c, 0x6e, 0x67, 0xac, 0xcf, + 0xbb, 0xe2, 0xbf, 0xda, 0x87, 0xd5, 0x0d, 0xe6, 0x41, 0x5a, 0x4a, 0x9b, + 0xaa, 0x27, 0x3f, 0x99, 0x7b, 0xdc, 0xe9, 0x03, 0x27, 0x1a, 0x05, 0x82, + 0xbe, 0xfc, 0x40, 0x2f, 0x33, 0xfc, 0xab, 0xb6, 0xdb, 0x6f, 0x14, 0x52, + 0x52, 0xd8, 0x70, 0x55, 0x4d, 0x78, 0x91, 0xd2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(96, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_97(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xf0, 0x7a, 0xce, 0x29, 0x9e, 0xa3, 0xc1, 0x04, 0x9d, 0x88, 0x37, 0x8e, + 0x3a, 0x64, 0xd6, 0xfe, 0x78, 0x1b, 0x87, 0x72, 0xcb, 0xd1, 0x92, 0xc9, + 0x69, 0x2a, 0x4d, 0x8e, 0x7a, 0xec, 0x19, 0x87, + }, + { + 0x87, 0xcd, 0x0d, 0x8f, 0xff, 0x8d, 0xad, 0xec, 0x5b, 0x8b, 0xcc, 0xd0, + 0x85, 0xf4, 0x1a, 0x1e, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x42, 0xfb, 0x6e, 0x92, 0xee, 0x26, 0x3b, 0x1c, 0x03, 0xa6, 0x3e, 0x5b, + 0xea, 0xf8, 0x06, 0x62, 0xad, 0x67, 0xb1, 0x95, 0xe1, 0x55, 0xd0, 0xac, + 0xb7, 0x47, 0x8a, 0x82, 0x93, 0x83, 0x1f, 0xc6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x3e, 0x3e, 0xeb, 0x53, 0x80, 0x0b, 0x48, 0x74, 0xbd, 0xda, 0x33, 0x1c, + 0x1e, 0x9b, 0x98, 0xc5, 0x77, 0x00, 0xe7, 0xc2, 0x06, 0xf5, 0xf3, 0xd0, + 0xf4, 0x21, 0xe3, 0xc4, 0x90, 0x79, 0x70, 0x84, 0xc0, 0x9e, 0xd6, 0xb4, + 0xbd, 0x58, 0x85, 0xbc, 0xaa, 0x42, 0xe0, 0x36, 0x87, 0x0d, 0x63, 0x3d, + 0xf8, 0xb3, 0xbf, 0x1d, 0x1b, 0xaf, 0xf5, 0x88, 0xac, 0x9b, 0x24, 0xe0, + 0x82, 0x7c, 0x26, 0xed, 0x4f, 0x06, 0x18, 0xd9, 0x12, 0xd3, 0x90, 0x04, + 0xcc, 0xa9, 0x73, 0x9e, 0x0b, 0x99, 0x46, 0xf8, 0x92, 0x7b, 0x58, 0x0b, + 0xb2, 0xf3, 0x2c, 0x9f, 0x14, 0x2a, 0x7b, 0x1c, 0x09, 0xb3, 0x2a, 0x40, + 0x5e, 0x1e, 0xf5, 0x20, 0x9c, 0xae, 0x79, 0x0b, 0x07, 0x11, 0xd1, 0x49, + 0x93, 0x51, 0x09, 0x53, 0x01, 0x8f, 0x27, 0x9c, 0x8c, 0x8d, 0xfd, 0x06, + 0x64, 0x8c, 0xd1, 0xb1, 0xa5, 0x8b, 0xdf, 0x93, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(97, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_98(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x96, 0xc3, 0xe7, 0xe5, 0xfe, 0xcc, 0xc0, 0x61, 0x80, 0x59, 0x00, 0x6c, + 0x73, 0x5a, 0x6c, 0xe0, 0xb5, 0x11, 0x4d, 0x20, 0x8c, 0x79, 0x14, 0x3e, + 0x1c, 0x9f, 0x8e, 0xf5, 0x03, 0x6e, 0x33, 0x0d, + }, + { + 0x6b, 0xbb, 0x09, 0xc4, 0x16, 0x51, 0xc1, 0xc7, 0x8c, 0x36, 0xc2, 0x5e, + 0x4c, 0xee, 0x8a, 0xa9, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xab, 0xa5, 0x10, 0x86, 0x57, 0x7c, 0x69, 0x48, 0xb8, 0x92, 0xcf, 0x52, + 0x54, 0x52, 0x0b, 0xf8, 0xd2, 0x40, 0xc2, 0xe3, 0xb0, 0x92, 0x4a, 0xfe, + 0x69, 0x65, 0xac, 0xfa, 0xbd, 0x7e, 0x0a, 0xbf, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x1d, 0x7e, 0xc4, 0x82, 0x34, 0xbb, 0x2a, 0xaa, 0xf5, 0x4f, 0xbd, 0x55, + 0xff, 0x06, 0x63, 0xf0, 0xfc, 0x82, 0x82, 0x25, 0x31, 0xf6, 0x66, 0xee, + 0x7f, 0x7f, 0x5e, 0x25, 0x70, 0x07, 0xf3, 0x04, 0x62, 0x42, 0x8a, 0x51, + 0x9d, 0x86, 0xa8, 0x76, 0x4b, 0xa0, 0xd6, 0xa2, 0x33, 0x1c, 0xb1, 0x29, + 0x23, 0x2d, 0x9a, 0x5c, 0x03, 0x18, 0x3b, 0x0f, 0x41, 0x9d, 0x81, 0x3f, + 0x4c, 0x0e, 0x00, 0xe4, 0xbe, 0x5d, 0xd1, 0x6a, 0x87, 0xa9, 0xfa, 0xec, + 0x89, 0x15, 0xa3, 0x9f, 0xd2, 0xd4, 0x06, 0xc5, 0x4e, 0xb8, 0xaa, 0xf2, + 0x28, 0xa0, 0x9a, 0x46, 0xdb, 0x55, 0xfd, 0xa8, 0xa9, 0x0b, 0x27, 0xef, + 0xc9, 0x6c, 0x46, 0x1e, 0x9e, 0x9b, 0xe0, 0x8e, 0x27, 0xaf, 0x86, 0xb0, + 0x17, 0x50, 0xdb, 0xbf, 0xb4, 0x02, 0x45, 0xe9, 0x98, 0xf0, 0x67, 0x96, + 0x86, 0xe1, 0x8d, 0x80, 0x17, 0x02, 0xff, 0xa2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(98, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_99(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x21, 0x07, 0x25, 0xc6, 0x08, 0x39, 0x78, 0x2d, 0x36, 0x65, 0xa3, 0x00, + 0xad, 0xcf, 0x81, 0xc6, 0xd5, 0x14, 0x78, 0xb1, 0xf1, 0x2e, 0x5d, 0x53, + 0x10, 0x4b, 0xeb, 0x38, 0x5c, 0xe1, 0x50, 0x24, + }, + { + 0x12, 0x9a, 0x70, 0x5c, 0x88, 0xe4, 0xfd, 0xb1, 0x67, 0xd3, 0x47, 0x94, + 0xf6, 0xf7, 0x39, 0xb4, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe1, 0x2e, 0x9c, 0xc5, 0x23, 0xd6, 0x18, 0xae, 0x6c, 0xb6, 0x67, 0xec, + 0xa7, 0xed, 0xd3, 0x54, 0x58, 0x18, 0x7b, 0xd1, 0x9e, 0x90, 0x79, 0xb5, + 0xc5, 0xe1, 0xcb, 0x97, 0x1e, 0x38, 0x03, 0x09, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x34, 0x5b, 0x3b, 0x8c, 0x01, 0x1c, 0x78, 0x7e, 0x90, 0x63, 0xf8, 0x11, + 0xd5, 0x1f, 0x09, 0x6a, 0x31, 0xcc, 0x1e, 0xa9, 0xfa, 0xa0, 0xb8, 0xf2, + 0x9d, 0x91, 0x6b, 0xe1, 0xb9, 0x25, 0xa4, 0xb7, 0x1f, 0x8e, 0x6d, 0xb5, + 0x6e, 0x0e, 0x22, 0xab, 0xfd, 0xe3, 0xf0, 0x35, 0xf2, 0xd5, 0xa6, 0xfc, + 0xde, 0x02, 0xe5, 0xdf, 0x8c, 0x0b, 0xef, 0xe0, 0xc0, 0x04, 0x38, 0xfa, + 0xa4, 0x27, 0x7c, 0xa7, 0x90, 0xe6, 0x32, 0x31, 0x80, 0x61, 0xfb, 0xab, + 0xbb, 0x83, 0xdc, 0x83, 0xf7, 0x19, 0xf3, 0xce, 0xab, 0x43, 0x1e, 0x3f, + 0xe8, 0x06, 0x95, 0xbc, 0x44, 0xd7, 0x4d, 0x09, 0x35, 0xc8, 0x42, 0x25, + 0x21, 0xce, 0x78, 0x4a, 0x92, 0x3c, 0xac, 0xc3, 0x75, 0x17, 0xb9, 0xdd, + 0x93, 0xc7, 0xc0, 0x60, 0x8f, 0x95, 0x5e, 0x5b, 0x48, 0x68, 0x0b, 0x53, + 0x71, 0x42, 0x45, 0x9a, 0x6d, 0x7b, 0x79, 0xe8, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(99, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_100(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xf8, 0x7e, 0x04, 0x74, 0x38, 0xc6, 0xf5, 0xdc, 0x41, 0xa5, 0xe3, 0xbd, + 0x0d, 0xdb, 0x38, 0x6c, 0x99, 0x40, 0x7b, 0xf2, 0x76, 0xb5, 0x78, 0x24, + 0xd4, 0x36, 0x6e, 0x09, 0x73, 0xef, 0x65, 0xf2, + }, + { + 0x73, 0x00, 0x2b, 0x5a, 0xc3, 0xcd, 0xb5, 0x61, 0x5a, 0x2e, 0x17, 0x92, + 0xb9, 0x63, 0x86, 0xe2, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xca, 0x22, 0xf8, 0x53, 0xf4, 0x37, 0x1e, 0xd3, 0x34, 0xab, 0x94, 0x44, + 0x4b, 0x58, 0xa4, 0xf9, 0xcb, 0xda, 0xcf, 0xda, 0x96, 0xe4, 0xa9, 0xe4, + 0x6c, 0x9c, 0xf7, 0x76, 0xa9, 0x03, 0x99, 0x0d, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5d, 0x54, 0x82, 0x7f, 0xb3, 0x7f, 0xd8, 0x64, 0x41, 0xab, 0x4e, 0xb3, + 0x79, 0x60, 0x89, 0xde, 0x39, 0xf1, 0x13, 0x24, 0x41, 0x58, 0x23, 0x6e, + 0xc1, 0x62, 0x99, 0x69, 0xf9, 0x29, 0x5f, 0x37, 0x83, 0x6b, 0x2d, 0x7d, + 0x4d, 0x6e, 0x59, 0xe0, 0xbd, 0xce, 0xfd, 0x92, 0x3c, 0x2c, 0x44, 0x21, + 0x18, 0xc8, 0xca, 0x3b, 0x00, 0xa2, 0x58, 0xbe, 0xec, 0xad, 0x7d, 0x28, + 0xd7, 0xe1, 0x21, 0x62, 0xa4, 0x20, 0x21, 0x29, 0x18, 0x93, 0x7a, 0x4d, + 0x0d, 0xa5, 0xea, 0x7c, 0x0b, 0x96, 0x02, 0x81, 0x32, 0x66, 0x01, 0x5f, + 0x38, 0x5e, 0xd5, 0xc6, 0x9a, 0x48, 0x37, 0x5e, 0x9b, 0x37, 0x38, 0x81, + 0x4f, 0x16, 0xc0, 0x85, 0xd5, 0xcf, 0xd1, 0xd2, 0xe6, 0x26, 0x7e, 0x1c, + 0x5d, 0x7b, 0xad, 0x88, 0xf2, 0x0b, 0x3a, 0xb0, 0xab, 0x27, 0x9f, 0xcb, + 0x65, 0x10, 0x20, 0xec, 0xfc, 0x15, 0x07, 0x63, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(100, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_101(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x50, 0xeb, 0xb3, 0x84, 0x61, 0xd3, 0xf2, 0x6c, 0x5a, 0xc2, 0xec, 0xf5, + 0x3a, 0x03, 0x41, 0x78, 0x42, 0x52, 0x5b, 0xad, 0x57, 0x7f, 0x05, 0x7e, + 0xd9, 0x20, 0xc1, 0xc4, 0x97, 0x0e, 0x55, 0x29, + }, + { + 0x99, 0x6c, 0x6b, 0x9d, 0xb4, 0xa1, 0xaa, 0xb9, 0xd3, 0x1c, 0x75, 0x4a, + 0xf4, 0x9a, 0x54, 0x45, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xea, 0x89, 0x85, 0x50, 0xce, 0xe3, 0x88, 0x88, 0xc0, 0x38, 0xf6, 0x7b, + 0x49, 0x12, 0xe4, 0x8a, 0xa9, 0xe3, 0x78, 0xff, 0x3a, 0xdc, 0x9c, 0xc6, + 0xc5, 0xba, 0xee, 0x8c, 0x37, 0x6f, 0xc7, 0x08, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x77, 0x37, 0x71, 0xf1, 0xf3, 0x90, 0x37, 0x63, 0xf4, 0xf9, 0xd6, 0xb2, + 0x16, 0x73, 0xd2, 0xa9, 0x3f, 0x6e, 0x4d, 0x03, 0x63, 0x6d, 0x38, 0x1b, + 0xc2, 0x68, 0x64, 0xb4, 0x64, 0x96, 0xe9, 0x58, 0x8a, 0x06, 0x4b, 0x00, + 0xe8, 0x46, 0xa8, 0xd9, 0x1e, 0x30, 0x2c, 0x47, 0xda, 0xcd, 0xab, 0x73, + 0x88, 0xf5, 0xcd, 0x00, 0x93, 0xd2, 0x17, 0x4e, 0x33, 0x32, 0x7f, 0x9d, + 0xf6, 0x53, 0x71, 0x24, 0xab, 0x91, 0xcf, 0x35, 0xcb, 0xee, 0xce, 0x38, + 0xf6, 0x37, 0x3a, 0x8b, 0x85, 0x1d, 0xa2, 0x64, 0x5d, 0xad, 0x5c, 0xf0, + 0x1a, 0x59, 0xf5, 0x31, 0x80, 0xa0, 0xfb, 0xfe, 0xb9, 0x28, 0xa7, 0x10, + 0x90, 0xd1, 0x99, 0x7b, 0x05, 0x5f, 0xa2, 0x0f, 0x14, 0xf4, 0x9c, 0x28, + 0xdc, 0x06, 0x5d, 0xdd, 0x84, 0xa1, 0x4d, 0x93, 0x23, 0x19, 0x2b, 0x24, + 0x28, 0xae, 0xc6, 0xf9, 0x15, 0xf9, 0x04, 0x91, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(101, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_102(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0xc1, 0x3d, 0x6c, 0xd6, 0x3b, 0xb7, 0x93, 0x11, 0x74, 0x69, 0x6f, 0x3e, + 0x04, 0xa0, 0xc4, 0x1c, 0xb0, 0xb2, 0x56, 0x11, 0x34, 0xe8, 0x47, 0xce, + 0x03, 0xe3, 0x63, 0x26, 0xb8, 0x03, 0xf8, 0xab, + }, + { + 0x20, 0x84, 0xab, 0x32, 0x37, 0x43, 0x92, 0xea, 0x9f, 0x6e, 0x8a, 0x47, + 0x4f, 0x18, 0xe9, 0xd7, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xae, 0xc5, 0xa6, 0xa7, 0x23, 0x2a, 0x52, 0xb8, 0x1c, 0xe7, 0xe9, 0x81, + 0xa3, 0x59, 0xce, 0xf1, 0xbb, 0xd2, 0xf1, 0xef, 0xf8, 0x48, 0x83, 0x71, + 0x46, 0x8c, 0xd1, 0xf4, 0x14, 0x7a, 0x89, 0xc2, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xda, 0xea, 0x78, 0x88, 0x17, 0x37, 0xcb, 0x26, 0xd6, 0x0c, 0x36, 0xce, + 0xb9, 0xfe, 0xc3, 0xd2, 0x81, 0xc7, 0xae, 0xc5, 0x4b, 0x4b, 0x98, 0x50, + 0x93, 0x7b, 0x37, 0x3b, 0x2b, 0x26, 0x21, 0xfe, 0x07, 0x75, 0x85, 0xa1, + 0xfe, 0x88, 0x26, 0x5d, 0x84, 0xf2, 0x25, 0x55, 0x2e, 0x5c, 0x85, 0xcb, + 0xec, 0x8d, 0x00, 0x06, 0x96, 0x48, 0x06, 0x5a, 0xc1, 0x20, 0x73, 0xae, + 0xdc, 0xe8, 0xc9, 0x40, 0x46, 0x09, 0x49, 0xb5, 0x97, 0x66, 0x7e, 0xcf, + 0xce, 0xda, 0xbd, 0x7a, 0x86, 0xa9, 0x79, 0xb9, 0x04, 0xa2, 0x4d, 0x32, + 0xdb, 0x10, 0x22, 0x3e, 0xae, 0x5a, 0x98, 0xa0, 0xd1, 0xb6, 0x57, 0x1b, + 0x86, 0x43, 0xdf, 0x2c, 0x62, 0x65, 0xa5, 0xd6, 0x6c, 0xee, 0x9f, 0x4a, + 0xbf, 0xc5, 0x77, 0x81, 0x46, 0xd6, 0xfb, 0x2b, 0x85, 0x3d, 0x82, 0x63, + 0x6c, 0x13, 0x25, 0xb2, 0xd1, 0xef, 0x45, 0x76, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(102, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_103(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x67, 0xf9, 0x8d, 0x4d, 0x9f, 0x35, 0xa8, 0xda, 0xc0, 0x3d, 0x19, 0x92, + 0x22, 0xb0, 0x7c, 0x78, 0x5f, 0x11, 0xdc, 0x51, 0x7a, 0x8d, 0x88, 0x40, + 0xf5, 0xfe, 0xa4, 0xb6, 0xfd, 0x68, 0x44, 0x8e, + }, + { + 0x1d, 0xcd, 0x3a, 0x1b, 0xbb, 0x4f, 0x94, 0xad, 0x78, 0x35, 0x58, 0x42, + 0x89, 0x3d, 0xe0, 0x35, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf1, 0xf9, 0xca, 0xee, 0x31, 0x03, 0x6a, 0x2a, 0x20, 0x0a, 0x05, 0x2d, + 0x8a, 0x1e, 0x06, 0x59, 0x20, 0xb8, 0x36, 0x3f, 0xbb, 0xf1, 0xc3, 0x71, + 0xa2, 0x32, 0x44, 0xc6, 0x83, 0x51, 0x13, 0xd3, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x9f, 0x24, 0xa5, 0x6f, 0x98, 0x58, 0x51, 0x26, 0x2d, 0x0c, 0xfd, 0xf1, + 0x22, 0xb8, 0x9b, 0x3b, 0x93, 0xa1, 0xdf, 0xd9, 0x7a, 0x29, 0x7f, 0xb1, + 0xf6, 0xfc, 0x39, 0xd6, 0xc7, 0x19, 0x94, 0x2e, 0x28, 0x97, 0x7b, 0xde, + 0x91, 0xcb, 0x39, 0x41, 0xc0, 0x35, 0xe3, 0xec, 0x45, 0x4d, 0xbf, 0x9d, + 0xbb, 0x43, 0x57, 0x69, 0x20, 0xdc, 0x47, 0x27, 0x3d, 0x3f, 0x82, 0xcc, + 0xc8, 0xa8, 0xfa, 0xbc, 0x1b, 0x53, 0x2f, 0x9d, 0x1c, 0x48, 0x7d, 0xb3, + 0x1e, 0x7e, 0xaa, 0xc3, 0x32, 0x5e, 0xdd, 0x1f, 0xd8, 0x08, 0x70, 0xcf, + 0x30, 0xcc, 0xdc, 0x87, 0xa1, 0xfa, 0x4b, 0x88, 0xeb, 0x7a, 0x1c, 0x46, + 0x4d, 0x0b, 0x68, 0xef, 0xc3, 0xdd, 0x76, 0x0a, 0x32, 0x59, 0xad, 0x28, + 0x0d, 0x49, 0x64, 0x2b, 0xeb, 0xde, 0xbc, 0x1a, 0x58, 0x29, 0xf3, 0x2f, + 0x09, 0xfb, 0x77, 0x7a, 0xfb, 0x40, 0x9a, 0xee, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(103, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_104(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x0f, 0x4a, 0x78, 0xc8, 0x62, 0x3d, 0x30, 0x31, 0x54, 0x39, 0x8c, 0xb9, + 0x34, 0x08, 0x57, 0xba, 0x93, 0x73, 0x88, 0xf9, 0x5b, 0x01, 0x97, 0xec, + 0xba, 0x48, 0x7c, 0x4c, 0xf0, 0x21, 0xb3, 0xca, + }, + { + 0x6c, 0x02, 0xe6, 0x93, 0x98, 0xab, 0x7b, 0x7d, 0xfc, 0x4a, 0xd8, 0x3e, + 0x7f, 0x3c, 0xa8, 0xff, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x03, 0x02, 0x0b, 0x45, 0x11, 0xb2, 0x52, 0x9b, 0x2a, 0x33, 0x48, 0x07, + 0x8a, 0xd0, 0x31, 0x8b, 0xa5, 0xf8, 0x25, 0xa1, 0xbb, 0x06, 0x72, 0xdc, + 0x89, 0x4c, 0xb4, 0xd1, 0xdd, 0x3e, 0x29, 0x4d, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf5, 0xb9, 0xa5, 0x26, 0x29, 0x70, 0xb8, 0xcd, 0x94, 0x48, 0x2a, 0xc6, + 0xe4, 0xde, 0xdd, 0x8f, 0xfd, 0xca, 0xca, 0x0f, 0xc3, 0x7e, 0x6d, 0x0f, + 0xa7, 0x1a, 0xb1, 0x0e, 0x5a, 0xe0, 0x74, 0x87, 0xc6, 0x88, 0x01, 0x7d, + 0xc0, 0x15, 0x14, 0xf8, 0x57, 0x70, 0x2b, 0x28, 0xcd, 0x8e, 0x4f, 0x1b, + 0x08, 0x39, 0xb9, 0xec, 0x4d, 0x6f, 0x9e, 0x07, 0xe4, 0x55, 0x1e, 0x15, + 0x0c, 0x91, 0xcd, 0x4f, 0x4a, 0xa2, 0x2a, 0xa7, 0xe8, 0xa5, 0xe1, 0x07, + 0x78, 0x69, 0xb2, 0x45, 0x4b, 0xb8, 0xcd, 0xda, 0xee, 0x69, 0xa0, 0x67, + 0xc6, 0xb0, 0xdc, 0xc1, 0x78, 0xfe, 0x1d, 0xa6, 0xed, 0xe5, 0xd5, 0x32, + 0x69, 0x37, 0x25, 0x36, 0xf3, 0x4b, 0xed, 0x37, 0x85, 0x66, 0xcb, 0xd8, + 0x98, 0x6d, 0xc1, 0xae, 0x08, 0x48, 0xbe, 0x74, 0x90, 0x79, 0xdd, 0x57, + 0x2d, 0x4d, 0x62, 0xe5, 0x1f, 0xe6, 0x59, 0xca, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(104, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_105(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 0, + 0, + 128, + { + 0x00, 0x1c, 0xf2, 0xbb, 0x87, 0xee, 0x4a, 0xa1, 0x45, 0x01, 0x19, 0x08, + 0xce, 0x79, 0x92, 0x07, 0x00, 0xff, 0x40, 0xce, 0x76, 0x50, 0x99, 0x29, + 0x2b, 0x7b, 0x7a, 0xec, 0x68, 0xee, 0xb0, 0x5e, + }, + { + 0xb1, 0x01, 0x15, 0xcc, 0xfe, 0xfe, 0xc7, 0x48, 0x7c, 0x87, 0x24, 0x12, + 0x97, 0x70, 0x67, 0xa9, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x9b, 0x5d, 0xcf, 0xa4, 0x0b, 0x5c, 0x5a, 0x9d, 0xca, 0xe4, 0xe8, 0xcd, + 0xf1, 0x6e, 0x14, 0x58, 0xd4, 0x91, 0x64, 0xb3, 0x17, 0xce, 0xfc, 0xe6, + 0x3f, 0x28, 0xc1, 0x0d, 0x29, 0x22, 0x99, 0x74, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xe0, 0xf0, 0x73, 0xc0, 0xbb, 0x40, 0x24, 0xc4, 0x6c, 0xed, 0xd5, 0x6f, + 0x6d, 0xde, 0x44, 0x67, 0x7d, 0x8d, 0xcd, 0xaf, 0x8d, 0xf9, 0x39, 0xe2, + 0xcb, 0xfa, 0xaf, 0x0f, 0xc3, 0x81, 0x0f, 0x62, 0x1b, 0x29, 0xdd, 0xaa, + 0x78, 0x10, 0xee, 0x3c, 0xfc, 0x25, 0x12, 0x32, 0xc4, 0xf8, 0xb0, 0x1c, + 0x56, 0x64, 0xe4, 0xaf, 0x5e, 0xa0, 0xa7, 0xa2, 0x0c, 0x76, 0x8a, 0xae, + 0x83, 0x92, 0x18, 0x63, 0xd7, 0xe0, 0xff, 0x12, 0x77, 0x8e, 0xe1, 0xe6, + 0xe4, 0xef, 0xee, 0xa6, 0x32, 0x0f, 0x9c, 0x8d, 0xd4, 0x39, 0xe7, 0x98, + 0x7e, 0x62, 0x0a, 0xc2, 0xee, 0x40, 0x96, 0x52, 0xba, 0x7f, 0x07, 0x70, + 0x8c, 0xa1, 0x9a, 0x2e, 0x16, 0xf4, 0xd3, 0x24, 0xba, 0x1a, 0xcc, 0xa3, + 0xa4, 0xd2, 0x44, 0x30, 0x24, 0x38, 0x60, 0x8b, 0xa3, 0xb6, 0x4c, 0xae, + 0x05, 0x54, 0x5a, 0xd8, 0x67, 0x19, 0x49, 0x51, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(105, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_106(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x22, 0xd8, 0xc6, 0x2b, 0xcd, 0xdf, 0x5d, 0xa1, 0xdb, 0xdb, 0x09, 0x3d, + 0x6b, 0x1f, 0x66, 0x3d, 0xde, 0x33, 0x73, 0x43, 0xc5, 0x6c, 0xcf, 0xd4, + 0x0a, 0xcb, 0xe3, 0x30, 0x23, 0x09, 0xea, 0xe0, + }, + { + 0x2a, 0x4b, 0x8e, 0x66, 0xde, 0xaa, 0xc3, 0x8b, 0x70, 0xd9, 0xff, 0xc2, + 0x0c, 0x58, 0x5d, 0xa5, + }, + { + 0x0a, 0x33, 0x70, 0x38, 0xf4, 0xb4, 0x57, 0x3f, 0xf4, 0x3a, 0x43, 0x21, + 0xa5, 0x86, 0xca, 0x77, 0x7c, 0x30, 0x30, 0x12, 0x67, 0xd8, 0x2f, 0xdf, + 0x93, 0x71, 0x98, 0xac, 0x56, 0xc7, 0x06, 0x2c, + }, + { + 0x0b, 0x6f, 0xd1, 0x79, 0xe4, 0x4f, 0x14, 0x9f, 0x06, 0x2d, 0xa4, 0xf6, + 0x6f, 0x82, 0x9c, 0x3c, 0x58, 0xc4, 0xa0, 0xa4, 0xf7, 0x5a, 0xc2, 0xa9, + 0xe0, 0x24, 0x0d, 0x43, 0xbe, 0xc3, 0x0e, 0x44, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x04, 0x6e, 0x19, 0xb4, 0xd8, 0xab, 0x38, 0xdd, 0x08, 0xde, 0xfd, 0xd0, + 0xd7, 0xc3, 0x0c, 0x8c, 0x75, 0xd5, 0x68, 0x9c, 0xa2, 0x6f, 0x2b, 0xc9, + 0x94, 0xac, 0x7f, 0xca, 0x4f, 0xdb, 0xee, 0x80, 0x67, 0x7d, 0xfb, 0xdd, + 0x85, 0x1e, 0x77, 0x22, 0x83, 0x58, 0x44, 0xdc, 0xa7, 0x9d, 0xec, 0x4a, + 0x3f, 0xa8, 0x2f, 0xeb, 0x88, 0x4d, 0xf7, 0xd4, 0x74, 0xbd, 0x97, 0x2e, + 0x12, 0x61, 0x9b, 0xd5, 0xd6, 0xcb, 0x1b, 0x95, 0x1e, 0xac, 0x47, 0xee, + 0xc2, 0x58, 0x11, 0x95, 0xb5, 0x31, 0x53, 0x4e, 0xde, 0x50, 0x7a, 0xf6, + 0xf7, 0x41, 0x7f, 0xca, 0x84, 0x53, 0x2b, 0xe7, 0xef, 0x5d, 0xa6, 0x73, + 0x8d, 0xbf, 0x7a, 0xad, 0xfc, 0xd7, 0xcb, 0x88, 0x88, 0x62, 0xb5, 0x2e, + 0xc7, 0x73, 0xcf, 0x3f, 0xd0, 0x0e, 0x6d, 0x4e, 0xfb, 0x30, 0x71, 0xaf, + 0x9b, 0x70, 0xa4, 0x99, 0x35, 0xa3, 0xba, 0x38, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(106, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_107(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x64, 0x11, 0x75, 0x6d, 0xc7, 0xaa, 0x3b, 0xe0, 0x96, 0xad, 0x41, 0x9c, + 0xe8, 0x38, 0x1c, 0x09, 0x10, 0xd2, 0xa2, 0xaf, 0x5e, 0x94, 0x4d, 0x8f, + 0xf2, 0x1f, 0x2f, 0xc5, 0x66, 0x6a, 0xcb, 0x87, + }, + { + 0x73, 0xb6, 0x8f, 0x5c, 0x74, 0x9f, 0xac, 0x09, 0xf0, 0x1b, 0xa5, 0x65, + 0xa7, 0x57, 0x89, 0xf8, + }, + { + 0x3c, 0xa3, 0xd9, 0x14, 0x6e, 0x2e, 0xbf, 0xf2, 0x1a, 0x28, 0x7d, 0x38, + 0x5c, 0x42, 0x24, 0xed, 0x23, 0x59, 0x6d, 0x74, 0x50, 0x17, 0xf3, 0xb8, + 0x11, 0x48, 0xc9, 0x2f, 0x3b, 0x9b, 0x27, 0xa1, + }, + { + 0xd7, 0x70, 0x12, 0x8e, 0x71, 0x1a, 0x8d, 0xf1, 0x63, 0xf4, 0xe2, 0x89, + 0xe7, 0x75, 0x03, 0x2f, 0xdb, 0x47, 0x3a, 0xa3, 0x8f, 0x7e, 0x1d, 0x29, + 0x17, 0x26, 0x12, 0x13, 0x78, 0xe9, 0xa8, 0xde, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xcd, 0x72, 0xf8, 0x09, 0xd9, 0xcd, 0x1a, 0xe1, 0x3d, 0x99, 0x5d, 0x1c, + 0xac, 0x36, 0x8e, 0xdb, 0xff, 0xf4, 0x56, 0x97, 0xde, 0xb1, 0xd1, 0xb7, + 0x95, 0xff, 0xcf, 0x35, 0x49, 0x36, 0xf0, 0xbf, 0x61, 0xcf, 0x55, 0x0d, + 0x04, 0x3f, 0x9d, 0x2f, 0xa4, 0x62, 0x81, 0xa1, 0x39, 0x3e, 0xac, 0xe3, + 0x84, 0x7d, 0x5e, 0x4c, 0x63, 0x35, 0x18, 0x2f, 0x87, 0xf4, 0x65, 0x80, + 0x29, 0x89, 0xb2, 0x55, 0x70, 0x1f, 0x9d, 0xae, 0xe0, 0x3f, 0x59, 0x1b, + 0xa5, 0xc0, 0x80, 0xd1, 0xf0, 0x58, 0x4b, 0x02, 0x7a, 0xb3, 0xb1, 0xda, + 0x57, 0x35, 0xc9, 0x36, 0x11, 0xd9, 0xbe, 0x11, 0xa7, 0x9c, 0x0f, 0xde, + 0x3b, 0xd4, 0x20, 0x4e, 0xa3, 0x67, 0x40, 0x75, 0xea, 0x96, 0x7a, 0x24, + 0x4a, 0xb1, 0xdc, 0xac, 0xa6, 0xf0, 0x7b, 0x48, 0xbb, 0xb0, 0xb7, 0xe2, + 0x7d, 0x8a, 0x1a, 0x68, 0x0f, 0xa0, 0x79, 0x4c, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(107, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_108(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x68, 0xae, 0xa6, 0x3a, 0xa5, 0xd6, 0xa8, 0x3a, 0x5f, 0x71, 0xe3, 0x32, + 0x68, 0xd1, 0x62, 0xa5, 0x8d, 0x8e, 0xd1, 0x2f, 0xfb, 0x26, 0xc8, 0x25, + 0x70, 0x3e, 0xd0, 0xd1, 0x00, 0xdf, 0xd1, 0xeb, + }, + { + 0xfa, 0x79, 0x9c, 0x67, 0x7c, 0x36, 0x1c, 0x3e, 0x3e, 0xb3, 0x21, 0xb0, + 0x73, 0x08, 0xf2, 0xfd, + }, + { + 0xfd, 0x42, 0x73, 0xdf, 0xd5, 0xb3, 0xbc, 0x1c, 0x6a, 0x12, 0x46, 0xf5, + 0x43, 0x75, 0xe9, 0xa0, 0x02, 0x28, 0x64, 0xdc, 0x40, 0x08, 0xf1, 0x94, + 0x22, 0xec, 0x9c, 0x0f, 0xf8, 0xa9, 0x56, 0x44, + }, + { + 0xc6, 0x73, 0x35, 0x99, 0x70, 0x4a, 0xb7, 0x20, 0x44, 0xfd, 0x28, 0x6e, + 0x3f, 0x32, 0x7b, 0x53, 0xe2, 0xf0, 0x4c, 0x33, 0xb1, 0x75, 0x44, 0xa4, + 0x2c, 0x39, 0x90, 0x59, 0x43, 0xce, 0x20, 0xe7, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x38, 0x92, 0x53, 0xf7, 0x3e, 0x2e, 0xd3, 0xf9, 0x10, 0x9e, 0x6f, 0x98, + 0xd8, 0x89, 0xb1, 0x55, 0x4f, 0x3b, 0xee, 0xdc, 0xf9, 0xd4, 0x12, 0xae, + 0xbc, 0x07, 0xba, 0x9a, 0xc8, 0x50, 0xaf, 0x07, 0x91, 0x3f, 0xe1, 0xc9, + 0x9c, 0xc8, 0x24, 0xe9, 0x4e, 0x55, 0xcb, 0xe9, 0x9e, 0xe2, 0x30, 0x66, + 0xe8, 0xe0, 0x18, 0x83, 0x90, 0xaf, 0xd8, 0x8d, 0xc3, 0xe1, 0x2d, 0x41, + 0xb5, 0xb2, 0x77, 0x62, 0xa9, 0x6b, 0x2d, 0xb3, 0x05, 0xbf, 0x7c, 0x12, + 0x06, 0x53, 0x09, 0xaa, 0xb5, 0x71, 0xad, 0xf3, 0x5b, 0x26, 0x9b, 0xfb, + 0x64, 0x79, 0x39, 0x79, 0x4c, 0x2e, 0x7d, 0x1d, 0xae, 0xf3, 0x5d, 0x85, + 0x74, 0x55, 0xde, 0xb0, 0xfe, 0x12, 0x45, 0x1c, 0x41, 0x7e, 0x95, 0x55, + 0x30, 0x11, 0x81, 0x2e, 0xad, 0x9b, 0x81, 0x38, 0xf7, 0xac, 0xeb, 0x75, + 0xa5, 0x5e, 0xdc, 0xbf, 0x96, 0x8e, 0x1f, 0x68, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(108, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_109(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xf9, 0xaa, 0xbb, 0x49, 0x60, 0x0f, 0xef, 0x8a, 0x93, 0x11, 0xc0, 0x28, + 0x80, 0xb3, 0xab, 0x2d, 0xf9, 0x0a, 0xbb, 0xe0, 0x7f, 0x51, 0x43, 0x63, + 0x2c, 0x6c, 0x35, 0xb5, 0x73, 0xff, 0xdb, 0x8d, + }, + { + 0x7c, 0x64, 0xac, 0xa5, 0xa1, 0x21, 0x11, 0x4f, 0x6e, 0xbf, 0x5f, 0x62, + 0x9b, 0x08, 0x2b, 0x61, + }, + { + 0xf5, 0x55, 0x69, 0xa6, 0xdf, 0xb8, 0x77, 0x69, 0xcf, 0x69, 0xb0, 0x2b, + 0x40, 0x43, 0xa0, 0xe9, 0x05, 0x5b, 0x5a, 0xec, 0x53, 0xa3, 0x1d, 0x24, + 0x59, 0x55, 0x66, 0xd5, 0x22, 0xf7, 0x6c, 0xd5, + }, + { + 0x11, 0xdc, 0x58, 0x43, 0xc5, 0x5d, 0x03, 0x3b, 0x18, 0x01, 0x01, 0x6b, + 0xd0, 0xcf, 0x5d, 0x79, 0x9d, 0x76, 0x8c, 0xdc, 0x1e, 0xe3, 0xe2, 0x1d, + 0xa6, 0x1a, 0x02, 0x27, 0xb9, 0x83, 0x15, 0x8c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x3b, 0x6a, 0xa6, 0x99, 0xd9, 0x6f, 0x4f, 0x1d, 0xd2, 0x9c, 0x19, 0xc5, + 0x58, 0xd0, 0x3d, 0xb3, 0x00, 0xdb, 0x1c, 0xc9, 0x2f, 0xb1, 0xa0, 0x56, + 0x52, 0x79, 0xdb, 0x1d, 0x05, 0x56, 0x67, 0xa7, 0x84, 0x49, 0x34, 0xf0, + 0x4d, 0xb0, 0x00, 0x59, 0x4c, 0xc0, 0x66, 0xb0, 0x4b, 0xe5, 0x68, 0xc0, + 0xde, 0xa8, 0xe4, 0xeb, 0xe5, 0x46, 0x7e, 0x1f, 0xf9, 0xaf, 0x2c, 0x62, + 0x72, 0x3b, 0x90, 0xd4, 0xf2, 0xc2, 0x2a, 0x6c, 0xba, 0x2a, 0xfe, 0x15, + 0xf5, 0x50, 0x45, 0x03, 0xc8, 0xe4, 0x54, 0xdb, 0xc0, 0xe8, 0x0a, 0x20, + 0x33, 0x15, 0xa8, 0xf4, 0x59, 0xf9, 0xea, 0xfb, 0x71, 0x11, 0x64, 0x53, + 0x9d, 0xef, 0xa4, 0x42, 0xb8, 0xf3, 0x52, 0x0e, 0xbe, 0xd4, 0xa5, 0xfc, + 0x4a, 0x84, 0x46, 0x10, 0x69, 0xee, 0xc4, 0x42, 0x5a, 0xa3, 0xeb, 0x88, + 0xae, 0x6d, 0x83, 0xad, 0x7a, 0x23, 0x98, 0x50, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(109, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_110(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x88, 0xa7, 0x6c, 0x16, 0xd3, 0x27, 0x0e, 0xd3, 0xfc, 0xd1, 0x76, 0xf9, + 0xd7, 0x93, 0xfa, 0x0c, 0x35, 0x51, 0x65, 0x74, 0xc1, 0xce, 0xf4, 0x25, + 0xb6, 0x00, 0x76, 0x28, 0xaf, 0xa3, 0x5e, 0x2b, + }, + { + 0xff, 0x16, 0xcf, 0x7c, 0xb8, 0xe4, 0x9d, 0x48, 0x2c, 0xfd, 0x39, 0x94, + 0xab, 0xc5, 0xef, 0x8a, + }, + { + 0x92, 0x13, 0xc5, 0x4e, 0x3d, 0x00, 0x2d, 0xf8, 0x74, 0x11, 0x63, 0xab, + 0x9d, 0x7e, 0x07, 0x57, 0xcd, 0x51, 0x2c, 0x69, 0x1a, 0xd6, 0x4b, 0xaf, + 0xef, 0x95, 0xcb, 0x72, 0x53, 0x9b, 0x0a, 0xc6, + }, + { + 0x49, 0x3b, 0x64, 0x7f, 0xf0, 0xb3, 0xfa, 0xa2, 0x92, 0x1f, 0x12, 0xf8, + 0xf5, 0x7b, 0x91, 0x93, 0x29, 0xf2, 0xaf, 0x2f, 0xc1, 0xf1, 0x45, 0x76, + 0xd9, 0xdf, 0x2f, 0x8c, 0xc2, 0xad, 0xa7, 0xa6, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf1, 0x33, 0x0a, 0x85, 0xf9, 0x00, 0x37, 0x87, 0x6b, 0x37, 0x49, 0x20, + 0x3e, 0x84, 0x92, 0x87, 0x44, 0x4a, 0x82, 0x7f, 0x0a, 0x58, 0xc2, 0x49, + 0xff, 0x86, 0x8f, 0xc1, 0xad, 0xba, 0x4d, 0xce, 0x28, 0x5e, 0x07, 0x6a, + 0x1f, 0x8a, 0xe1, 0xda, 0x8c, 0xf9, 0xfe, 0x14, 0x93, 0x1e, 0x81, 0x64, + 0x18, 0x6c, 0x97, 0xa8, 0xfe, 0xaf, 0x24, 0x58, 0x34, 0x51, 0xf1, 0x16, + 0xe6, 0x5f, 0x8e, 0x43, 0x2e, 0x7e, 0xd5, 0x5a, 0x36, 0x68, 0x31, 0x20, + 0x37, 0x7e, 0x23, 0x12, 0x8d, 0xca, 0x15, 0x40, 0xfe, 0xfb, 0xf3, 0xaf, + 0x1b, 0x56, 0xd5, 0xc7, 0x41, 0x87, 0xf5, 0x28, 0x6d, 0x0a, 0x95, 0xfb, + 0x55, 0x93, 0x17, 0x70, 0x54, 0x30, 0x60, 0xce, 0x8d, 0xf0, 0x8f, 0x3c, + 0x19, 0x59, 0xa1, 0xf4, 0xfc, 0x36, 0xb6, 0x46, 0x71, 0xe0, 0x65, 0x4f, + 0xff, 0xe7, 0x0d, 0x96, 0xd5, 0x21, 0xbe, 0x21, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(110, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_111(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xf8, 0xf2, 0xc3, 0x19, 0x4e, 0x8c, 0x4e, 0x90, 0x9e, 0x6f, 0x05, 0x27, + 0x95, 0x03, 0x07, 0x18, 0xcd, 0xd6, 0x23, 0x53, 0x03, 0xbd, 0xe5, 0x37, + 0xea, 0x3c, 0x70, 0x53, 0x05, 0x62, 0x26, 0xe1, + }, + { + 0xd5, 0x0e, 0xf4, 0xd0, 0x6d, 0x00, 0x74, 0x54, 0x65, 0xce, 0x7b, 0x08, + 0xcd, 0x03, 0x51, 0x76, + }, + { + 0xed, 0x89, 0x7e, 0xc3, 0x3a, 0xe3, 0xf4, 0xb0, 0xc2, 0x0b, 0x12, 0x8d, + 0x94, 0x61, 0x5f, 0xe3, 0x87, 0x27, 0x0f, 0x8f, 0x0d, 0x66, 0x5e, 0x11, + 0x9b, 0x9b, 0x5a, 0xd1, 0x0f, 0xd3, 0x65, 0x7a, + }, + { + 0x91, 0x78, 0x49, 0x2a, 0x92, 0x51, 0x12, 0x80, 0x6b, 0x27, 0x80, 0x2e, + 0x0c, 0x9b, 0x0e, 0x70, 0xaf, 0x3f, 0xd5, 0xb6, 0xdb, 0x9a, 0xf8, 0x70, + 0x40, 0x28, 0x02, 0x56, 0x35, 0xc5, 0xed, 0x27, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x0e, 0x50, 0xd9, 0xdb, 0x9a, 0x5e, 0xb2, 0xd0, 0xb0, 0xd5, 0xc4, 0x53, + 0x01, 0x70, 0x7e, 0xe2, 0x81, 0x86, 0x68, 0x79, 0xe0, 0x72, 0xe5, 0x16, + 0x96, 0xe3, 0x28, 0x19, 0xb3, 0x3a, 0x44, 0xf0, 0xd0, 0x0b, 0x88, 0xab, + 0x5d, 0x6c, 0x31, 0xd9, 0x19, 0x88, 0xb1, 0x75, 0x7c, 0xee, 0xa8, 0x93, + 0x6e, 0xd5, 0xd0, 0xad, 0x67, 0x29, 0x90, 0xf4, 0x95, 0x1d, 0xfa, 0xea, + 0x99, 0x4d, 0xc0, 0x0f, 0x32, 0x65, 0x09, 0x5b, 0xdb, 0xef, 0xaf, 0x1d, + 0x42, 0x24, 0xda, 0x61, 0x68, 0x88, 0xa8, 0x06, 0x60, 0x9d, 0x28, 0x05, + 0xcf, 0x0f, 0x51, 0x83, 0xd5, 0xe9, 0x25, 0x26, 0x1e, 0x6b, 0x24, 0x90, + 0xdd, 0x85, 0x24, 0x2f, 0xc9, 0xfb, 0xd4, 0x26, 0xd7, 0x7a, 0xe8, 0x33, + 0x9a, 0xea, 0xc1, 0x83, 0x94, 0xbb, 0xf3, 0x51, 0xe0, 0x61, 0xe4, 0x95, + 0x61, 0x38, 0x36, 0x1d, 0x11, 0xb3, 0x57, 0x72, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(111, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_112(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x2a, 0x65, 0xb1, 0x29, 0x9d, 0x03, 0x4b, 0x95, 0x40, 0x07, 0xae, 0x77, + 0x34, 0x03, 0xf5, 0x09, 0xec, 0x8d, 0xf5, 0x2b, 0x25, 0xff, 0x57, 0x79, + 0x19, 0xd3, 0x3e, 0x97, 0x6f, 0xfd, 0x21, 0xa5, + }, + { + 0x80, 0x80, 0xab, 0xa8, 0xc9, 0xf7, 0xa0, 0x4a, 0xd4, 0x1c, 0x41, 0xde, + 0xbc, 0x8d, 0x6b, 0x02, + }, + { + 0x31, 0xa4, 0x66, 0x17, 0xe8, 0xee, 0xc9, 0x15, 0x70, 0x7b, 0x75, 0xf7, + 0xba, 0x78, 0x81, 0xf9, 0x63, 0x4e, 0x7b, 0x01, 0x5e, 0xf2, 0xa2, 0xfb, + 0x51, 0xf5, 0x92, 0xfd, 0xda, 0x27, 0xfb, 0x20, + }, + { + 0xe3, 0xc8, 0x81, 0x51, 0x72, 0xec, 0xee, 0x13, 0xe6, 0x49, 0xff, 0x62, + 0x4c, 0x62, 0x43, 0xaf, 0xbb, 0x46, 0x60, 0x2b, 0xbf, 0xc3, 0xbd, 0x28, + 0xd0, 0x31, 0x7b, 0xad, 0x68, 0x56, 0xc6, 0x6f, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x5b, 0x1c, 0x01, 0xab, 0x1d, 0xf4, 0x42, 0x30, 0x5d, 0xaa, 0x89, 0x98, + 0x72, 0x8e, 0x1e, 0x99, 0x97, 0x5b, 0x32, 0x32, 0x7d, 0xa7, 0x27, 0xf1, + 0x62, 0xaf, 0xf5, 0xec, 0xbb, 0x01, 0xd4, 0xd6, 0xe8, 0xb8, 0x55, 0x1f, + 0x7a, 0xbe, 0x18, 0x92, 0x62, 0x50, 0x12, 0xc2, 0x48, 0x17, 0x8b, 0x2e, + 0xc1, 0x2d, 0x64, 0xd8, 0x40, 0x63, 0xf8, 0x7f, 0x12, 0x79, 0x28, 0xeb, + 0xab, 0x06, 0xcf, 0xc3, 0x77, 0xfd, 0x96, 0x55, 0xaa, 0xdb, 0xa3, 0x61, + 0xb9, 0x3f, 0x97, 0x6e, 0x51, 0x33, 0xb6, 0xfb, 0x87, 0x45, 0xf1, 0x30, + 0xd8, 0xc5, 0xea, 0xe6, 0xf0, 0xd3, 0x85, 0x7f, 0xe5, 0xc6, 0x89, 0x04, + 0xad, 0xea, 0xa2, 0x24, 0xcc, 0xb9, 0x3a, 0x96, 0x0e, 0xd7, 0x9e, 0xcf, + 0x55, 0xd6, 0xaf, 0x30, 0x7d, 0x28, 0x73, 0x66, 0xb8, 0xa2, 0xd4, 0x66, + 0xb9, 0x5e, 0xdb, 0xa1, 0x42, 0xe8, 0x6d, 0x12, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(112, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_113(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x85, 0xb6, 0x0f, 0xaa, 0x4e, 0xbf, 0xde, 0x82, 0x5f, 0x0a, 0x49, 0x70, + 0xc8, 0x0c, 0x78, 0xe3, 0x77, 0xa5, 0x1d, 0xce, 0xbb, 0x09, 0x45, 0x3a, + 0x03, 0xb6, 0x46, 0xcb, 0xdc, 0x1c, 0x2f, 0x0e, + }, + { + 0xfb, 0x4d, 0xff, 0x7e, 0x1a, 0xd3, 0x7f, 0x1d, 0x00, 0xa1, 0x00, 0xde, + 0x0a, 0x9d, 0x5d, 0x2b, + }, + { + 0x46, 0x10, 0xc5, 0x65, 0x63, 0x72, 0x6c, 0x7b, 0xaa, 0x3a, 0x21, 0x12, + 0x90, 0x4a, 0xd8, 0x03, 0x62, 0x55, 0xc9, 0x2f, 0xe7, 0x48, 0xd6, 0x5f, + 0x12, 0x33, 0x35, 0x48, 0x96, 0xfe, 0xe7, 0x2a, + }, + { + 0x85, 0x40, 0x56, 0x92, 0x7b, 0x35, 0x05, 0x3b, 0x57, 0x44, 0x8a, 0x2e, + 0x0b, 0x6c, 0x7c, 0xf3, 0x71, 0xce, 0x10, 0x79, 0x7e, 0xab, 0x1c, 0x0a, + 0x00, 0x9d, 0x7a, 0xbd, 0x1a, 0x06, 0x7c, 0xcc, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x19, 0x42, 0xa4, 0xdc, 0x08, 0xfe, 0x8d, 0x92, 0xf5, 0xfa, 0x58, 0x17, + 0x56, 0xdd, 0xc3, 0xf7, 0xa3, 0x21, 0xcb, 0x96, 0x93, 0x3c, 0xc1, 0x93, + 0x71, 0x1a, 0x0f, 0x64, 0x40, 0xa7, 0x6b, 0x6c, 0x5a, 0x5d, 0xb8, 0x06, + 0x9c, 0x5c, 0x82, 0xfe, 0x3e, 0x1c, 0xdf, 0x3f, 0x35, 0x20, 0xde, 0xb1, + 0x65, 0x2a, 0x96, 0x98, 0xf9, 0x72, 0x6f, 0xd4, 0x04, 0x8b, 0xab, 0xaf, + 0x07, 0x05, 0x0e, 0x93, 0x7d, 0x56, 0x54, 0x28, 0x99, 0xee, 0xa5, 0xec, + 0x2c, 0x16, 0x91, 0x9a, 0x36, 0x0d, 0xe5, 0xcc, 0xf4, 0x9e, 0xee, 0xd1, + 0x15, 0xee, 0x02, 0xc0, 0x67, 0xb7, 0x25, 0x52, 0xbc, 0x4d, 0x4e, 0xef, + 0xb6, 0xaa, 0x91, 0xa2, 0x33, 0xdd, 0x73, 0x17, 0x95, 0x9a, 0x7e, 0x80, + 0xe1, 0x6b, 0x17, 0x37, 0x91, 0x84, 0x50, 0x3c, 0xbf, 0x39, 0x31, 0xa6, + 0x9e, 0x90, 0x2d, 0x97, 0xf8, 0x20, 0xf8, 0x03, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(113, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_114(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xbb, 0x71, 0x47, 0xf6, 0x74, 0x54, 0x51, 0x7b, 0x2f, 0x2b, 0x10, 0x37, + 0x90, 0xb4, 0x42, 0x47, 0xef, 0xb5, 0x28, 0xa7, 0x7a, 0x05, 0xaa, 0x22, + 0x0c, 0x8f, 0xe4, 0x0b, 0x32, 0x3a, 0x1f, 0x0a, + }, + { + 0x33, 0xb4, 0x2b, 0x70, 0xeb, 0x65, 0xd9, 0x85, 0xf2, 0x47, 0x61, 0x36, + 0xc9, 0x49, 0xca, 0x18, + }, + { + 0x7e, 0xaa, 0x52, 0xf6, 0xd4, 0x35, 0x29, 0x8f, 0xda, 0x70, 0xef, 0x9a, + 0xba, 0xe9, 0x0e, 0xb5, 0x49, 0x68, 0xbd, 0x2b, 0x4c, 0xe7, 0x49, 0x83, + 0x6c, 0xb2, 0xb1, 0x1e, 0x45, 0x2f, 0x67, 0x68, + }, + { + 0x4c, 0x26, 0x86, 0xe2, 0xed, 0xc7, 0xa2, 0x5b, 0xc9, 0x27, 0x46, 0x42, + 0xb8, 0x86, 0xf1, 0x51, 0x0c, 0x4d, 0x0f, 0x00, 0x71, 0x5b, 0x75, 0x90, + 0x1a, 0x40, 0xf3, 0xd1, 0x53, 0x77, 0x88, 0xfc, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x50, 0xdc, 0x60, 0xbf, 0x8d, 0xf4, 0xb7, 0x3e, 0x0c, 0x95, 0xb3, 0xe1, + 0x73, 0x64, 0x11, 0x1d, 0xde, 0xff, 0x81, 0x44, 0x24, 0x60, 0xd6, 0xc9, + 0x35, 0xe1, 0xfc, 0x5d, 0x2e, 0xd2, 0x95, 0xc2, 0x54, 0xc5, 0xc9, 0xf3, + 0x9d, 0x18, 0xf6, 0x54, 0x0e, 0x69, 0x7a, 0x1a, 0x7f, 0xc5, 0x88, 0xb3, + 0x7e, 0x8f, 0xc4, 0x5f, 0x31, 0x4c, 0x06, 0xe9, 0xeb, 0x04, 0x45, 0x8f, + 0x3b, 0xd1, 0x8d, 0x23, 0xfb, 0x33, 0xdb, 0x2a, 0x31, 0x85, 0xa0, 0xcb, + 0x2b, 0x2d, 0x9b, 0xa6, 0x09, 0x15, 0x38, 0xe8, 0x5c, 0x2d, 0x6f, 0xba, + 0xc0, 0x20, 0x1f, 0xec, 0xd3, 0x37, 0xd2, 0x68, 0x34, 0x7a, 0xd8, 0xf3, + 0x04, 0x21, 0x3c, 0x3a, 0xf9, 0x45, 0xca, 0x31, 0xed, 0xf8, 0xbe, 0x84, + 0x7a, 0x7b, 0x56, 0xd7, 0xbd, 0xcd, 0x30, 0x83, 0x99, 0xb0, 0x65, 0x02, + 0x79, 0x44, 0x43, 0xf7, 0x38, 0xf6, 0xee, 0x55, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(114, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_115(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xd7, 0xdc, 0xdf, 0xaa, 0x81, 0xc3, 0x51, 0x19, 0xa4, 0x69, 0x51, 0xae, + 0xd8, 0xd8, 0x89, 0x95, 0x02, 0xfc, 0x21, 0xb9, 0x09, 0xc8, 0xde, 0x8c, + 0xf3, 0xa5, 0x67, 0xc1, 0xae, 0x81, 0x16, 0x1d, + }, + { + 0x4c, 0x24, 0x49, 0x56, 0x7c, 0x08, 0x67, 0xc9, 0xf4, 0x3b, 0x75, 0x28, + 0x60, 0xe3, 0x4b, 0xde, + }, + { + 0x09, 0x41, 0x7a, 0x19, 0x12, 0xef, 0xc0, 0x14, 0x65, 0xa8, 0x68, 0x2f, + 0xf7, 0x13, 0x78, 0x70, 0x65, 0x24, 0xb4, 0x6a, 0x0c, 0x27, 0x22, 0x0e, + 0x9e, 0x40, 0xec, 0x43, 0x07, 0x3c, 0x56, 0x3c, + }, + { + 0x54, 0x8a, 0x97, 0xb1, 0x12, 0xab, 0x6c, 0xcb, 0x57, 0x8d, 0xd7, 0x75, + 0x99, 0xdf, 0x0c, 0xac, 0xde, 0x33, 0x2a, 0xc1, 0xa6, 0x00, 0x88, 0xdc, + 0x01, 0x8d, 0x18, 0x38, 0x75, 0xb6, 0x1c, 0x51, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb2, 0x00, 0xd6, 0x98, 0xfc, 0x72, 0xf0, 0x1e, 0x97, 0x09, 0xe5, 0x3a, + 0x0c, 0xa4, 0x82, 0xed, 0x3b, 0xe1, 0x0e, 0x27, 0x72, 0x96, 0x42, 0x4c, + 0xef, 0xd1, 0x10, 0x72, 0xc7, 0xb1, 0x9b, 0xdd, 0xf7, 0x0f, 0xf1, 0x37, + 0xc9, 0x56, 0xe4, 0xd1, 0x1d, 0x8e, 0xb1, 0xeb, 0x29, 0xbb, 0xe4, 0x97, + 0x9c, 0xba, 0x9e, 0x2e, 0xb9, 0x41, 0xf5, 0x29, 0xea, 0x96, 0x84, 0xce, + 0xc6, 0x61, 0x4a, 0x5f, 0x8c, 0x30, 0x95, 0x0d, 0x95, 0x44, 0x14, 0x8f, + 0xc4, 0xc9, 0x2b, 0xb8, 0xb7, 0xba, 0x89, 0x9e, 0x72, 0x17, 0x48, 0xa1, + 0xd6, 0xbf, 0x5e, 0x8b, 0xb6, 0x42, 0x9b, 0xa9, 0x02, 0x0e, 0x08, 0x9a, + 0x7c, 0x1e, 0x91, 0x0c, 0x8f, 0xc7, 0x08, 0xe0, 0x2b, 0xe7, 0x5e, 0xfb, + 0x89, 0xf0, 0x0d, 0x6f, 0x8b, 0x52, 0x05, 0x40, 0x62, 0xe4, 0x33, 0x43, + 0xa6, 0x0d, 0xee, 0xd3, 0x9c, 0xd8, 0x75, 0x6a, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(115, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_116(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x79, 0xad, 0xc5, 0xce, 0xae, 0xf7, 0x71, 0x10, 0x24, 0x01, 0xac, 0xc2, + 0xfc, 0xb3, 0xd0, 0x1d, 0x9b, 0xf7, 0x54, 0x1e, 0xd8, 0x6e, 0x8a, 0xa1, + 0x6c, 0x93, 0x8d, 0x95, 0x56, 0x82, 0x9a, 0x8e, + }, + { + 0x37, 0x9d, 0x9a, 0xeb, 0xe0, 0xbd, 0xbc, 0xa0, 0x7c, 0x77, 0x4b, 0x5e, + 0xf1, 0xee, 0x73, 0x2d, + }, + { + 0x8b, 0x13, 0x32, 0x6a, 0x52, 0x19, 0x57, 0xed, 0xe0, 0x04, 0x23, 0x5c, + 0xd1, 0x38, 0x76, 0x7b, 0x7f, 0x45, 0xf5, 0x50, 0xf2, 0xfc, 0x55, 0xb1, + 0xf6, 0x7c, 0xdc, 0xc7, 0x09, 0x23, 0x81, 0x1d, + }, + { + 0xe2, 0x68, 0xce, 0xa9, 0xdd, 0xeb, 0x0c, 0xca, 0x53, 0x88, 0xe1, 0x24, + 0x17, 0xd9, 0x0c, 0x7f, 0xab, 0x62, 0x9b, 0x2b, 0x2c, 0x14, 0x4d, 0xdc, + 0x80, 0x54, 0xd0, 0x42, 0x10, 0x58, 0x67, 0x14, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0x00, 0x8f, 0xed, 0xe4, 0x41, 0xe5, 0x50, 0x95, 0x5d, 0x75, 0x9c, 0x89, + 0x22, 0x93, 0x59, 0xf6, 0xa0, 0x6e, 0xc2, 0xc0, 0x6c, 0xe2, 0xdc, 0xf4, + 0x2b, 0xb7, 0x2f, 0x25, 0x5c, 0x28, 0xed, 0x75, 0x8b, 0x38, 0xa5, 0xf7, + 0xf7, 0xea, 0x94, 0x51, 0xa1, 0xc9, 0xb7, 0xa6, 0x88, 0xd3, 0x79, 0xc9, + 0xd3, 0x6f, 0xa7, 0xc8, 0x6e, 0xb1, 0x1b, 0x67, 0xf4, 0xe3, 0xb9, 0x83, + 0xfe, 0x4b, 0x42, 0x15, 0x9f, 0xa6, 0x23, 0xf5, 0x5e, 0xea, 0x9f, 0xb1, + 0xff, 0x36, 0x76, 0xad, 0x54, 0x7d, 0xf4, 0x69, 0x60, 0x7a, 0x03, 0xe8, + 0xf8, 0x32, 0x26, 0x79, 0x68, 0xc8, 0x38, 0x8b, 0x2d, 0xb8, 0x49, 0x16, + 0x6a, 0x98, 0xa9, 0x8a, 0xef, 0x8d, 0x9e, 0x25, 0x88, 0x8b, 0x1f, 0x6a, + 0xec, 0x3d, 0x66, 0xa0, 0x26, 0x35, 0x32, 0x59, 0xbd, 0xa9, 0x02, 0xdf, + 0x45, 0x5e, 0x6d, 0x2d, 0x52, 0x2c, 0xde, 0xd4, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(116, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_117(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x37, 0x6d, 0xfb, 0x59, 0x42, 0x41, 0x45, 0x42, 0x0a, 0xc6, 0x59, 0x67, + 0x14, 0x5f, 0x6f, 0xa5, 0x1a, 0xac, 0xec, 0x27, 0xbe, 0xa1, 0xd3, 0xf9, + 0xf8, 0xb7, 0x61, 0x6f, 0xcb, 0x36, 0xf7, 0x3b, + }, + { + 0x56, 0x4c, 0x1c, 0xb8, 0x2b, 0xef, 0x2b, 0xdc, 0x2c, 0x69, 0x99, 0x55, + 0xbd, 0x2b, 0x07, 0x77, + }, + { + 0xa0, 0x83, 0x9d, 0xaa, 0xac, 0xe6, 0xff, 0x20, 0x9f, 0xba, 0x71, 0xc6, + 0xbb, 0xba, 0x05, 0x84, 0x49, 0x7c, 0xff, 0x77, 0x5d, 0x86, 0x50, 0x72, + 0x28, 0x71, 0x7b, 0x57, 0x6f, 0x3d, 0x5e, 0xd2, + }, + { + 0x23, 0x0d, 0xa7, 0x2e, 0x74, 0x36, 0x7d, 0x92, 0x10, 0x77, 0xb7, 0xc3, + 0x8c, 0x11, 0xeb, 0x9e, 0x17, 0x13, 0x1f, 0x7e, 0xe4, 0xff, 0x58, 0x0e, + 0xd8, 0x83, 0x53, 0x0d, 0xac, 0xf3, 0x41, 0x99, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xa7, 0xfe, 0xff, 0x8c, 0x68, 0x59, 0xff, 0x3d, 0x69, 0x54, 0x3b, 0xe6, + 0x16, 0x57, 0xc8, 0xc1, 0x9b, 0xe1, 0x2b, 0x9f, 0x2b, 0x53, 0x48, 0xb9, + 0x4f, 0x23, 0x70, 0x04, 0x43, 0x7a, 0x20, 0xc6, 0xbe, 0x86, 0x19, 0xd5, + 0x31, 0x00, 0x5f, 0xc4, 0x7f, 0xcd, 0x6a, 0x1f, 0x07, 0x38, 0x0f, 0xca, + 0x90, 0x75, 0xfb, 0x11, 0x48, 0xf5, 0xe3, 0xe1, 0x57, 0x16, 0x99, 0x8c, + 0x12, 0x68, 0xba, 0xc9, 0x72, 0xf9, 0x4e, 0x1b, 0x3e, 0xdb, 0x89, 0xe2, + 0x86, 0xa7, 0xb3, 0x6a, 0x53, 0xc0, 0x21, 0xfc, 0xa6, 0x04, 0x53, 0xd7, + 0xfb, 0x03, 0xa4, 0xeb, 0x00, 0x96, 0x0d, 0xe3, 0x1c, 0x45, 0x8b, 0x37, + 0x79, 0x86, 0xaf, 0x33, 0xfc, 0xfc, 0xef, 0xa7, 0xf6, 0xc9, 0x38, 0xc7, + 0xfc, 0x61, 0x83, 0x37, 0xd4, 0xec, 0x8b, 0xd9, 0x42, 0xb2, 0x3a, 0xb0, + 0x1b, 0xb3, 0xb3, 0xde, 0x27, 0x0c, 0xc9, 0xa9, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(117, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_118(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0xfd, 0xbe, 0xe9, 0xba, 0xff, 0x0d, 0x02, 0x17, 0x18, 0xbc, 0x07, 0x32, + 0xce, 0x5b, 0x2e, 0x0b, 0xba, 0x13, 0x3b, 0xd3, 0x19, 0xb4, 0xc5, 0x37, + 0x5c, 0xbe, 0x32, 0xda, 0x82, 0x74, 0xef, 0x72, + }, + { + 0x68, 0x48, 0xa7, 0x8d, 0xac, 0x81, 0x74, 0x3c, 0x0a, 0xc4, 0xc1, 0xd7, + 0xa0, 0x8b, 0x21, 0xf3, + }, + { + 0xeb, 0xc1, 0xf9, 0x76, 0x83, 0x42, 0x63, 0x2f, 0x57, 0x6f, 0x7a, 0xf5, + 0x03, 0x69, 0x95, 0x98, 0xd1, 0x3b, 0xba, 0x5f, 0xcc, 0x8f, 0xfb, 0xe2, + 0x94, 0xbd, 0xd1, 0x6b, 0x8c, 0x86, 0x5f, 0xad, + }, + { + 0xcc, 0x39, 0x27, 0x64, 0x5f, 0x65, 0xf5, 0x46, 0x60, 0xc1, 0x69, 0xfd, + 0x33, 0x94, 0xa3, 0x6a, 0x98, 0x9c, 0x76, 0x0a, 0x28, 0x7f, 0x23, 0xee, + 0x8b, 0xe2, 0x3d, 0x0b, 0xcd, 0xb2, 0xbf, 0x6c, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xb4, 0x58, 0xae, 0xd8, 0x8a, 0x53, 0xcb, 0x5a, 0x1a, 0x15, 0x71, 0x97, + 0xb3, 0x80, 0x79, 0xcd, 0xa4, 0x55, 0xbe, 0xdb, 0xc0, 0xe6, 0x9f, 0x7c, + 0x66, 0xc1, 0xca, 0x67, 0xad, 0xec, 0x05, 0xa4, 0x11, 0x71, 0x53, 0x09, + 0x58, 0x2c, 0x7a, 0x2d, 0x57, 0x09, 0xa4, 0xd6, 0xf2, 0x7c, 0x70, 0x68, + 0x66, 0x27, 0xad, 0xec, 0xc6, 0x8f, 0x3a, 0x20, 0x45, 0xb8, 0xe7, 0xce, + 0xd5, 0xb9, 0x2b, 0x5d, 0xfa, 0x4a, 0x36, 0xe5, 0x55, 0xfd, 0x42, 0x12, + 0xf1, 0xe0, 0x33, 0xd9, 0x4a, 0x52, 0x3b, 0x16, 0xf1, 0xa4, 0xfb, 0x15, + 0xb6, 0x95, 0xd5, 0x8d, 0xf4, 0xa5, 0xbe, 0x8e, 0xe7, 0xa2, 0xb9, 0xcb, + 0xa0, 0xaf, 0x05, 0xf2, 0x94, 0xcf, 0x0d, 0xaf, 0x54, 0xca, 0xba, 0x5b, + 0xfc, 0xd2, 0x89, 0xc6, 0xf7, 0xd9, 0x78, 0xef, 0xb4, 0x12, 0x63, 0xc1, + 0xba, 0x0d, 0xeb, 0xb0, 0x6b, 0x56, 0xf3, 0xdc, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(118, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_119(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x0d, 0x10, 0x15, 0xbc, 0xe0, 0xf7, 0xba, 0xc3, 0xc0, 0x74, 0x20, 0xb4, + 0xf3, 0xf9, 0xbe, 0xca, 0x05, 0x64, 0x87, 0x89, 0x7a, 0xb2, 0x6e, 0x8a, + 0xd5, 0xc3, 0x39, 0x03, 0x6c, 0x87, 0xa7, 0xce, + }, + { + 0xad, 0x72, 0x17, 0x94, 0x44, 0x30, 0x6c, 0x67, 0x7b, 0xb2, 0x70, 0x9d, + 0x1d, 0x46, 0x4e, 0xfc, + }, + { + 0xe8, 0xce, 0x89, 0xf4, 0xb7, 0xe0, 0xcb, 0xb3, 0xa2, 0xfb, 0x74, 0x79, + 0xd9, 0x5e, 0x80, 0xb3, 0x6e, 0xae, 0x5c, 0x62, 0xd7, 0x23, 0x2f, 0x26, + 0xc5, 0xa9, 0x10, 0x35, 0x99, 0xa4, 0x9b, 0xdd, + }, + { + 0x15, 0x58, 0x98, 0x57, 0x01, 0x04, 0x68, 0xca, 0x37, 0xcb, 0x83, 0xad, + 0xd5, 0x9c, 0xfc, 0x73, 0x3f, 0x6e, 0x97, 0xf9, 0x53, 0xe2, 0xf8, 0xb8, + 0xb9, 0x8f, 0xab, 0xb8, 0x1f, 0x60, 0x8e, 0x47, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xcd, 0xb7, 0xa1, 0x15, 0x16, 0x1c, 0x33, 0x2a, 0x97, 0xca, 0xee, 0xa6, + 0xeb, 0x7a, 0x6b, 0xfd, 0x29, 0x9a, 0x76, 0x8a, 0x8f, 0x78, 0x27, 0xdf, + 0x16, 0x30, 0x48, 0xf4, 0xdb, 0xf1, 0x75, 0x0e, 0xe1, 0xe8, 0x4d, 0x52, + 0x1b, 0x80, 0x01, 0xad, 0x7d, 0xbf, 0x97, 0xa8, 0x67, 0xfb, 0x2b, 0x99, + 0xd2, 0x1f, 0x99, 0x52, 0x4b, 0x84, 0x11, 0x36, 0x36, 0x36, 0xe2, 0xd4, + 0x40, 0xe9, 0x4f, 0x26, 0xf2, 0xdd, 0x93, 0x51, 0x6e, 0x08, 0x96, 0x4d, + 0x29, 0x1f, 0x49, 0x96, 0x1a, 0xd2, 0xf3, 0xfa, 0x21, 0xf6, 0xac, 0x7a, + 0x00, 0xda, 0x08, 0xdb, 0xd8, 0x3c, 0x52, 0x02, 0x31, 0xa9, 0x7e, 0x48, + 0x29, 0xf6, 0x76, 0xfb, 0xc1, 0x87, 0x17, 0xab, 0xce, 0xdc, 0x4d, 0xee, + 0x2a, 0x41, 0x44, 0x0d, 0x57, 0x97, 0xab, 0x01, 0x45, 0x37, 0xa4, 0x2f, + 0x59, 0x53, 0xa9, 0x59, 0x53, 0x5b, 0x3c, 0x81, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(119, &vec); + TC_END_RESULT(result); + return result; +} + +unsigned int test_120(void) +{ + unsigned int result = TC_PASS; + const struct hmac_prng_test_vector vec = { + 32, + 16, + 32, + 0, + 128, + { + 0x92, 0x84, 0xfd, 0x46, 0x60, 0xbe, 0xb7, 0xa1, 0x54, 0x34, 0x9d, 0x74, + 0xe2, 0xad, 0x84, 0x42, 0xa5, 0xac, 0x06, 0x67, 0xac, 0x4d, 0x28, 0xda, + 0xf0, 0x52, 0x9d, 0xac, 0x5c, 0x80, 0x5a, 0x21, + }, + { + 0xaf, 0xe9, 0x6e, 0x33, 0xc6, 0xd5, 0xbe, 0xf1, 0x65, 0x28, 0x21, 0xde, + 0xdb, 0x96, 0x41, 0x83, + }, + { + 0x1b, 0x34, 0x19, 0xbe, 0xc2, 0x51, 0x35, 0x31, 0xfa, 0x5f, 0xaf, 0xb4, + 0x27, 0x85, 0xeb, 0x07, 0xec, 0x01, 0xb6, 0x1a, 0x1e, 0x06, 0x45, 0x28, + 0x08, 0xb2, 0x27, 0xf5, 0xf5, 0xc8, 0x73, 0xcf, + }, + { + 0xf4, 0x94, 0x2b, 0x20, 0xa4, 0x25, 0x89, 0xa2, 0x2e, 0x1b, 0x3b, 0x22, + 0x14, 0x33, 0x6d, 0x1b, 0xa3, 0xb1, 0x17, 0x53, 0x93, 0x7b, 0x93, 0xf1, + 0xd7, 0xc3, 0x63, 0x6b, 0x34, 0x6d, 0x70, 0xa1, + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + { + 0xf0, 0xb8, 0x7f, 0x8c, 0x3c, 0x67, 0xf4, 0xdf, 0x3c, 0xc6, 0x13, 0xc3, + 0xc6, 0x79, 0x99, 0x67, 0x59, 0x51, 0x17, 0x7c, 0x2d, 0x7d, 0x64, 0x6e, + 0xc0, 0x3e, 0x52, 0x22, 0x67, 0xea, 0x1d, 0x39, 0xd4, 0x20, 0x60, 0xd8, + 0xb1, 0x57, 0x77, 0x4a, 0xf7, 0xad, 0x7f, 0xd7, 0xf8, 0x51, 0xf9, 0xc1, + 0x3a, 0xaf, 0xa5, 0x6a, 0x64, 0xd7, 0xc0, 0xff, 0x86, 0xc8, 0xdd, 0x95, + 0x88, 0xf6, 0x9c, 0x6e, 0x7a, 0x96, 0x80, 0x75, 0x9b, 0xc1, 0xb6, 0x02, + 0x79, 0x8b, 0x23, 0x95, 0x9f, 0xe5, 0x4f, 0xf4, 0xbd, 0x2c, 0xe2, 0xd8, + 0xed, 0xe7, 0x29, 0x8f, 0x68, 0x80, 0x1a, 0xad, 0x61, 0x97, 0x74, 0x85, + 0xe0, 0xac, 0xba, 0xde, 0xec, 0xf4, 0x7b, 0x7e, 0xb3, 0x0e, 0x92, 0xf4, + 0x06, 0xd9, 0x73, 0xe3, 0x26, 0x51, 0x8d, 0xb3, 0xaf, 0x0e, 0xa0, 0x6e, + 0xa5, 0x74, 0xba, 0x7b, 0x01, 0x61, 0xab, 0xf2, + } + }; + + TC_PRINT("HMAC-PRNG %s:\n", __func__); + result = do_hmac_prng_pr_false_test(120, &vec); + TC_END_RESULT(result); + return result; +} + + +/* + * Main task to test HMAC-PRNG + */ +int main(void) +{ + unsigned int result = TC_PASS; + + TC_START("Performing HMAC-PRNG tests:"); + + result = test_1(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_2(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_3(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_4(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_5(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_6(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_7(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_8(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_9(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_10(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_11(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_12(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_13(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_14(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_15(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_16(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_17(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_18(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_19(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_20(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_21(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_22(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_23(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_24(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_25(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_26(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_27(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_28(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_29(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_30(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_31(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_32(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_33(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_34(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_35(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_36(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_37(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_38(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_39(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_40(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_41(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_42(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_43(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_44(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_45(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_46(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_47(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_48(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_49(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_50(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_51(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_52(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_53(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_54(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_55(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_56(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_57(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_58(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_59(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_60(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_61(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_62(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_63(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_64(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_65(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_66(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_67(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_68(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_69(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_70(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_71(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_72(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_73(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_74(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_75(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_76(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_77(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_78(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_79(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_80(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_81(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_82(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_83(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_84(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_85(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_86(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_87(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_88(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_89(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_90(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_91(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_92(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_93(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_94(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_95(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_96(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_97(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_98(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_99(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_100(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_101(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_102(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_103(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_104(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_105(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_106(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_107(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_108(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_109(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_110(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_111(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_112(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_113(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_114(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_115(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_116(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_117(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_118(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_119(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + result = test_120(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("HMAC test #{test_number} failed.\n"); + goto exitTest; + } + + TC_PRINT("All HMAC-PRNG tests succeeded!\n"); + +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} diff --git a/tinycrypt/tests/test_sha256.c b/tinycrypt/tests/test_sha256.c new file mode 100644 index 00000000..b309ed18 --- /dev/null +++ b/tinycrypt/tests/test_sha256.c @@ -0,0 +1,511 @@ +/* test_sha256.c - TinyCrypt implementation of some SHA-256 tests */ + +/* + * Copyright (C) 2017 by Intel Corporation, All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +/* + DESCRIPTION + This module tests the following SHA256 routines: + + Scenarios tested include: + - NIST SHA256 test vectors +*/ + +#include +#include +#include + +#include +#include +#include +#include + +/* + * NIST SHA256 test vector 1. + */ +unsigned int test_1(void) +{ + unsigned int result = TC_PASS; + + TC_PRINT("SHA256 test #1:\n"); + const uint8_t expected[32] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad + }; + const char *m = "abc"; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, (const uint8_t *) m, strlen(m)); + (void)tc_sha256_final(digest, &s); + result = check_result(1, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +/* + * NIST SHA256 test vector 2. + */ +unsigned int test_2(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #2:\n"); + const uint8_t expected[32] = { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, + 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 + }; + const char *m = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, (const uint8_t *) m, strlen(m)); + (void) tc_sha256_final(digest, &s); + + result = check_result(2, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_3(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #3:\n"); + const uint8_t expected[32] = { + 0x68, 0x32, 0x57, 0x20, 0xaa, 0xbd, 0x7c, 0x82, 0xf3, 0x0f, 0x55, 0x4b, + 0x31, 0x3d, 0x05, 0x70, 0xc9, 0x5a, 0xcc, 0xbb, 0x7d, 0xc4, 0xb5, 0xaa, + 0xe1, 0x12, 0x04, 0xc0, 0x8f, 0xfe, 0x73, 0x2b + }; + const uint8_t m[1] = { 0xbd }; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(3, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_4(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #4:\n"); + const uint8_t expected[32] = { + 0x7a, 0xbc, 0x22, 0xc0, 0xae, 0x5a, 0xf2, 0x6c, 0xe9, 0x3d, 0xbb, 0x94, + 0x43, 0x3a, 0x0e, 0x0b, 0x2e, 0x11, 0x9d, 0x01, 0x4f, 0x8e, 0x7f, 0x65, + 0xbd, 0x56, 0xc6, 0x1c, 0xcc, 0xcd, 0x95, 0x04 + }; + const uint8_t m[4] = { 0xc9, 0x8c, 0x8e, 0x55 }; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(4, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_5(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #5:\n"); + + const uint8_t expected[32] = { + 0x02, 0x77, 0x94, 0x66, 0xcd, 0xec, 0x16, 0x38, 0x11, 0xd0, 0x78, 0x81, + 0x5c, 0x63, 0x3f, 0x21, 0x90, 0x14, 0x13, 0x08, 0x14, 0x49, 0x00, 0x2f, + 0x24, 0xaa, 0x3e, 0x80, 0xf0, 0xb8, 0x8e, 0xf7 + }; + uint8_t m[55]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x00, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(5, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_6(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #6:\n"); + const uint8_t expected[32] = { + 0xd4, 0x81, 0x7a, 0xa5, 0x49, 0x76, 0x28, 0xe7, 0xc7, 0x7e, 0x6b, 0x60, + 0x61, 0x07, 0x04, 0x2b, 0xbb, 0xa3, 0x13, 0x08, 0x88, 0xc5, 0xf4, 0x7a, + 0x37, 0x5e, 0x61, 0x79, 0xbe, 0x78, 0x9f, 0xbb + }; + uint8_t m[56]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x00, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(6, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_7(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #7:\n"); + const uint8_t expected[32] = { + 0x65, 0xa1, 0x6c, 0xb7, 0x86, 0x13, 0x35, 0xd5, 0xac, 0xe3, 0xc6, 0x07, + 0x18, 0xb5, 0x05, 0x2e, 0x44, 0x66, 0x07, 0x26, 0xda, 0x4c, 0xd1, 0x3b, + 0xb7, 0x45, 0x38, 0x1b, 0x23, 0x5a, 0x17, 0x85 + }; + uint8_t m[57]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x00, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(7, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_8(void) +{ + unsigned int result = TC_PASS; + + TC_PRINT("SHA256 test #8:\n"); + const uint8_t expected[32] = { + 0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30, 0x27, 0x98, 0xef, 0x6e, + 0xd3, 0x09, 0x97, 0x9b, 0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8, + 0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x4b + }; + uint8_t m[64]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x00, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(8, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_9(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #9:\n"); + const uint8_t expected[32] = { + 0x54, 0x1b, 0x3e, 0x9d, 0xaa, 0x09, 0xb2, 0x0b, 0xf8, 0x5f, 0xa2, 0x73, + 0xe5, 0xcb, 0xd3, 0xe8, 0x01, 0x85, 0xaa, 0x4e, 0xc2, 0x98, 0xe7, 0x65, + 0xdb, 0x87, 0x74, 0x2b, 0x70, 0x13, 0x8a, 0x53 + }; + uint8_t m[1000]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x00, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(9, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_10(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #10:\n"); + const uint8_t expected[32] = { + 0xc2, 0xe6, 0x86, 0x82, 0x34, 0x89, 0xce, 0xd2, 0x01, 0x7f, 0x60, 0x59, + 0xb8, 0xb2, 0x39, 0x31, 0x8b, 0x63, 0x64, 0xf6, 0xdc, 0xd8, 0x35, 0xd0, + 0xa5, 0x19, 0x10, 0x5a, 0x1e, 0xad, 0xd6, 0xe4 + }; + uint8_t m[1000]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x41, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(10, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_11(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #11:\n"); + const uint8_t expected[32] = { + 0xf4, 0xd6, 0x2d, 0xde, 0xc0, 0xf3, 0xdd, 0x90, 0xea, 0x13, 0x80, 0xfa, + 0x16, 0xa5, 0xff, 0x8d, 0xc4, 0xc5, 0x4b, 0x21, 0x74, 0x06, 0x50, 0xf2, + 0x4a, 0xfc, 0x41, 0x20, 0x90, 0x35, 0x52, 0xb0 + }; + uint8_t m[1005]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + + (void)memset(m, 0x55, sizeof(m)); + + (void)tc_sha256_init(&s); + tc_sha256_update(&s, m, sizeof(m)); + (void)tc_sha256_final(digest, &s); + + result = check_result(11, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_12(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #12:\n"); + + const uint8_t expected[32] = { + 0xd2, 0x97, 0x51, 0xf2, 0x64, 0x9b, 0x32, 0xff, 0x57, 0x2b, 0x5e, 0x0a, + 0x9f, 0x54, 0x1e, 0xa6, 0x60, 0xa5, 0x0f, 0x94, 0xff, 0x0b, 0xee, 0xdf, + 0xb0, 0xb6, 0x92, 0xb9, 0x24, 0xcc, 0x80, 0x25 + }; + uint8_t m[1000]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + unsigned int i; + + (void)memset(m, 0x00, sizeof(m)); + + (void)tc_sha256_init(&s); + for (i = 0; i < 1000; ++i) { + tc_sha256_update(&s, m, sizeof(m)); + } + (void)tc_sha256_final(digest, &s); + + result = check_result(12, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_13(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #13:\n"); + const uint8_t expected[32] = { + 0x15, 0xa1, 0x86, 0x8c, 0x12, 0xcc, 0x53, 0x95, 0x1e, 0x18, 0x23, 0x44, + 0x27, 0x74, 0x47, 0xcd, 0x09, 0x79, 0x53, 0x6b, 0xad, 0xcc, 0x51, 0x2a, + 0xd2, 0x4c, 0x67, 0xe9, 0xb2, 0xd4, 0xf3, 0xdd + }; + uint8_t m[32768]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + unsigned int i; + + (void)memset(m, 0x5a, sizeof(m)); + + (void)tc_sha256_init(&s); + for (i = 0; i < 16384; ++i) { + tc_sha256_update(&s, m, sizeof(m)); + } + (void)tc_sha256_final(digest, &s); + + result = check_result(13, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +unsigned int test_14(void) +{ + unsigned int result = TC_PASS; + TC_PRINT("SHA256 test #14:\n"); + const uint8_t expected[32] = { + 0x46, 0x1c, 0x19, 0xa9, 0x3b, 0xd4, 0x34, 0x4f, 0x92, 0x15, 0xf5, 0xec, + 0x64, 0x35, 0x70, 0x90, 0x34, 0x2b, 0xc6, 0x6b, 0x15, 0xa1, 0x48, 0x31, + 0x7d, 0x27, 0x6e, 0x31, 0xcb, 0xc2, 0x0b, 0x53 + }; + uint8_t m[32768]; + uint8_t digest[32]; + struct tc_sha256_state_struct s; + unsigned int i; + + (void)memset(m, 0x00, sizeof(m)); + + (void) tc_sha256_init(&s); + for (i = 0; i < 33280; ++i) { + tc_sha256_update(&s, m, sizeof(m)); + } + (void) tc_sha256_final(digest, &s); + + result = check_result(14, expected, sizeof(expected), + digest, sizeof(digest)); + TC_END_RESULT(result); + return result; +} + +/* + * Main task to test AES + */ + +int main(void) +{ + unsigned int result = TC_PASS; + TC_START("Performing SHA256 tests (NIST tests vectors):"); + + result = test_1(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #1 failed.\n"); + goto exitTest; + } + result = test_2(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #2 failed.\n"); + goto exitTest; + } + result = test_3(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #3 failed.\n"); + goto exitTest; + } + result = test_4(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #4 failed.\n"); + goto exitTest; + } + result = test_5(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #5 failed.\n"); + goto exitTest; + } + result = test_6(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #6 failed.\n"); + goto exitTest; + } + result = test_7(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #7 failed.\n"); + goto exitTest; + } + result = test_8(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #8 failed.\n"); + goto exitTest; + } + result = test_9(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #9 failed.\n"); + goto exitTest; + } + result = test_10(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #10 failed.\n"); + goto exitTest; + } + result = test_11(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #11 failed.\n"); + goto exitTest; + } + result = test_12(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #12 failed.\n"); + goto exitTest; + } + /* memory and computation intensive test cases: */ + result = test_13(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #13 failed.\n"); + goto exitTest; + } + result = test_14(); + if (result == TC_FAIL) { + /* terminate test */ + TC_ERROR("SHA256 test #14 failed.\n"); + goto exitTest; + } + + TC_PRINT("All SHA256 tests succeeded!\n"); + +exitTest: + TC_END_RESULT(result); + TC_END_REPORT(result); +} + diff --git a/u_async.c b/u_async.c new file mode 100644 index 00000000..30b7f2de --- /dev/null +++ b/u_async.c @@ -0,0 +1,276 @@ +// uasync.c + +#include "u_async.h" +#include +#include +#include +#include +#include + +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 // Assume standard size; adjust if needed for your platform +#endif + +// Timeout node +struct timeout_node { + struct timeval expire_time; + void* arg; + timeout_callback_t callback; + struct timeout_node* next; + struct timeout_node* prev; // Doubly linked for easier removal +}; + +// Socket node +struct socket_node { + int fd; + socket_callback_t read_cbk; + socket_callback_t write_cbk; + socket_callback_t except_cbk; + void* user_data; + struct socket_node* next; +}; + +// Global state +static struct timeout_node* timeout_head = NULL; // Sorted by expire_time, earliest first +static struct socket_node* socket_head = NULL; +static int max_fd = -1; + +// New: Persistent master fd_sets, updated only on add/remove +static fd_set master_readfds; +static fd_set master_writefds; +static fd_set master_exceptfds; + +// New: FD-to-node map for faster post-select lookup (addresses point 2) +static struct socket_node* fd_to_node[FD_SETSIZE]; + +// Helper to get current time +static void get_current_time(struct timeval* tv) { + gettimeofday(tv, NULL); +} + +// Helper to compare times: returns 1 if a > b, 0 if equal, -1 if a < b +static int timeval_cmp(const struct timeval* a, const struct timeval* b) { + if (a->tv_sec > b->tv_sec) return 1; + if (a->tv_sec < b->tv_sec) return -1; + if (a->tv_usec > b->tv_usec) return 1; + if (a->tv_usec < b->tv_usec) return -1; + return 0; +} + +// Helper to add timeval: tv += dt (timebase units) +static void timeval_add_tb(struct timeval* tv, int dt) { + tv->tv_usec += (dt % 10000) * 100; + tv->tv_sec += dt / 10000 + tv->tv_usec / 1000000; + tv->tv_usec %= 1000000; +} + +// Insert timeout into sorted list +static struct timeout_node* insert_timeout(struct timeout_node* new_node) { + if (!timeout_head || timeval_cmp(&new_node->expire_time, &timeout_head->expire_time) < 0) { + new_node->next = timeout_head; + new_node->prev = NULL; + if (timeout_head) timeout_head->prev = new_node; + timeout_head = new_node; + return new_node; + } + + struct timeout_node* cur = timeout_head; + while (cur->next && timeval_cmp(&new_node->expire_time, &cur->next->expire_time) >= 0) { + cur = cur->next; + } + new_node->next = cur->next; + new_node->prev = cur; + if (cur->next) cur->next->prev = new_node; + cur->next = new_node; + return new_node; +} + +// Process expired timeouts +static void process_timeouts() { + struct timeval now; + get_current_time(&now); + + while (timeout_head && timeval_cmp(&timeout_head->expire_time, &now) <= 0) { + struct timeout_node* node = timeout_head; + timeout_head = node->next; + if (timeout_head) timeout_head->prev = NULL; + + if (node->callback) node->callback(node->arg); + free(node); + } +} + +// Compute time to next timeout +static void get_next_timeout(struct timeval* tv) { + struct timeval now; + get_current_time(&now); + + if (!timeout_head) { + tv->tv_sec = 0; + tv->tv_usec = 0; // No timeout, but select can handle NULL + return; + } + + *tv = timeout_head->expire_time; + if (timeval_cmp(tv, &now) <= 0) { + tv->tv_sec = 0; + tv->tv_usec = 0; + return; + } + + tv->tv_sec -= now.tv_sec; + tv->tv_usec -= now.tv_usec; + if (tv->tv_usec < 0) { + tv->tv_sec--; + tv->tv_usec += 1000000; + } +} + +void uasync_init(void) { + FD_ZERO(&master_readfds); + FD_ZERO(&master_writefds); + FD_ZERO(&master_exceptfds); + memset(fd_to_node, 0, sizeof(fd_to_node)); // Init map to NULL +} + +void* uasync_set_timeout(int timeout, void* arg, timeout_callback_t callback) { + if (timeout < 0 || !callback) return NULL; + + struct timeout_node* node = malloc(sizeof(struct timeout_node)); + if (!node) return NULL; + + get_current_time(&node->expire_time); + timeval_add_tb(&node->expire_time, timeout); + node->arg = arg; + node->callback = callback; + node->next = NULL; + node->prev = NULL; + + return insert_timeout(node); +} + +err_t uasync_cancel_timeout(void* t_id) { + if (!t_id) return ERR_FAIL; + + struct timeout_node* node = (struct timeout_node*)t_id; + if (node->prev) { + node->prev->next = node->next; + } else { + timeout_head = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } + free(node); + return ERR_OK; +} + +void* uasync_add_socket(int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_data) { + if (fd < 0 || fd >= FD_SETSIZE) return NULL; // Add bounds check for map + + struct socket_node* node = malloc(sizeof(struct socket_node)); + if (!node) return NULL; + + node->fd = fd; + node->read_cbk = read_cbk; + node->write_cbk = write_cbk; + node->except_cbk = except_cbk; + node->user_data = user_data; + node->next = socket_head; + socket_head = node; + + // Update masters (point 1) + if (read_cbk) FD_SET(fd, &master_readfds); + if (write_cbk) FD_SET(fd, &master_writefds); + if (except_cbk) FD_SET(fd, &master_exceptfds); + + // Update map (point 2) + fd_to_node[fd] = node; + + if (fd > max_fd) max_fd = fd; + + return node; +} + +err_t uasync_remove_socket(void* s_id) { + if (!s_id) return ERR_FAIL; + + struct socket_node* node = (struct socket_node*)s_id; + struct socket_node* cur = socket_head; + struct socket_node* prev = NULL; + + while (cur) { + if (cur == node) { + if (prev) { + prev->next = cur->next; + } else { + socket_head = cur->next; + } + + // Update masters (point 1) + if (node->read_cbk) FD_CLR(node->fd, &master_readfds); + if (node->write_cbk) FD_CLR(node->fd, &master_writefds); + if (node->except_cbk) FD_CLR(node->fd, &master_exceptfds); + + // Update map (point 2) + fd_to_node[node->fd] = NULL; + + free(cur); + + // Update max_fd (simple rescan; optimize if needed by checking if removed == max_fd) + max_fd = -1; + cur = socket_head; + while (cur) { + if (cur->fd > max_fd) max_fd = cur->fd; + cur = cur->next; + } + return ERR_OK; + } + prev = cur; + cur = cur->next; + } + return ERR_FAIL; +} + +void uasync_mainloop(void) { + while (1) { + // Process timeouts first + process_timeouts(); + + // Prepare select with copies of masters (point 1: no loop/FD_ZERO here) + fd_set readfds = master_readfds; + fd_set writefds = master_writefds; + fd_set exceptfds = master_exceptfds; + + struct timeval tv; + get_next_timeout(&tv); + struct timeval* ptv = (tv.tv_sec == 0 && tv.tv_usec == 0 && !timeout_head) ? NULL : &tv; + + int nfds = select(max_fd + 1, &readfds, &writefds, &exceptfds, ptv); + if (nfds < 0) { + if (errno == EINTR) continue; + perror("select"); + break; + } + + // Process sockets with faster dispatch (point 2: loop only up to max_fd, but use map for O(1) node lookup) + // This is O(max_fd) worst-case, but in practice fast; only checks if FD_ISSET. + for (int fd = 0; nfds > 0 && fd <= max_fd; fd++) { + struct socket_node* node = fd_to_node[fd]; + if (!node) continue; // Skip unmapped fds + + if (node->except_cbk && FD_ISSET(fd, &exceptfds)) { + node->except_cbk(fd, node->user_data); + nfds--; + } + if (node->read_cbk && FD_ISSET(fd, &readfds)) { + node->read_cbk(fd, node->user_data); + nfds--; + } + if (node->write_cbk && FD_ISSET(fd, &writefds)) { + node->write_cbk(fd, node->user_data); + nfds--; + } + } + } +} diff --git a/u_async.h b/u_async.h new file mode 100644 index 00000000..e763b96c --- /dev/null +++ b/u_async.h @@ -0,0 +1,33 @@ +// uasync.h + +// модуль асинхронных операций. добавляем сокеты и таймауты и mainloop их обслуживает. + +#ifndef UASYNC_H +#define UASYNC_H + +#include +#include + +typedef void (*timeout_callback_t)(void* user_arg);// передаёт user_arg из uasync_set_timeout +typedef void (*socket_callback_t)(int fd, void* user_arg);// передаёт user_arg из uasync_add_socket +// user_arg полезен если нужно передать управляющую структуру. Ее можно выделить в памяти и в ней хранить всё что надо. т.е. при set_timeout передаём и получаем ее в callback-е + + +// Error type +typedef int err_t; +#define ERR_OK 0 +#define ERR_FAIL -1 + +// API functions +void uasync_init(void); +void uasync_mainloop(void);// бесконечный цикл, __noreturn + +// Timeouts, timebase = 0.1 mS +void* uasync_set_timeout(int timeout_tb, void* user_arg, timeout_callback_t callback); +err_t uasync_cancel_timeout(void* t_id); + +// Sockets +void* uasync_add_socket(int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_arg); +err_t uasync_remove_socket(void* s_id); + +#endif // UASYNC_H
  • ipOWeN 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