1/* $OpenBSD: whirlpool_test.c,v 1.3 2024/04/09 18:12:11 tb Exp $ */ 2/* 3 * Copyright (c) 2024 Joshua Sing <joshua@joshuasing.dev> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <openssl/evp.h> 19#include <openssl/whrlpool.h> 20 21#include <stdint.h> 22#include <string.h> 23 24struct whirlpool_test { 25 const uint8_t in[128]; 26 const size_t in_len; 27 const uint8_t out[EVP_MAX_MD_SIZE]; 28}; 29 30static const struct whirlpool_test whirlpool_tests[] = { 31 { 32 .in = "", 33 .in_len = 0, 34 .out = { 35 0x19, 0xfa, 0x61, 0xd7, 0x55, 0x22, 0xa4, 0x66, 36 0x9b, 0x44, 0xe3, 0x9c, 0x1d, 0x2e, 0x17, 0x26, 37 0xc5, 0x30, 0x23, 0x21, 0x30, 0xd4, 0x07, 0xf8, 38 0x9a, 0xfe, 0xe0, 0x96, 0x49, 0x97, 0xf7, 0xa7, 39 0x3e, 0x83, 0xbe, 0x69, 0x8b, 0x28, 0x8f, 0xeb, 40 0xcf, 0x88, 0xe3, 0xe0, 0x3c, 0x4f, 0x07, 0x57, 41 0xea, 0x89, 0x64, 0xe5, 0x9b, 0x63, 0xd9, 0x37, 42 0x08, 0xb1, 0x38, 0xcc, 0x42, 0xa6, 0x6e, 0xb3, 43 }, 44 }, 45 { 46 .in = "a", 47 .in_len = 1, 48 .out = { 49 0x8a, 0xca, 0x26, 0x02, 0x79, 0x2a, 0xec, 0x6f, 50 0x11, 0xa6, 0x72, 0x06, 0x53, 0x1f, 0xb7, 0xd7, 51 0xf0, 0xdf, 0xf5, 0x94, 0x13, 0x14, 0x5e, 0x69, 52 0x73, 0xc4, 0x50, 0x01, 0xd0, 0x08, 0x7b, 0x42, 53 0xd1, 0x1b, 0xc6, 0x45, 0x41, 0x3a, 0xef, 0xf6, 54 0x3a, 0x42, 0x39, 0x1a, 0x39, 0x14, 0x5a, 0x59, 55 0x1a, 0x92, 0x20, 0x0d, 0x56, 0x01, 0x95, 0xe5, 56 0x3b, 0x47, 0x85, 0x84, 0xfd, 0xae, 0x23, 0x1a, 57 }, 58 }, 59 { 60 .in = "abc", 61 .in_len = 3, 62 .out = { 63 0x4e, 0x24, 0x48, 0xa4, 0xc6, 0xf4, 0x86, 0xbb, 64 0x16, 0xb6, 0x56, 0x2c, 0x73, 0xb4, 0x02, 0x0b, 65 0xf3, 0x04, 0x3e, 0x3a, 0x73, 0x1b, 0xce, 0x72, 66 0x1a, 0xe1, 0xb3, 0x03, 0xd9, 0x7e, 0x6d, 0x4c, 67 0x71, 0x81, 0xee, 0xbd, 0xb6, 0xc5, 0x7e, 0x27, 68 0x7d, 0x0e, 0x34, 0x95, 0x71, 0x14, 0xcb, 0xd6, 69 0xc7, 0x97, 0xfc, 0x9d, 0x95, 0xd8, 0xb5, 0x82, 70 0xd2, 0x25, 0x29, 0x20, 0x76, 0xd4, 0xee, 0xf5, 71 }, 72 }, 73 { 74 .in = "message digest", 75 .in_len = 14, 76 .out = { 77 0x37, 0x8c, 0x84, 0xa4, 0x12, 0x6e, 0x2d, 0xc6, 78 0xe5, 0x6d, 0xcc, 0x74, 0x58, 0x37, 0x7a, 0xac, 79 0x83, 0x8d, 0x00, 0x03, 0x22, 0x30, 0xf5, 0x3c, 80 0xe1, 0xf5, 0x70, 0x0c, 0x0f, 0xfb, 0x4d, 0x3b, 81 0x84, 0x21, 0x55, 0x76, 0x59, 0xef, 0x55, 0xc1, 82 0x06, 0xb4, 0xb5, 0x2a, 0xc5, 0xa4, 0xaa, 0xa6, 83 0x92, 0xed, 0x92, 0x00, 0x52, 0x83, 0x8f, 0x33, 84 0x62, 0xe8, 0x6d, 0xbd, 0x37, 0xa8, 0x90, 0x3e, 85 }, 86 }, 87 { 88 .in = "abcdefghijklmnopqrstuvwxyz", 89 .in_len = 26, 90 .out = { 91 0xf1, 0xd7, 0x54, 0x66, 0x26, 0x36, 0xff, 0xe9, 92 0x2c, 0x82, 0xeb, 0xb9, 0x21, 0x2a, 0x48, 0x4a, 93 0x8d, 0x38, 0x63, 0x1e, 0xad, 0x42, 0x38, 0xf5, 94 0x44, 0x2e, 0xe1, 0x3b, 0x80, 0x54, 0xe4, 0x1b, 95 0x08, 0xbf, 0x2a, 0x92, 0x51, 0xc3, 0x0b, 0x6a, 96 0x0b, 0x8a, 0xae, 0x86, 0x17, 0x7a, 0xb4, 0xa6, 97 0xf6, 0x8f, 0x67, 0x3e, 0x72, 0x07, 0x86, 0x5d, 98 0x5d, 0x98, 0x19, 0xa3, 0xdb, 0xa4, 0xeb, 0x3b, 99 }, 100 }, 101 { 102 .in = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 103 .in_len = 62, 104 .out = { 105 0xdc, 0x37, 0xe0, 0x08, 0xcf, 0x9e, 0xe6, 0x9b, 106 0xf1, 0x1f, 0x00, 0xed, 0x9a, 0xba, 0x26, 0x90, 107 0x1d, 0xd7, 0xc2, 0x8c, 0xde, 0xc0, 0x66, 0xcc, 108 0x6a, 0xf4, 0x2e, 0x40, 0xf8, 0x2f, 0x3a, 0x1e, 109 0x08, 0xeb, 0xa2, 0x66, 0x29, 0x12, 0x9d, 0x8f, 110 0xb7, 0xcb, 0x57, 0x21, 0x1b, 0x92, 0x81, 0xa6, 111 0x55, 0x17, 0xcc, 0x87, 0x9d, 0x7b, 0x96, 0x21, 112 0x42, 0xc6, 0x5f, 0x5a, 0x7a, 0xf0, 0x14, 0x67, 113 }, 114 }, 115 { 116 .in = "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 117 .in_len = 80, 118 .out = { 119 0x46, 0x6e, 0xf1, 0x8b, 0xab, 0xb0, 0x15, 0x4d, 120 0x25, 0xb9, 0xd3, 0x8a, 0x64, 0x14, 0xf5, 0xc0, 121 0x87, 0x84, 0x37, 0x2b, 0xcc, 0xb2, 0x04, 0xd6, 122 0x54, 0x9c, 0x4a, 0xfa, 0xdb, 0x60, 0x14, 0x29, 123 0x4d, 0x5b, 0xd8, 0xdf, 0x2a, 0x6c, 0x44, 0xe5, 124 0x38, 0xcd, 0x04, 0x7b, 0x26, 0x81, 0xa5, 0x1a, 125 0x2c, 0x60, 0x48, 0x1e, 0x88, 0xc5, 0xa2, 0x0b, 126 0x2c, 0X2A, 0X80, 0XCF, 0X3A, 0X9A, 0X08, 0X3B, 127 }, 128 }, 129 { 130 .in = "abcdbcdecdefdefgefghfghighijhijk", 131 .in_len = 32, 132 .out = { 133 0x2a, 0x98, 0x7e, 0xa4, 0x0f, 0x91, 0x70, 0x61, 134 0xf5, 0xd6, 0xf0, 0xa0, 0xe4, 0x64, 0x4f, 0x48, 135 0x8a, 0x7a, 0x5a, 0x52, 0xde, 0xee, 0x65, 0x62, 136 0x07, 0xc5, 0x62, 0xf9, 0x88, 0xe9, 0x5c, 0x69, 137 0x16, 0xbd, 0xc8, 0x03, 0x1b, 0xc5, 0xbe, 0x1b, 138 0x7b, 0x94, 0x76, 0x39, 0xfe, 0x05, 0x0b, 0x56, 139 0x93, 0x9b, 0xaa, 0xa0, 0xad, 0xff, 0x9a, 0xe6, 140 0x74, 0x5b, 0x7b, 0x18, 0x1c, 0x3b, 0xe3, 0xfd, 141 }, 142 }, 143}; 144 145#define N_WHIRLPOOL_TESTS (sizeof(whirlpool_tests) / sizeof(whirlpool_tests[0])) 146 147static int 148whirlpool_test(void) 149{ 150 const struct whirlpool_test *wt; 151 EVP_MD_CTX *md_ctx = NULL; 152 const EVP_MD *md = EVP_whirlpool(); 153 uint8_t out[EVP_MAX_MD_SIZE]; 154 size_t i, l, in_len; 155 int failed = 1; 156 157 if ((md_ctx = EVP_MD_CTX_new()) == NULL) { 158 fprintf(stderr, "FAIL: EVP_MD_CTX_new() failed\n"); 159 goto failed; 160 } 161 162 for (i = 0; i < N_WHIRLPOOL_TESTS; i++) { 163 wt = &whirlpool_tests[i]; 164 165 /* Digest */ 166 memset(out, 0, sizeof(out)); 167 WHIRLPOOL(wt->in, wt->in_len, out); 168 if (memcmp(wt->out, out, WHIRLPOOL_DIGEST_LENGTH) != 0) { 169 fprintf(stderr, "FAIL (%zu): digest mismatch\n", i); 170 goto failed; 171 } 172 173 /* EVP single-shot digest */ 174 memset(out, 0, sizeof(out)); 175 if (!EVP_Digest(wt->in, wt->in_len, out, NULL, md, NULL)) { 176 fprintf(stderr, "FAIL (%zu): EVP_Digest failed\n", i); 177 goto failed; 178 } 179 180 if (memcmp(wt->out, out, WHIRLPOOL_DIGEST_LENGTH) != 0) { 181 fprintf(stderr, 182 "FAIL (%zu): EVP single-shot mismatch\n", i); 183 goto failed; 184 } 185 186 /* EVP digest */ 187 memset(out, 0, sizeof(out)); 188 if (!EVP_DigestInit_ex(md_ctx, md, NULL)) { 189 fprintf(stderr, 190 "FAIL (%zu): EVP_DigestInit_ex failed\n", i); 191 goto failed; 192 } 193 194 for (l = 0; l < wt->in_len;) { 195 in_len = 1; 196 if (wt->in_len > 1) 197 in_len = arc4random_uniform(wt->in_len / 2); 198 if (in_len < 1) 199 in_len = 1; 200 if (in_len > wt->in_len - l) 201 in_len = wt->in_len - l; 202 203 if (!EVP_DigestUpdate(md_ctx, wt->in + l, in_len)) { 204 fprintf(stderr, 205 "FAIL(%zu, %zu): EVP_DigestUpdate failed\n", 206 i, l); 207 goto failed; 208 } 209 210 l += in_len; 211 } 212 213 if (!EVP_DigestFinal_ex(md_ctx, out, NULL)) { 214 fprintf(stderr, 215 "FAIL (%zu): EVP_DigestFinal_ex failed\n", 216 i); 217 goto failed; 218 } 219 220 if (memcmp(wt->out, out, WHIRLPOOL_DIGEST_LENGTH) != 0) { 221 fprintf(stderr, "FAIL (%zu): EVP mismatch\n", i); 222 goto failed; 223 } 224 } 225 226 failed = 0; 227 228 failed: 229 EVP_MD_CTX_free(md_ctx); 230 231 return failed; 232} 233 234int 235main(int argc, char **argv) 236{ 237 int failed = 0; 238 239 failed |= whirlpool_test(); 240 241 return failed; 242} 243