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"
18 #define T(e) if (!(e)) {\
19 ERR_print_errors_fp(stderr);\
20 OpenSSLDie(__FILE__, __LINE__, #e);\
23 #define cRED "\033[1;31m"
24 #define cDRED "\033[0;31m"
25 #define cGREEN "\033[1;32m"
26 #define cDGREEN "\033[0;32m"
27 #define cBLUE "\033[1;34m"
28 #define cDBLUE "\033[0;34m"
29 #define cNORM "\033[m"
30 #define TEST_ASSERT(e) {if ((test = (e))) \
31 printf(cRED " Test FAILED" cNORM "\n"); \
33 printf(cGREEN " Test passed" cNORM "\n");}
35 static void hexdump(const void *ptr, size_t len)
37 const unsigned char *p = ptr;
40 for (i = 0; i < len; i += j) {
41 for (j = 0; j < 16 && i + j < len; j++)
42 printf("%s%02x", j? "" : " ", p[i + j]);
50 static int test_contexts_cipher(const char *name, const int enc, int acpkm)
52 EVP_CIPHER_CTX *ctx, *save;
53 unsigned char pt[TEST_SIZE] = {1};
54 unsigned char b[TEST_SIZE]; /* base output */
55 unsigned char c[TEST_SIZE]; /* cloned output */
56 unsigned char K[32] = {1};
57 unsigned char iv[16] = {1};
59 int ret = 0, test = 0;
63 T((type = (EVP_CIPHER *)EVP_get_cipherbyname(name))
64 || (type = EVP_CIPHER_fetch(NULL, name, NULL)));
67 printf(cBLUE "%s test for %s" cNORM "\n",
68 enc ? "Encryption" : "Decryption", name);
70 /* produce base encryption */
71 ctx = EVP_CIPHER_CTX_new();
73 T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
75 if (EVP_CIPHER_get0_provider(type) != NULL) {
76 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
77 size_t v = (size_t)acpkm;
79 params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
80 T(EVP_CIPHER_CTX_set_params(ctx, params));
82 T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
85 T(EVP_CIPHER_CTX_set_padding(ctx, 0));
86 T(EVP_CipherUpdate(ctx, b, &outlen, pt, sizeof(b)));
87 T(EVP_CipherFinal_ex(ctx, b + outlen, &tmplen));
90 EVP_CIPHER_CTX_reset(ctx);
91 EVP_CIPHER_CTX_reset(ctx); /* double call is intentional */
92 T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
93 T(EVP_CIPHER_CTX_set_padding(ctx, 0));
95 if (EVP_CIPHER_get0_provider(type) != NULL) {
96 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
97 size_t v = (size_t)acpkm;
99 params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
100 T(EVP_CIPHER_CTX_set_params(ctx, params));
102 T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
107 printf(" cloned contexts: ");
109 memset(c, 0, sizeof(c));
110 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
111 EVP_CIPHER_CTX *copy = EVP_CIPHER_CTX_new();
113 T(EVP_CIPHER_CTX_copy(copy, ctx));
114 if (save != ctx) /* else original context */
115 EVP_CIPHER_CTX_free(ctx);
118 T(EVP_CipherUpdate(ctx, c + STEP_SIZE * i, &outlen,
119 pt + STEP_SIZE * i, STEP_SIZE));
122 outlen = i * STEP_SIZE;
123 T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
124 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
125 EVP_CIPHER_CTX_free(ctx);
127 printf(" b[%d] = ", outlen);
129 printf(" c[%d] = ", outlen);
134 /* resume original context */
135 printf(" base context: ");
136 memset(c, 0, sizeof(c));
137 T(EVP_CipherUpdate(save, c, &outlen, pt, sizeof(c)));
138 T(EVP_CipherFinal_ex(save, c + outlen, &tmplen));
139 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
140 EVP_CIPHER_CTX_cleanup(save); /* multiple calls are intentional */
141 EVP_CIPHER_CTX_cleanup(save);
142 EVP_CIPHER_CTX_free(save);
143 EVP_CIPHER_free(type);
145 printf(" b[%d] = ", outlen);
147 printf(" c[%d] = ", outlen);
155 static int test_contexts_digest_or_legacy_mac(const EVP_MD *type, int mac)
157 int ret = 0, test = 0;
158 unsigned char K[32] = {1};
160 /* produce base digest */
161 EVP_MD_CTX *ctx, *save;
162 unsigned char pt[TEST_SIZE] = {1};
163 unsigned char b[EVP_MAX_MD_SIZE] = {0};
164 unsigned char c[EVP_MAX_MD_SIZE];
165 unsigned int outlen, tmplen;
167 /* Simply digest whole input. */
168 T(ctx = EVP_MD_CTX_new());
169 T(EVP_DigestInit_ex(ctx, type, NULL));
171 T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
172 T(EVP_DigestUpdate(ctx, pt, sizeof(pt)));
173 T(EVP_DigestFinal_ex(ctx, b, &tmplen));
174 save = ctx; /* will be not freed while cloning */
177 EVP_MD_CTX_reset(ctx); /* test double reset */
178 EVP_MD_CTX_reset(ctx);
179 T(EVP_DigestInit_ex(ctx, type, NULL));
181 T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
182 printf(" cloned contexts: ");
183 memset(c, 0, sizeof(c));
185 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
186 /* Clone and continue digesting next part of input. */
188 T(copy = EVP_MD_CTX_new());
189 T(EVP_MD_CTX_copy_ex(copy, ctx));
193 EVP_MD_CTX_free(ctx);
196 T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE));
198 outlen = i * STEP_SIZE;
199 T(EVP_DigestFinal_ex(ctx, c, &tmplen));
200 /* Should be same as the simple digest. */
201 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
202 EVP_MD_CTX_free(ctx);
204 printf(" b[%d] = ", outlen);
206 printf(" c[%d] = ", outlen);
211 /* Resume original context, what if it's damaged? */
212 printf(" base context: ");
213 memset(c, 0, sizeof(c));
214 T(EVP_DigestUpdate(save, pt, sizeof(pt)));
215 T(EVP_DigestFinal_ex(save, c, &tmplen));
216 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
217 EVP_MD_CTX_free(save);
219 printf(" b[%d] = ", outlen);
221 printf(" c[%d] = ", outlen);
229 static int test_contexts_digest(const char *name)
233 T((type = (EVP_MD *)EVP_get_digestbyname(name))
234 || (type = EVP_MD_fetch(NULL, name, NULL)));
237 printf(cBLUE "Digest test for %s" cNORM "\n", name);
238 int ret = test_contexts_digest_or_legacy_mac(type, 0);
243 static int test_contexts_mac(const char *name)
245 int ret = 0, test = 0;
246 unsigned char K[32] = {1};
247 const EVP_MD *type = EVP_get_digestbyname(name);
251 printf(cBLUE "Mac via EVP_MD test for %s" cNORM "\n", name);
252 return test_contexts_digest_or_legacy_mac(type, 1);
255 T(mac = EVP_MAC_fetch(NULL, name, NULL));
256 printf(cBLUE "Mac test for %s" cNORM "\n", name);
258 /* produce base mac */
260 unsigned char pt[TEST_SIZE] = {1};
261 unsigned char b[EVP_MAX_MD_SIZE] = {0};
262 unsigned char c[EVP_MAX_MD_SIZE] = {0};
263 size_t outlen, tmplen;
265 /* Simply mac whole input. */
266 T(ctx = EVP_MAC_CTX_new(mac));
267 T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
268 T(EVP_MAC_update(ctx, pt, sizeof(pt)));
269 T(EVP_MAC_final(ctx, b, &tmplen, sizeof(b)));
270 EVP_MAC_CTX_free(ctx);
272 /* Mac with rolling input. */
273 printf(" cloned contexts: ");
274 T(ctx = EVP_MAC_CTX_new(mac));
275 T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
277 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
278 T(EVP_MAC_update(ctx, pt + STEP_SIZE * i, STEP_SIZE));
280 outlen = i * STEP_SIZE;
281 T(EVP_MAC_final(ctx, c, &tmplen, sizeof(c)));
282 EVP_MAC_CTX_free(ctx);
285 /* Rolling mac should give the same result as the simple mac. */
286 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
289 printf(" b[%d] = ", (int)outlen);
291 printf(" c[%d] = ", (int)outlen);
299 static struct testcase_cipher {
302 } testcases_ciphers[] = {
303 { SN_id_Gost28147_89, },
305 { SN_gost89_cnt_12, },
307 { SN_grasshopper_ecb, },
308 { SN_grasshopper_cbc, },
309 { SN_grasshopper_cfb, },
310 { SN_grasshopper_ofb, },
311 { SN_grasshopper_ctr, },
314 { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 256 / 8 },
318 static struct testcase_digest {
321 } testcases_digests[] = {
322 { SN_id_GostR3411_94, },
323 { SN_id_Gost28147_89_MAC, 1 },
324 { SN_id_GostR3411_2012_256, },
325 { SN_id_GostR3411_2012_512, },
326 { SN_gost_mac_12, 1 },
328 { SN_grasshopper_mac, 1 },
329 { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 1 },
332 int main(int argc, char **argv)
336 OPENSSL_add_all_algorithms_conf();
338 const struct testcase_cipher *tc;
339 for (tc = testcases_ciphers; tc->name; tc++) {
340 ret |= test_contexts_cipher(tc->name, 1, tc->acpkm);
341 ret |= test_contexts_cipher(tc->name, 0, tc->acpkm);
343 const struct testcase_digest *td;
344 for (td = testcases_digests; td->name; td++) {
346 ret |= test_contexts_mac(td->name);
348 ret |= test_contexts_digest(td->name);
352 printf(cDRED "= Some tests FAILED!" cNORM "\n");
354 printf(cDGREEN "= All tests passed!" cNORM "\n");