2 * Copyright (C) 2018,2020 Vitaly Chikunov <vt@altlinux.org> All Rights Reserved.
4 * Contents licensed under the terms of the OpenSSL license
5 * See https://www.openssl.org/source/license.html for details
8 #include <openssl/engine.h>
9 #include <openssl/evp.h>
10 #include <openssl/rand.h>
11 #include <openssl/err.h>
12 #include <openssl/asn1.h>
14 #ifndef EVP_MD_CTRL_SET_KEY
15 # include "gost_lcl.h"
20 ERR_print_errors_fp(stderr); \
21 OpenSSLDie(__FILE__, __LINE__, #e); \
24 #define cRED "\033[1;31m"
25 #define cDRED "\033[0;31m"
26 #define cGREEN "\033[1;32m"
27 #define cDGREEN "\033[0;32m"
28 #define cBLUE "\033[1;34m"
29 #define cDBLUE "\033[0;34m"
30 #define cNORM "\033[m"
31 #define TEST_ASSERT(e) {if ((test = (e))) \
32 printf(cRED " Test FAILED" cNORM "\n"); \
34 printf(cGREEN " Test passed" cNORM "\n");}
36 static void hexdump(const void *ptr, size_t len)
38 const unsigned char *p = ptr;
41 for (i = 0; i < len; i += j) {
42 for (j = 0; j < 16 && i + j < len; j++)
43 printf("%s%02x", j? "" : " ", p[i + j]);
51 static int test_contexts_cipher(const char *name, const int enc, int acpkm)
53 EVP_CIPHER_CTX *ctx, *save;
54 unsigned char pt[TEST_SIZE] = {1};
55 unsigned char b[TEST_SIZE]; /* base output */
56 unsigned char c[TEST_SIZE]; /* cloned output */
57 unsigned char K[32] = {1};
58 unsigned char iv[16] = {1};
60 int ret = 0, test = 0;
64 T((type = (EVP_CIPHER *)EVP_get_cipherbyname(name))
65 || (type = EVP_CIPHER_fetch(NULL, name, NULL)));
68 printf(cBLUE "%s test for %s" cNORM "\n",
69 enc ? "Encryption" : "Decryption", name);
71 /* produce base encryption */
72 ctx = EVP_CIPHER_CTX_new();
74 T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
76 if (EVP_CIPHER_get0_provider(type) != NULL) {
77 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
78 size_t v = (size_t)acpkm;
80 params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
81 T(EVP_CIPHER_CTX_set_params(ctx, params));
83 T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
86 T(EVP_CIPHER_CTX_set_padding(ctx, 0));
87 T(EVP_CipherUpdate(ctx, b, &outlen, pt, sizeof(b)));
88 T(EVP_CipherFinal_ex(ctx, b + outlen, &tmplen));
91 EVP_CIPHER_CTX_reset(ctx);
92 EVP_CIPHER_CTX_reset(ctx); /* double call is intentional */
93 T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
94 T(EVP_CIPHER_CTX_set_padding(ctx, 0));
96 if (EVP_CIPHER_get0_provider(type) != NULL) {
97 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
98 size_t v = (size_t)acpkm;
100 params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
101 T(EVP_CIPHER_CTX_set_params(ctx, params));
103 T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
108 printf(" cloned contexts: ");
110 memset(c, 0, sizeof(c));
111 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
112 EVP_CIPHER_CTX *copy = EVP_CIPHER_CTX_new();
114 T(EVP_CIPHER_CTX_copy(copy, ctx));
115 if (save != ctx) /* else original context */
116 EVP_CIPHER_CTX_free(ctx);
119 T(EVP_CipherUpdate(ctx, c + STEP_SIZE * i, &outlen,
120 pt + STEP_SIZE * i, STEP_SIZE));
123 outlen = i * STEP_SIZE;
124 T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
125 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
126 EVP_CIPHER_CTX_free(ctx);
128 printf(" b[%d] = ", outlen);
130 printf(" c[%d] = ", outlen);
135 /* resume original context */
136 printf(" base context: ");
137 memset(c, 0, sizeof(c));
138 T(EVP_CipherUpdate(save, c, &outlen, pt, sizeof(c)));
139 T(EVP_CipherFinal_ex(save, c + outlen, &tmplen));
140 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
141 EVP_CIPHER_CTX_cleanup(save); /* multiple calls are intentional */
142 EVP_CIPHER_CTX_cleanup(save);
143 EVP_CIPHER_CTX_free(save);
144 EVP_CIPHER_free(type);
146 printf(" b[%d] = ", outlen);
148 printf(" c[%d] = ", outlen);
156 static int test_contexts_digest_or_legacy_mac(const EVP_MD *type, int mac)
158 int ret = 0, test = 0;
159 unsigned char K[32] = {1};
161 /* produce base digest */
162 EVP_MD_CTX *ctx, *save;
163 unsigned char pt[TEST_SIZE] = {1};
164 unsigned char b[EVP_MAX_MD_SIZE] = {0};
165 unsigned char c[EVP_MAX_MD_SIZE];
166 unsigned int outlen, tmplen;
168 /* Simply digest whole input. */
169 T(ctx = EVP_MD_CTX_new());
170 T(EVP_DigestInit_ex(ctx, type, NULL));
172 T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
173 T(EVP_DigestUpdate(ctx, pt, sizeof(pt)));
174 T(EVP_DigestFinal_ex(ctx, b, &tmplen));
175 save = ctx; /* will be not freed while cloning */
178 EVP_MD_CTX_reset(ctx); /* test double reset */
179 EVP_MD_CTX_reset(ctx);
180 T(EVP_DigestInit_ex(ctx, type, NULL));
182 T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
183 printf(" cloned contexts: ");
184 memset(c, 0, sizeof(c));
186 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
187 /* Clone and continue digesting next part of input. */
189 T(copy = EVP_MD_CTX_new());
190 T(EVP_MD_CTX_copy_ex(copy, ctx));
194 EVP_MD_CTX_free(ctx);
197 T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE));
199 outlen = i * STEP_SIZE;
200 T(EVP_DigestFinal_ex(ctx, c, &tmplen));
201 /* Should be same as the simple digest. */
202 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
203 EVP_MD_CTX_free(ctx);
205 printf(" b[%d] = ", outlen);
207 printf(" c[%d] = ", outlen);
212 /* Resume original context, what if it's damaged? */
213 printf(" base context: ");
214 memset(c, 0, sizeof(c));
215 T(EVP_DigestUpdate(save, pt, sizeof(pt)));
216 T(EVP_DigestFinal_ex(save, c, &tmplen));
217 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
218 EVP_MD_CTX_free(save);
220 printf(" b[%d] = ", outlen);
222 printf(" c[%d] = ", outlen);
230 static int test_contexts_digest(const char *name)
234 T((type = (EVP_MD *)EVP_get_digestbyname(name))
235 || (type = EVP_MD_fetch(NULL, name, NULL)));
238 printf(cBLUE "Digest test for %s" cNORM "\n", name);
239 int ret = test_contexts_digest_or_legacy_mac(type, 0);
244 static int test_contexts_mac(const char *name)
246 int ret = 0, test = 0;
247 unsigned char K[32] = {1};
248 const EVP_MD *type = EVP_get_digestbyname(name);
252 printf(cBLUE "Mac via EVP_MD test for %s" cNORM "\n", name);
253 return test_contexts_digest_or_legacy_mac(type, 1);
256 T(mac = EVP_MAC_fetch(NULL, name, NULL));
257 printf(cBLUE "Mac test for %s" cNORM "\n", name);
259 /* produce base mac */
261 unsigned char pt[TEST_SIZE] = {1};
262 unsigned char b[EVP_MAX_MD_SIZE] = {0};
263 unsigned char c[EVP_MAX_MD_SIZE] = {0};
264 size_t outlen, tmplen;
266 /* Simply mac whole input. */
267 T(ctx = EVP_MAC_CTX_new(mac));
268 T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
269 T(EVP_MAC_update(ctx, pt, sizeof(pt)));
270 T(EVP_MAC_final(ctx, b, &tmplen, sizeof(b)));
271 EVP_MAC_CTX_free(ctx);
273 /* Mac with rolling input. */
274 printf(" cloned contexts: ");
275 T(ctx = EVP_MAC_CTX_new(mac));
276 T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
278 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
279 T(EVP_MAC_update(ctx, pt + STEP_SIZE * i, STEP_SIZE));
281 outlen = i * STEP_SIZE;
282 T(EVP_MAC_final(ctx, c, &tmplen, sizeof(c)));
283 EVP_MAC_CTX_free(ctx);
286 /* Rolling mac should give the same result as the simple mac. */
287 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
290 printf(" b[%d] = ", (int)outlen);
292 printf(" c[%d] = ", (int)outlen);
300 static struct testcase_cipher {
303 } testcases_ciphers[] = {
304 { SN_id_Gost28147_89, },
306 { SN_gost89_cnt_12, },
308 { SN_grasshopper_ecb, },
309 { SN_grasshopper_cbc, },
310 { SN_grasshopper_cfb, },
311 { SN_grasshopper_ofb, },
312 { SN_grasshopper_ctr, },
315 { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 256 / 8 },
319 static struct testcase_digest {
322 } testcases_digests[] = {
323 { SN_id_GostR3411_94, },
324 { SN_id_Gost28147_89_MAC, 1 },
325 { SN_id_GostR3411_2012_256, },
326 { SN_id_GostR3411_2012_512, },
327 { SN_gost_mac_12, 1 },
329 { SN_grasshopper_mac, 1 },
330 { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 1 },
333 int main(int argc, char **argv)
337 OPENSSL_add_all_algorithms_conf();
339 const struct testcase_cipher *tc;
340 for (tc = testcases_ciphers; tc->name; tc++) {
341 ret |= test_contexts_cipher(tc->name, 1, tc->acpkm);
342 ret |= test_contexts_cipher(tc->name, 0, tc->acpkm);
344 const struct testcase_digest *td;
345 for (td = testcases_digests; td->name; td++) {
347 ret |= test_contexts_mac(td->name);
349 ret |= test_contexts_digest(td->name);
353 printf(cDRED "= Some tests FAILED!" cNORM "\n");
355 printf(cDGREEN "= All tests passed!" cNORM "\n");