/*
- * Copyright (C) 2018 vt@altlinux.org. All Rights Reserved.
+ * Copyright (C) 2018,2020 Vitaly Chikunov <vt@altlinux.org> All Rights Reserved.
*
* Contents licensed under the terms of the OpenSSL license
* See https://www.openssl.org/source/license.html for details
*/
-#include "gost_grasshopper_cipher.h"
-#include "gost_grasshopper_defines.h"
-#include "gost_grasshopper_math.h"
-#include "gost_grasshopper_core.h"
-#include "e_gost_err.h"
-#include "gost_lcl.h"
+#include <openssl/engine.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <string.h>
+#ifndef EVP_MD_CTRL_SET_KEY
+# include "gost_lcl.h"
+#endif
#define T(e) if (!(e)) {\
ERR_print_errors_fp(stderr);\
#define cDBLUE "\033[0;34m"
#define cNORM "\033[m"
#define TEST_ASSERT(e) {if ((test = (e))) \
- printf(cRED " Test FAILED\n" cNORM); \
+ printf(cRED " Test FAILED" cNORM "\n"); \
else \
- printf(cGREEN " Test passed\n" cNORM);}
+ printf(cGREEN " Test passed" cNORM "\n");}
static void hexdump(const void *ptr, size_t len)
{
#define TEST_SIZE 256
#define STEP_SIZE 16
-static int test_contexts(const EVP_CIPHER *type, const int enc, const char *msg,
- int acpkm)
+static int test_contexts_cipher(int nid, const int enc, int acpkm)
{
EVP_CIPHER_CTX *ctx, *save;
unsigned char pt[TEST_SIZE] = {1};
- unsigned char b[TEST_SIZE];
- unsigned char c[TEST_SIZE];
+ unsigned char b[TEST_SIZE]; /* base output */
+ unsigned char c[TEST_SIZE]; /* cloned output */
unsigned char K[32] = {1};
unsigned char iv[16] = {1};
int outlen, tmplen;
int ret = 0, test = 0;
- printf(cBLUE "%s test for %s\n" cNORM, enc ? "Encryption" : "Decryption", msg);
+ const EVP_CIPHER *type = EVP_get_cipherbynid(nid);
+ const char *name = EVP_CIPHER_name(type);
+
+ printf(cBLUE "%s test for %s (nid %d)" cNORM "\n",
+ enc ? "Encryption" : "Decryption", name, nid);
/* produce base encryption */
ctx = EVP_CIPHER_CTX_new();
T(EVP_CipherFinal_ex(ctx, b + outlen, &tmplen));
/* and now tests */
- printf(" cloned contexts\n");
EVP_CIPHER_CTX_reset(ctx);
EVP_CIPHER_CTX_reset(ctx); /* double call is intentional */
T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, enc));
T(EVP_CIPHER_CTX_set_padding(ctx, 0));
if (acpkm)
T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL));
-
save = ctx;
+
+ printf(" cloned contexts: ");
int i;
memset(c, 0, sizeof(c));
for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
pt + STEP_SIZE * i, STEP_SIZE));
}
- outlen = i * GRASSHOPPER_BLOCK_SIZE;
+ outlen = i * STEP_SIZE;
T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, TEST_SIZE));
EVP_CIPHER_CTX_free(ctx);
ret |= test;
/* resume original context */
- printf(" base context\n");
+ printf(" base context: ");
memset(c, 0, sizeof(c));
T(EVP_CipherUpdate(save, c, &outlen, pt, sizeof(c)));
T(EVP_CipherFinal_ex(save, c + outlen, &tmplen));
return ret;
}
+static int test_contexts_digest(int nid, int mac)
+{
+ int ret = 0, test = 0;
+ unsigned char K[32] = {1};
+ const EVP_MD *type = EVP_get_digestbynid(nid);
+ const char *name = EVP_MD_name(type);
+ printf(cBLUE "Digest test for %s (nid %d)" cNORM "\n", name, nid);
+
+ /* produce base digest */
+ EVP_MD_CTX *ctx, *save;
+ unsigned char pt[TEST_SIZE] = {1};
+ unsigned char b[EVP_MAX_MD_SIZE] = {0};
+ unsigned char c[EVP_MAX_MD_SIZE];
+ unsigned int outlen, tmplen;
+
+ /* Simply digest whole input. */
+ T(ctx = EVP_MD_CTX_new());
+ T(EVP_DigestInit_ex(ctx, type, NULL));
+ if (mac)
+ T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
+ T(EVP_DigestUpdate(ctx, pt, sizeof(pt)));
+ T(EVP_DigestFinal_ex(ctx, b, &tmplen));
+ save = ctx; /* will be not freed while cloning */
+
+ /* cloned digest */
+ EVP_MD_CTX_reset(ctx); /* test double reset */
+ EVP_MD_CTX_reset(ctx);
+ T(EVP_DigestInit_ex(ctx, type, NULL));
+ if (mac)
+ T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
+ printf(" cloned contexts: ");
+ memset(c, 0, sizeof(c));
+ int i;
+ for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
+ /* Clone and continue digesting next part of input. */
+ EVP_MD_CTX *copy;
+ T(copy = EVP_MD_CTX_new());
+ T(EVP_MD_CTX_copy_ex(copy, ctx));
+
+ /* rolling */
+ if (save != ctx)
+ EVP_MD_CTX_free(ctx);
+ ctx = copy;
+
+ T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE));
+ }
+ outlen = i * STEP_SIZE;
+ T(EVP_DigestFinal_ex(ctx, c, &tmplen));
+ /* Should be same as the simple digest. */
+ TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
+ EVP_MD_CTX_free(ctx);
+ if (test) {
+ printf(" b[%d] = ", outlen);
+ hexdump(b, outlen);
+ printf(" c[%d] = ", outlen);
+ hexdump(c, outlen);
+ }
+ ret |= test;
+
+ /* Resume original context, what if it's damaged? */
+ printf(" base context: ");
+ memset(c, 0, sizeof(c));
+ T(EVP_DigestUpdate(save, pt, sizeof(pt)));
+ T(EVP_DigestFinal_ex(save, c, &tmplen));
+ TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
+ EVP_MD_CTX_free(save);
+ if (test) {
+ printf(" b[%d] = ", outlen);
+ hexdump(b, outlen);
+ printf(" c[%d] = ", outlen);
+ hexdump(c, outlen);
+ }
+ ret |= test;
+
+ return ret;
+}
+
+static struct testcase_cipher {
+ int nid;
+ int acpkm;
+} testcases_ciphers[] = {
+ { NID_id_Gost28147_89, },
+ { NID_gost89_cnt, },
+ { NID_gost89_cnt_12, },
+ { NID_gost89_cbc, },
+ { NID_grasshopper_ecb, },
+ { NID_grasshopper_cbc, },
+ { NID_grasshopper_cfb, },
+ { NID_grasshopper_ofb, },
+ { NID_grasshopper_ctr, },
+ { NID_magma_cbc, },
+ { NID_magma_ctr, },
+ { NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 256 / 8 },
+ { 0 },
+};
+
+static struct testcase_digest {
+ int nid;
+ int mac;
+} testcases_digests[] = {
+ { NID_id_GostR3411_94, },
+ { NID_id_Gost28147_89_MAC, 1 },
+ { NID_id_GostR3411_2012_256, },
+ { NID_id_GostR3411_2012_512, },
+ { NID_gost_mac_12, 1 },
+ { NID_magma_mac, 1 },
+ { NID_grasshopper_mac, 1 },
+ { NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, 1 },
+ { 0 },
+};
int main(int argc, char **argv)
{
int ret = 0;
- ret |= test_contexts(cipher_gost_grasshopper_ecb(), 1, "grasshopper ecb", 0);
- ret |= test_contexts(cipher_gost_grasshopper_ecb(), 0, "grasshopper ecb", 0);
- ret |= test_contexts(cipher_gost_grasshopper_cbc(), 1, "grasshopper cbc", 0);
- ret |= test_contexts(cipher_gost_grasshopper_cbc(), 0, "grasshopper cbc", 0);
- ret |= test_contexts(cipher_gost_grasshopper_ctr(), 1, "grasshopper ctr", 0);
- ret |= test_contexts(cipher_gost_grasshopper_ctr(), 0, "grasshopper ctr", 0);
- ret |= test_contexts(cipher_gost_grasshopper_ofb(), 1, "grasshopper ofb", 0);
- ret |= test_contexts(cipher_gost_grasshopper_ofb(), 0, "grasshopper ofb", 0);
- ret |= test_contexts(cipher_gost_grasshopper_ctracpkm(), 1, "grasshopper ctracpkm", 256 / 8);
- ret |= test_contexts(cipher_gost_grasshopper_ctracpkm(), 0, "grasshopper ctracpkm", 256 / 8);
+ OPENSSL_add_all_algorithms_conf();
+
+ const struct testcase_cipher *tc;
+ for (tc = testcases_ciphers; tc->nid; tc++) {
+ ret |= test_contexts_cipher(tc->nid, 1, tc->acpkm);
+ ret |= test_contexts_cipher(tc->nid, 0, tc->acpkm);
+ }
+ const struct testcase_digest *td;
+ for (td = testcases_digests; td->nid; td++) {
+ ret |= test_contexts_digest(td->nid, td->mac);
+ }
if (ret)
- printf(cDRED "= Some tests FAILED!\n" cNORM);
+ printf(cDRED "= Some tests FAILED!" cNORM "\n");
else
- printf(cDGREEN "= All tests passed!\n" cNORM);
+ printf(cDGREEN "= All tests passed!" cNORM "\n");
return ret;
}