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
9 # pragma warning(push, 3)
10 # include <openssl/applink.c>
13 #include <openssl/engine.h>
14 #include <openssl/evp.h>
15 #include <openssl/rand.h>
16 #include <openssl/err.h>
17 #include <openssl/asn1.h>
19 #ifndef EVP_MD_CTRL_SET_KEY
20 # include "gost_lcl.h"
25 ERR_print_errors_fp(stderr); \
26 OpenSSLDie(__FILE__, __LINE__, #e); \
29 #define cRED "\033[1;31m"
30 #define cDRED "\033[0;31m"
31 #define cGREEN "\033[1;32m"
32 #define cDGREEN "\033[0;32m"
33 #define cBLUE "\033[1;34m"
34 #define cDBLUE "\033[0;34m"
35 #define cNORM "\033[m"
36 #define TEST_ASSERT(e) {if ((test = (e))) \
37 printf(cRED " Test FAILED" cNORM "\n"); \
39 printf(cGREEN " Test passed" cNORM "\n");}
41 static void hexdump(const void *ptr, size_t len)
43 const unsigned char *p = ptr;
46 for (i = 0; i < len; i += j) {
47 for (j = 0; j < 16 && i + j < len; j++)
48 printf("%s%02x", j? "" : " ", p[i + j]);
56 static int test_contexts_cipher(const char *name, const int enc, int acpkm)
58 EVP_CIPHER_CTX *ctx, *save;
59 unsigned char pt[TEST_SIZE] = {1};
60 unsigned char b[TEST_SIZE]; /* base output */
61 unsigned char c[TEST_SIZE]; /* cloned output */
62 unsigned char K[32] = {1};
63 unsigned char iv[16] = {1};
65 int ret = 0, test = 0;
69 T((type = (EVP_CIPHER *)EVP_get_cipherbyname(name))
70 || (type = EVP_CIPHER_fetch(NULL, name, NULL)));
73 printf(cBLUE "%s test for %s" cNORM "\n",
74 enc ? "Encryption" : "Decryption", name);
76 /* produce base encryption */
77 ctx = EVP_CIPHER_CTX_new();
79 T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
81 if (EVP_CIPHER_get0_provider(type) != NULL) {
82 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
83 size_t v = (size_t)acpkm;
85 params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
86 T(EVP_CIPHER_CTX_set_params(ctx, params));
88 T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
91 T(EVP_CIPHER_CTX_set_padding(ctx, 0));
92 T(EVP_CipherUpdate(ctx, b, &outlen, pt, sizeof(b)));
93 T(EVP_CipherFinal_ex(ctx, b + outlen, &tmplen));
96 EVP_CIPHER_CTX_reset(ctx);
97 EVP_CIPHER_CTX_reset(ctx); /* double call is intentional */
98 T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
99 T(EVP_CIPHER_CTX_set_padding(ctx, 0));
101 if (EVP_CIPHER_get0_provider(type) != NULL) {
102 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
103 size_t v = (size_t)acpkm;
105 params[0] = OSSL_PARAM_construct_size_t("key-mesh", &v);
106 T(EVP_CIPHER_CTX_set_params(ctx, params));
108 T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
113 printf(" cloned contexts: ");
115 memset(c, 0, sizeof(c));
116 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
117 EVP_CIPHER_CTX *copy = EVP_CIPHER_CTX_new();
119 T(EVP_CIPHER_CTX_copy(copy, ctx));
120 if (save != ctx) /* else original context */
121 EVP_CIPHER_CTX_free(ctx);
124 T(EVP_CipherUpdate(ctx, c + STEP_SIZE * i, &outlen,
125 pt + STEP_SIZE * i, STEP_SIZE));
128 outlen = i * STEP_SIZE;
129 T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
130 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
131 EVP_CIPHER_CTX_free(ctx);
133 printf(" b[%d] = ", outlen);
135 printf(" c[%d] = ", outlen);
140 /* resume original context */
141 printf(" base context: ");
142 memset(c, 0, sizeof(c));
143 T(EVP_CipherUpdate(save, c, &outlen, pt, sizeof(c)));
144 T(EVP_CipherFinal_ex(save, c + outlen, &tmplen));
145 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
146 EVP_CIPHER_CTX_cleanup(save); /* multiple calls are intentional */
147 EVP_CIPHER_CTX_cleanup(save);
148 EVP_CIPHER_CTX_free(save);
149 EVP_CIPHER_free(type);
151 printf(" b[%d] = ", outlen);
153 printf(" c[%d] = ", outlen);
161 static int test_contexts_digest_or_legacy_mac(const EVP_MD *type, int mac)
163 int ret = 0, test = 0;
164 unsigned char K[32] = {1};
166 /* produce base digest */
167 EVP_MD_CTX *ctx, *save;
168 unsigned char pt[TEST_SIZE] = {1};
169 unsigned char b[EVP_MAX_MD_SIZE] = {0};
170 unsigned char c[EVP_MAX_MD_SIZE];
171 unsigned int outlen, tmplen;
173 /* Simply digest whole input. */
174 T(ctx = EVP_MD_CTX_new());
175 T(EVP_DigestInit_ex(ctx, type, NULL));
177 T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
178 T(EVP_DigestUpdate(ctx, pt, sizeof(pt)));
179 T(EVP_DigestFinal_ex(ctx, b, &tmplen));
180 save = ctx; /* will be not freed while cloning */
183 EVP_MD_CTX_reset(ctx); /* test double reset */
184 EVP_MD_CTX_reset(ctx);
185 T(EVP_DigestInit_ex(ctx, type, NULL));
187 T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
188 printf(" cloned contexts: ");
189 memset(c, 0, sizeof(c));
191 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
192 /* Clone and continue digesting next part of input. */
194 T(copy = EVP_MD_CTX_new());
195 T(EVP_MD_CTX_copy_ex(copy, ctx));
199 EVP_MD_CTX_free(ctx);
202 T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE));
204 outlen = i * STEP_SIZE;
205 T(EVP_DigestFinal_ex(ctx, c, &tmplen));
206 /* Should be same as the simple digest. */
207 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
208 EVP_MD_CTX_free(ctx);
210 printf(" b[%d] = ", outlen);
212 printf(" c[%d] = ", outlen);
217 /* Resume original context, what if it's damaged? */
218 printf(" base context: ");
219 memset(c, 0, sizeof(c));
220 T(EVP_DigestUpdate(save, pt, sizeof(pt)));
221 T(EVP_DigestFinal_ex(save, c, &tmplen));
222 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
223 EVP_MD_CTX_free(save);
225 printf(" b[%d] = ", outlen);
227 printf(" c[%d] = ", outlen);
235 static int test_contexts_digest(const char *name)
239 T((type = (EVP_MD *)EVP_get_digestbyname(name))
240 || (type = EVP_MD_fetch(NULL, name, NULL)));
243 printf(cBLUE "Digest test for %s" cNORM "\n", name);
244 int ret = test_contexts_digest_or_legacy_mac(type, 0);
249 static int test_contexts_mac(const char *name)
251 int ret = 0, test = 0;
252 unsigned char K[32] = {1};
253 const EVP_MD *type = EVP_get_digestbyname(name);
257 printf(cBLUE "Mac via EVP_MD test for %s" cNORM "\n", name);
258 return test_contexts_digest_or_legacy_mac(type, 1);
261 T(mac = EVP_MAC_fetch(NULL, name, NULL));
262 printf(cBLUE "Mac test for %s" cNORM "\n", name);
264 /* produce base mac */
266 unsigned char pt[TEST_SIZE] = {1};
267 unsigned char b[EVP_MAX_MD_SIZE] = {0};
268 unsigned char c[EVP_MAX_MD_SIZE] = {0};
269 size_t outlen, tmplen;
271 /* Simply mac whole input. */
272 T(ctx = EVP_MAC_CTX_new(mac));
273 T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
274 T(EVP_MAC_update(ctx, pt, sizeof(pt)));
275 T(EVP_MAC_final(ctx, b, &tmplen, sizeof(b)));
276 EVP_MAC_CTX_free(ctx);
278 /* Mac with rolling input. */
279 printf(" cloned contexts: ");
280 T(ctx = EVP_MAC_CTX_new(mac));
281 T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
283 for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
284 T(EVP_MAC_update(ctx, pt + STEP_SIZE * i, STEP_SIZE));
286 outlen = i * STEP_SIZE;
287 T(EVP_MAC_final(ctx, c, &tmplen, sizeof(c)));
288 EVP_MAC_CTX_free(ctx);
291 /* Rolling mac should give the same result as the simple mac. */
292 TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
295 printf(" b[%d] = ", (int)outlen);
297 printf(" c[%d] = ", (int)outlen);
305 static struct testcase_cipher {
308 } testcases_ciphers[] = {
309 { SN_id_Gost28147_89, },
311 { SN_gost89_cnt_12, },
313 { SN_grasshopper_ecb, },
314 { SN_grasshopper_cbc, },
315 { SN_grasshopper_cfb, },
316 { SN_grasshopper_ofb, },
317 { SN_grasshopper_ctr, },
320 { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 256 / 8 },
324 static struct testcase_digest {
327 } testcases_digests[] = {
328 { SN_id_GostR3411_94, },
329 { SN_id_Gost28147_89_MAC, 1 },
330 { SN_id_GostR3411_2012_256, },
331 { SN_id_GostR3411_2012_512, },
332 { SN_gost_mac_12, 1 },
334 { SN_grasshopper_mac, 1 },
335 { SN_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 1 },
338 int main(int argc, char **argv)
342 OPENSSL_add_all_algorithms_conf();
344 const struct testcase_cipher *tc;
345 for (tc = testcases_ciphers; tc->name; tc++) {
346 ret |= test_contexts_cipher(tc->name, 1, tc->acpkm);
347 ret |= test_contexts_cipher(tc->name, 0, tc->acpkm);
349 const struct testcase_digest *td;
350 for (td = testcases_digests; td->name; td++) {
352 ret |= test_contexts_mac(td->name);
354 ret |= test_contexts_digest(td->name);
358 printf(cDRED "= Some tests FAILED!" cNORM "\n");
360 printf(cDGREEN "= All tests passed!" cNORM "\n");