From a04549cc755408ff2dcab209fd87d3e46f7d662a Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sun, 17 Sep 2006 13:00:18 +0000 Subject: [PATCH] GOST public key algorithm ENGINE donated to the OpenSSL by Cryptocom. Very early version, doesn't do much yet, not even added to the build system. --- engines/ccgost/Makefile | 122 ++++++ engines/ccgost/ameth.c | 671 ++++++++++++++++++++++++++++++++ engines/ccgost/crypt.h | 62 +++ engines/ccgost/e_gost_err.c | 210 ++++++++++ engines/ccgost/e_gost_err.h | 150 +++++++ engines/ccgost/e_gost_err.proto | 61 +++ engines/ccgost/engine.c | 230 +++++++++++ engines/ccgost/gost.ec | 5 + engines/ccgost/gost2001.c | 324 +++++++++++++++ engines/ccgost/gost2001_keyx.c | 385 ++++++++++++++++++ engines/ccgost/gost89.c | 383 ++++++++++++++++++ engines/ccgost/gost89.h | 96 +++++ engines/ccgost/gost94_keyx.c | 420 ++++++++++++++++++++ engines/ccgost/gost_asn1.c | 55 +++ engines/ccgost/gost_asn1.h | 57 +++ engines/ccgost/gost_crypt.c | 579 +++++++++++++++++++++++++++ engines/ccgost/gost_sign.c | 302 ++++++++++++++ engines/ccgost/gosthash.c | 256 ++++++++++++ engines/ccgost/gosthash.h | 39 ++ engines/ccgost/gostkeyx.h | 42 ++ engines/ccgost/gostsum.1 | 78 ++++ engines/ccgost/gostsum.c | 184 +++++++++ engines/ccgost/keywrap.c | 97 +++++ engines/ccgost/keywrap.h | 56 +++ engines/ccgost/md.h | 41 ++ engines/ccgost/md_gost.c | 69 ++++ engines/ccgost/meth.h | 22 ++ engines/ccgost/params.c | 198 ++++++++++ engines/ccgost/paramset.h | 34 ++ engines/ccgost/pmeth.c | 514 ++++++++++++++++++++++++ engines/ccgost/pmeth.h | 26 ++ engines/ccgost/sign.h | 30 ++ engines/ccgost/tools.h | 38 ++ 33 files changed, 5836 insertions(+) create mode 100644 engines/ccgost/Makefile create mode 100644 engines/ccgost/ameth.c create mode 100644 engines/ccgost/crypt.h create mode 100644 engines/ccgost/e_gost_err.c create mode 100644 engines/ccgost/e_gost_err.h create mode 100644 engines/ccgost/e_gost_err.proto create mode 100644 engines/ccgost/engine.c create mode 100644 engines/ccgost/gost.ec create mode 100644 engines/ccgost/gost2001.c create mode 100644 engines/ccgost/gost2001_keyx.c create mode 100644 engines/ccgost/gost89.c create mode 100644 engines/ccgost/gost89.h create mode 100644 engines/ccgost/gost94_keyx.c create mode 100644 engines/ccgost/gost_asn1.c create mode 100644 engines/ccgost/gost_asn1.h create mode 100644 engines/ccgost/gost_crypt.c create mode 100644 engines/ccgost/gost_sign.c create mode 100644 engines/ccgost/gosthash.c create mode 100644 engines/ccgost/gosthash.h create mode 100644 engines/ccgost/gostkeyx.h create mode 100644 engines/ccgost/gostsum.1 create mode 100644 engines/ccgost/gostsum.c create mode 100644 engines/ccgost/keywrap.c create mode 100644 engines/ccgost/keywrap.h create mode 100644 engines/ccgost/md.h create mode 100644 engines/ccgost/md_gost.c create mode 100644 engines/ccgost/meth.h create mode 100644 engines/ccgost/params.c create mode 100644 engines/ccgost/paramset.h create mode 100644 engines/ccgost/pmeth.c create mode 100644 engines/ccgost/pmeth.h create mode 100644 engines/ccgost/sign.h create mode 100644 engines/ccgost/tools.h diff --git a/engines/ccgost/Makefile b/engines/ccgost/Makefile new file mode 100644 index 0000000000..b4caacdb7e --- /dev/null +++ b/engines/ccgost/Makefile @@ -0,0 +1,122 @@ +# OPENSSL_DIR is a root directory of openssl sources +THISDIR?=$(shell perl -MCwd -e 'print getcwd') +OPENSSL_DIR?=$(THISDIR)/../openssl +ENGINE_ID?=gost +TESTSUITE_DIR?=$(THISDIR)/test-suite +FOR?=$(HOST) +CC=gcc +CFLAGS=-fPIC -g -Wall -I$(OPENSSL_DIR)/include +LDFLAGS=-g -L $(OPENSSL_DIR) -static-libgcc +ifeq "$(FOR)" "s64" +CFLAGS+=-m64 +LDFLAGS+=-m64 +endif +OS:=$(shell uname -s) +ifeq "$(OS)" "FreeBSD" +LIBDIR:=$(shell LD_LIBRARY_PATH=$(OPENSSL_DIR) $(OPENSSL_DIR)/apps/openssl version -d|sed -e 's/^[^"]*"//' -e 's/".*$$//')/lib +LDFLAGS+=-rpath $(LIBDIR) +endif + + +ifeq "$(FOR)" "w32" +ENGINE_LIB?=$(ENGINE_ID)$(DLLSUFFIX) +DLLSUFFIX=.dll +EXESUFFIX=.exe +CFLAGS+=-mno-cygwin +LDFLAGS+=-mno-cygwin +ifeq "$(OS)" "Linux" +CC=i586-mingw32msvc-gcc +endif +LIBS=-lcrypto.dll +else +ENGINE_LIB?=lib$(ENGINE_ID)$(DLLSUFFIX) +LIBS=-lcrypto +DLLSUFFIX=.so +endif +export DLLSUFFIX +export EXESUFFIX +ifneq "$(FOR)" "" +export FOR +endif +CFLAGS+=$(DEBUG_FLAGS) +export ENGINE_LIB +ENG_SOURCES=md_gost.c gost_crypt.c gost_asn1.c ameth.c pmeth.c\ + gost_crypt.c gost_sign.c gost2001.c md_gost.c gost_crypt.c\ + engine.c gost94_keyx.c keywrap.c gost2001_keyx.c +all: $(ENGINE_LIB) openssl.cnf +buildtests: +$(ENGINE_LIB): e_gost_err.o engine.o ameth.o pmeth.o params.o md_gost.o gosthash.o gost89.o gost_sign.o gost_crypt.o keywrap.o gost2001.o gost94_keyx.o gost2001_keyx.o gost_asn1.o + $(CC) $(LDFLAGS) -shared -o $@ $+ $(LIBS) $(LDFLAGS) +openssl.cnf: openssl.cnf.1 openssl.cnf.2 + cat $+ > $@ +openssl.cnf.1: + echo "openssl_conf = openssl_def" > $@ +openssl.cnf.2: + echo "[openssl_def]" > $@ + echo "engines = engine_section" >> $@ + echo "[engine_section]" >> $@ + echo "$(ENGINE_ID) = $(ENGINE_ID)_section" >> $@ + echo "[$(ENGINE_ID)_section]" >> $@ + echo "dynamic_path = $(THISDIR)/$(ENGINE_LIB)" >> $@ + echo "engine_id = $(ENGINE_ID)" >> $@ + echo "default_algorithms = ALL" >> $@ +gosthash1.o: gosthash.c + $(CC) -c $(CFLAGS) -o $@ -DOPENSSL_BUILD $+ +gostsum: gostsum.o gosthash.o gost89.o +inttests: gosttest$(EXESUFFIX) etalon wraptest$(EXESUFFIX) etalon.wrap ectest$(EXESUFFIX) etalon.ec + ./gosttest${EXESUFFIX} > gost_test + diff -uw gost_test etalon + ./wraptest$(EXESUFFIX) > wrap_test + diff -uw wrap_test etalon.wrap + ./ectest$(EXESUFFIX) > ec_test 2>&1 + diff -uw ec_test etalon.ec +ectest$(EXESUFFIX): ectest.o gost2001_dbg.o gost_sign_dbg.o params.o e_gost_err.o + $(CC) -o $@ $(LDFLAGS) $+ -lcrypto +%_dbg.o: %.c + $(CC) -c $(CFLAGS) -DDEBUG_SIGN -DDEBUG_KEYS -o $@ $+ +gosttest$(EXESUFFIX): gosttest.o gosthash.o gost89.o + $(CC) $(LDFLAGS) -o $@ $+ +wraptest$(EXESUFFIX): wraptest.c keywrap.c gost89.c + $(CC) -DDEBUG_DH $(LDFLAGS) -o $@ $+ +sign_ex: LOADLIBES=-lcrypto +sign_ex: sign_ex.o +clean: + rm -f core gosttest gostsum *.o gost_test openssl.cnf* $(ENGINE_LIB) + if [ -f t/Makefile ]; then $(MAKE) -C t clean; fi + if [ -f $(TESTSUITE_DIR)/Makefile ]; then $(MAKE) -C $(TESTSUITE_DIR) clean; fi +e_gost_err.c e_gost_err.h: $(ENG_SOURCES) gost.ec e_gost_err.proto + perl $(OPENSSL_DIR)/util/mkerr.pl -conf gost.ec -nostatic -debug -write $(ENG_SOURCES) + +tests: openssl.cnf.2 + OPENSSL_DIR=$(OPENSSL_DIR) $(MAKE) -C $(TESTSUITE_DIR) CONFADD=$(THISDIR)/openssl.cnf.2 + +# depedencies +# +# +gost_sign.o: gost_sign.c sign.h paramset.h tools.h e_gost_err.h + +pmeth.o: pmeth.c meth.h pmeth.h sign.h paramset.h e_gost_err.h + +ameth.o: ameth.c tools.h meth.h pmeth.h gost_asn1.h crypt.h e_gost_err.h paramset.h + +keywrap.o: keywrap.c gost89.h keywrap.h + +gost2001.o: gost2001.c tools.h sign.h paramset.h e_gost_err.h + +engine.o: engine.c md.h crypt.h meth.h e_gost_err.h + +gost89.o: gost89.c gost89.h + +gost_asn1.o: gost_asn1.c gost_asn1.h + +gost_crypt.o: gost_crypt.c crypt.h gost89.h e_gost_err.h gost_asn1.h + +gosthash.o: gosthash.c gost89.h gosthash.h + +md_gost.o: md_gost.c md.h gosthash.h e_gost_err.h + +params.o: params.c paramset.h + +gost94_keyx.o: gost94_keyx.c gost_asn1.h gost89.h gosthash.h crypt.h pmeth.h keywrap.h e_gost_err.h gostkeyx.h + +gost2001_keyx.o: gost2001_keyx.c gost89.h gost_asn1.h e_gost_err.h keywrap.h crypt.h sign.h gostkeyx.h pmeth.h gosthash.h tools.h diff --git a/engines/ccgost/ameth.c b/engines/ccgost/ameth.c new file mode 100644 index 0000000000..c64cd2d298 --- /dev/null +++ b/engines/ccgost/ameth.c @@ -0,0 +1,671 @@ +/********************************************************************** + * ameth.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of RFC 4490/4491 ASN1 method * + * for OpenSSL * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include "meth.h" +#include "pmeth.h" +#include "paramset.h" +#include "gost_asn1.h" +#include "crypt.h" +#include "sign.h" +#include "tools.h" +#include "e_gost_err.h" + +int gost94_nid_by_params(DSA *p) +{ + R3410_params *gost_params; + BIGNUM *q=BN_new(); + for (gost_params = R3410_paramset;gost_params->q!=NULL; gost_params++) { + BN_dec2bn(&q,gost_params->q); + if (!BN_cmp(q,p->q)) + { + BN_free(q); + return gost_params->nid; + } + } + BN_free(q); + return NID_undef; +} + +static ASN1_STRING *encode_gost_algor_params(const EVP_PKEY *key) +{ + ASN1_STRING *params = ASN1_STRING_new(); + GOST_KEY_PARAMS *gkp = GOST_KEY_PARAMS_new(); + int pkey_param_nid = NID_undef; + int cipher_param_nid = NID_undef; + if (!params || !gkp) { + GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, + ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(params); + params = NULL; + goto err; + } + switch (EVP_PKEY_base_id(key)) { + case NID_id_GostR3410_2001_cc: + pkey_param_nid = NID_id_GostR3410_2001_ParamSet_cc; + cipher_param_nid = NID_id_Gost28147_89_cc; + break; + case NID_id_GostR3410_94_cc: + pkey_param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet; + cipher_param_nid = NID_id_Gost28147_89_cc; + break; + case NID_id_GostR3410_2001: + pkey_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)key))); + cipher_param_nid = get_encryption_params(NULL)->nid; + break; + case NID_id_GostR3410_94: + pkey_param_nid = (int) gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)key)); + if (pkey_param_nid == NID_undef) { + GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, + GOST_R_INVALID_GOST94_PARMSET); + ASN1_STRING_free(params); + params=NULL; + goto err; + } + cipher_param_nid = get_encryption_params(NULL)->nid; + break; + } + gkp->key_params = OBJ_nid2obj(pkey_param_nid); + gkp->hash_params = OBJ_nid2obj(NID_id_GostR3411_94_CryptoProParamSet); + /*gkp->cipher_params = OBJ_nid2obj(cipher_param_nid);*/ + params->length = i2d_GOST_KEY_PARAMS(gkp, ¶ms->data); + if (params->length <=0 ) + { + GOSTerr(GOST_F_ENCODE_GOST_ALGOR_PARAMS, + ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(params); + params = NULL; + goto err; + } + params ->type = V_ASN1_SEQUENCE; +err: + GOST_KEY_PARAMS_free(gkp); + return params; +} +/* Parses GOST algorithm parameters from X509_ALGOR and + * modifies pkey setting NID and parameters + */ +static int decode_gost_algor_params(EVP_PKEY *pkey, X509_ALGOR *palg) +{ + ASN1_OBJECT *palg_obj =NULL; + int ptype = V_ASN1_UNDEF; + int pkey_nid = NID_undef,param_nid = NID_undef; + ASN1_STRING *pval = NULL; + const unsigned char *p; + GOST_KEY_PARAMS *gkp = NULL; + + X509_ALGOR_get0(&palg_obj, &ptype, (void **) (&pval), palg); + if (ptype != V_ASN1_SEQUENCE) { + GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, + GOST_R_BAD_KEY_PARAMETERS_FORMAT); + return 0; + } + p=pval->data; + pkey_nid = OBJ_obj2nid(palg_obj); + + gkp = d2i_GOST_KEY_PARAMS(NULL,&p,pval->length); + if (!gkp) { + GOSTerr(GOST_F_DECODE_GOST_ALGOR_PARAMS, + GOST_R_BAD_PKEY_PARAMETERS_FORMAT); + } + param_nid = OBJ_obj2nid(gkp->key_params); + GOST_KEY_PARAMS_free(gkp); + EVP_PKEY_set_type(pkey,pkey_nid); + switch (pkey_nid) { + case NID_id_GostR3410_94: + case NID_id_GostR3410_94_cc: + { DSA *dsa= EVP_PKEY_get0(pkey); + if (!dsa) { + dsa = DSA_new(); + if (!EVP_PKEY_assign(pkey,pkey_nid,dsa)) return 0; + } + if (!fill_GOST94_params(dsa,param_nid)) return 0; + break; + } + case NID_id_GostR3410_2001: + case NID_id_GostR3410_2001_cc: + { EC_KEY *ec = EVP_PKEY_get0(pkey); + if (!ec) { + ec = EC_KEY_new(); + if (!EVP_PKEY_assign(pkey,pkey_nid,ec)) return 0; + } + if (!fill_GOST2001_params(ec,param_nid)) return 0; + + } + + } + + return 1; +} + +static int gost_set_priv_key(EVP_PKEY *pkey,BIGNUM *priv) +{ + switch (EVP_PKEY_base_id(pkey)) { + case NID_id_GostR3410_94: + case NID_id_GostR3410_94_cc: + { DSA *dsa = EVP_PKEY_get0(pkey); + if (!dsa) { + dsa = DSA_new(); + EVP_PKEY_assign(pkey,EVP_PKEY_base_id(pkey),dsa); + } + dsa->priv_key = BN_dup(priv); + if (!EVP_PKEY_missing_parameters(pkey)) + gost94_compute_public(dsa); + break; + } + case NID_id_GostR3410_2001: + case NID_id_GostR3410_2001_cc: + { EC_KEY *ec = EVP_PKEY_get0(pkey); + if (!ec) { + ec = EC_KEY_new(); + EVP_PKEY_assign(pkey,EVP_PKEY_base_id(pkey),ec); + } + if (!EC_KEY_set_private_key(ec,priv)) return 0; + if (!EVP_PKEY_missing_parameters(pkey)) + gost2001_compute_public(ec); + break; + } + + } + return 1; +} +BIGNUM* gost_get_priv_key(const EVP_PKEY *pkey) +{ + switch (EVP_PKEY_base_id(pkey)) { + case NID_id_GostR3410_94: + case NID_id_GostR3410_94_cc: + { DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pkey); + if (!dsa) { + return NULL; + } + if (!dsa->priv_key) return NULL; + return BN_dup(dsa->priv_key); + break; + } + case NID_id_GostR3410_2001: + case NID_id_GostR3410_2001_cc: + { EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pkey); + const BIGNUM* priv; + if (!ec) { + return NULL; + } + if (!(priv=EC_KEY_get0_private_key(ec))) return NULL; + return BN_dup(priv); + break; + } + + } + return NULL; +} +static int pkey_ctrl_gost(EVP_PKEY *pkey, int op, + long arg1, void *arg2) +{ + switch (op) + { + case ASN1_PKEY_CTRL_PKCS7_SIGN: + if (arg1 == 0) { + X509_ALGOR *alg1 = NULL, *alg2 = NULL; + int nid = EVP_PKEY_base_id(pkey); + PKCS7_SIGNER_INFO_get0_algs((PKCS7_SIGNER_INFO*)arg2, + NULL, &alg1, &alg2); + X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_id_GostR3411_94), + V_ASN1_NULL, 0); + if (nid == NID_undef) { + return (-1); + } + X509_ALGOR_set0(alg2, OBJ_nid2obj(nid), V_ASN1_NULL, 0); + } + return 1; + case ASN1_PKEY_CTRL_PKCS7_ENCRYPT: + if (arg1 == 0) + { + X509_ALGOR *alg; + ASN1_STRING * params = encode_gost_algor_params(pkey); + if (!params) { + return -1; + } + PKCS7_RECIP_INFO_get0_alg((PKCS7_RECIP_INFO*)arg2, &alg); + X509_ALGOR_set0(alg, OBJ_nid2obj(pkey->type), + V_ASN1_SEQUENCE, params); + } + return 1; + case ASN1_PKEY_CTRL_DEFAULT_MD_NID: + *(int *)arg2 = NID_id_GostR3411_94; + return 2; + } + + return -2; +} +/*----------------------- free functions * ------------------------------*/ +static void pkey_free_gost94(EVP_PKEY *key) { + if (key->pkey.dsa) { + DSA_free(key->pkey.dsa); + } +} +static void pkey_free_gost01(EVP_PKEY *key) { + if (key->pkey.ec) { + EC_KEY_free(key->pkey.ec); + } +} +/* ------------------ private key functions -----------------------------*/ +static int priv_decode_gost( EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf) +{ + const unsigned char *pkey_buf = NULL,*p=NULL; + int priv_len = 0; + BIGNUM *pk_num=NULL; + int ret =0; + X509_ALGOR *palg =NULL; + ASN1_OBJECT *palg_obj = NULL; + ASN1_INTEGER *priv_key=NULL; + + if (!PKCS8_pkey_get0(&palg_obj,&pkey_buf,&priv_len,&palg,p8inf)) + return 0; + p = pkey_buf; + if (!decode_gost_algor_params(pk,palg)) { + return 0; + } + priv_key=d2i_ASN1_INTEGER(NULL,&p,priv_len); + if (!priv_key) { + } + + if (!(pk_num = ASN1_INTEGER_to_BN(priv_key, NULL))) { + GOSTerr(GOST_F_PRIV_DECODE_GOST_94, + EVP_R_DECODE_ERROR); + } + + ret= gost_set_priv_key(pk,pk_num); + BN_free(pk_num); + return ret; +} +/* ----------------------------------------------------------------------*/ +static int priv_encode_gost(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk) +{ + ASN1_OBJECT *algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); + ASN1_STRING *params = encode_gost_algor_params(pk); + unsigned char *priv_buf = NULL; + int priv_len; + BIGNUM *key; + + ASN1_INTEGER *asn1key=NULL; + if (!params) { + return 0; + } + key = gost_get_priv_key(pk); + asn1key = BN_to_ASN1_INTEGER(key,NULL); + BN_free(key); + priv_len = i2d_ASN1_INTEGER(asn1key,&priv_buf); + ASN1_INTEGER_free(asn1key); + return PKCS8_pkey_set0(p8,algobj,0,V_ASN1_SEQUENCE,params, + priv_buf,priv_len); +} + +static int priv_print_gost (BIO *out,const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) +{ + BIGNUM *key; + if (!BIO_indent(out,indent,128)) return 0; + key = gost_get_priv_key(pkey); + if (!key) return 0; + BN_print(out,key); + BN_free(key); + return 1; +} +/* ---------------------------------------------------------------------*/ +static int param_missing_gost94(const EVP_PKEY *pk) +{ + const DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pk); + if (!dsa) return 1; + if (!dsa->q) return 1; + return 0; +} +static int param_missing_gost01(const EVP_PKEY *pk) +{ + const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk); + if (!ec) return 1; + if (!EC_KEY_get0_group(ec)) return 1; + return 0; +} + +static int param_copy_gost94(EVP_PKEY *to, const EVP_PKEY *from) +{ + const DSA *dfrom = EVP_PKEY_get0((EVP_PKEY *)from); + DSA *dto = EVP_PKEY_get0(to); + if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) + { + GOSTerr(GOST_F_PARAM_COPY_GOST94, + GOST_R_INCOMPATIBLE_ALGORITHMS); + return 0; + } + if (!dfrom) + { + GOSTerr(GOST_F_PARAM_COPY_GOST94, + GOST_R_KEY_PARAMETERS_MISSING); + return 0; + } + if (!dto) + { + dto = DSA_new(); + EVP_PKEY_assign(to,EVP_PKEY_base_id(from),dto); + } +#define COPYBIGNUM(a,b,x) if (a->x) BN_free(a->x); a->x=BN_dup(b->x); + COPYBIGNUM(dto,dfrom,p) + COPYBIGNUM(dto,dfrom,q) + COPYBIGNUM(dto,dfrom,g) + + if (dto->priv_key) + gost94_compute_public(dto); + return 1; +} +static int param_copy_gost01(EVP_PKEY *to, const EVP_PKEY *from) { + EC_KEY *eto = EVP_PKEY_get0(to); + const EC_KEY *efrom = EVP_PKEY_get0((EVP_PKEY *)from); + if (EVP_PKEY_base_id(from) != EVP_PKEY_base_id(to)) { + GOSTerr(GOST_F_PARAM_COPY_GOST01, + GOST_R_INCOMPATIBLE_ALGORITHMS); + return 0; + } + if (!efrom) { + GOSTerr(GOST_F_PARAM_COPY_GOST94, + GOST_R_KEY_PARAMETERS_MISSING); + return 0; + } + if (!eto) { + eto = EC_KEY_new(); + EVP_PKEY_assign(to,EVP_PKEY_base_id(from),eto); + } + EC_KEY_set_group(eto,EC_GROUP_dup(EC_KEY_get0_group(efrom))); + if (EC_KEY_get0_private_key(eto)) { + gost2001_compute_public(eto); + } + return 1; + + + +} +static int param_cmp_gost94(const EVP_PKEY *a, const EVP_PKEY *b) { + const DSA *da = EVP_PKEY_get0((EVP_PKEY *)a); + const DSA *db = EVP_PKEY_get0((EVP_PKEY *)b); + if (!BN_cmp(da->q,db->q)) return 1; + return 0; +} +static int param_cmp_gost01(const EVP_PKEY *a, const EVP_PKEY *b) { + if (EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)a)))== + EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)b)))) { + return 1; + } + return 0; + +} +/* ---------- Public key functions * --------------------------------------*/ +static int pub_decode_gost94(EVP_PKEY *pk, X509_PUBKEY *pub) +{ + X509_ALGOR *palg = NULL; + const unsigned char *pubkey_buf = NULL; + unsigned char *databuf; + ASN1_OBJECT *palgobj = NULL; + int pub_len,i,j; + DSA *dsa; + ASN1_OCTET_STRING *octet= NULL; + + if (!X509_PUBKEY_get0_param(&palgobj,&pubkey_buf,&pub_len, + &palg, pub)) return 0; + EVP_PKEY_assign(pk,OBJ_obj2nid(palgobj),NULL); + if (!decode_gost_algor_params(pk,palg)) return 0; + octet = d2i_ASN1_OCTET_STRING(NULL,&pubkey_buf,pub_len); + if (!octet) + { + GOSTerr(GOST_F_PUB_DECODE_GOST94,ERR_R_MALLOC_FAILURE); + return 0; + } + databuf = OPENSSL_malloc(octet->length); + for (i=0,j=octet->length-1;ilength;i++,j--) + { + databuf[j]=octet->data[i]; + } + dsa = EVP_PKEY_get0(pk); + dsa->pub_key=BN_bin2bn(databuf,octet->length,NULL); + ASN1_OCTET_STRING_free(octet); + OPENSSL_free(databuf); + return 1; + +} +static int pub_encode_gost94(X509_PUBKEY *pub,const EVP_PKEY *pk) +{ + ASN1_OBJECT *algobj = NULL; + ASN1_OCTET_STRING *octet = NULL; + void *pval = NULL; + unsigned char *buf=NULL,*databuf,*sptr; + int i,j,data_len,ret=0; + + int ptype; + DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pk); + algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); + if (pk->save_parameters) { + ASN1_STRING *params = encode_gost_algor_params(pk); + pval = params; + ptype = V_ASN1_SEQUENCE; + } + data_len = BN_num_bytes(dsa->pub_key); + databuf = OPENSSL_malloc(data_len); + BN_bn2bin(dsa->pub_key,databuf); + octet = ASN1_OCTET_STRING_new(); + ASN1_STRING_set(octet,NULL,data_len); + sptr = ASN1_STRING_data(octet); + for (i=0,j=data_len-1; i< data_len;i++,j--) + { + sptr[i]=databuf[j]; + } + OPENSSL_free(databuf); + ret = i2d_ASN1_OCTET_STRING(octet,&buf); + ASN1_BIT_STRING_free(octet); + if (ret <0) return 0; + return X509_PUBKEY_set0_param(pub,algobj,ptype,pval,buf,ret); +} +static int pub_decode_gost01(EVP_PKEY *pk,X509_PUBKEY *pub) +{ + X509_ALGOR *palg = NULL; + const unsigned char *pubkey_buf = NULL; + unsigned char *databuf; + ASN1_OBJECT *palgobj = NULL; + int pub_len,i,j; + EC_POINT *pub_key; + BIGNUM *X,*Y; + ASN1_OCTET_STRING *octet= NULL; + const EC_GROUP *group; + + if (!X509_PUBKEY_get0_param(&palgobj,&pubkey_buf,&pub_len, + &palg, pub)) return 0; + EVP_PKEY_assign(pk,OBJ_obj2nid(palgobj),NULL); + if (!decode_gost_algor_params(pk,palg)) return 0; + group = EC_KEY_get0_group(EVP_PKEY_get0(pk)); + octet = d2i_ASN1_OCTET_STRING(NULL,&pubkey_buf,pub_len); + if (!octet) + { + GOSTerr(GOST_F_PUB_DECODE_GOST94,ERR_R_MALLOC_FAILURE); + return 0; + } + databuf = OPENSSL_malloc(octet->length); + for (i=0,j=octet->length-1;ilength;i++,j--) + { + databuf[j]=octet->data[i]; + } + if (EVP_PKEY_base_id(pk) == NID_id_GostR3410_2001_cc) { + X= getbnfrombuf(databuf,octet->length/2); + Y= getbnfrombuf(databuf+(octet->length/2),octet->length/2); + } else { + Y= getbnfrombuf(databuf,octet->length/2); + X= getbnfrombuf(databuf+(octet->length/2),octet->length/2); + } + OPENSSL_free(databuf); + pub_key = EC_POINT_new(group); + if (!EC_POINT_set_affine_coordinates_GFp(group + ,pub_key,X,Y,NULL)) + { + GOSTerr(GOST_F_PUB_DECODE_GOST01, + ERR_R_EC_LIB); + return 0; + } + BN_free(X); + BN_free(Y); + if (!EC_KEY_set_public_key(EVP_PKEY_get0(pk),pub_key)) + { + GOSTerr(GOST_F_PUB_DECODE_GOST01, + ERR_R_EC_LIB); + return 0; + } + /*EC_POINT_free(pub_key);*/ + return 1; + +} +static int pub_encode_gost01(X509_PUBKEY *pub,const EVP_PKEY *pk) +{ + ASN1_OBJECT *algobj = NULL; + ASN1_OCTET_STRING *octet = NULL; + void *pval = NULL; + unsigned char *buf=NULL,*databuf,*sptr; + int i,j,data_len,ret=0; + const EC_POINT *pub_key; + BIGNUM *X,*Y,*order; + const EC_KEY *ec = EVP_PKEY_get0((EVP_PKEY *)pk); + int ptype; + + algobj = OBJ_nid2obj(EVP_PKEY_base_id(pk)); + if (pk->save_parameters) { + ASN1_STRING *params = encode_gost_algor_params(pk); + pval = params; + ptype = V_ASN1_SEQUENCE; + } + order = BN_new(); + EC_GROUP_get_order(EC_KEY_get0_group(ec),order,NULL); + pub_key=EC_KEY_get0_public_key(ec); + if (!pub_key) { + GOSTerr(GOST_F_PUB_ENCODE_GOST01, + GOST_R_PUBLIC_KEY_UNDEFINED); + return 0; + } + X=BN_new(); + Y=BN_new(); + EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec), + pub_key,X,Y,NULL); + data_len = 2*BN_num_bytes(order); + BN_free(order); + databuf = OPENSSL_malloc(data_len); + memset(databuf,0,data_len); + if (EVP_PKEY_base_id(pk) == NID_id_GostR3410_2001_cc) { + store_bignum(X,databuf,data_len/2); + store_bignum(Y,databuf+data_len/2,data_len/2); + } else { + store_bignum(X,databuf+data_len/2,data_len/2); + store_bignum(Y,databuf,data_len/2); + } + BN_free(X); + BN_free(Y); + octet = ASN1_OCTET_STRING_new(); + ASN1_STRING_set(octet,NULL,data_len); + sptr=ASN1_STRING_data(octet); + for (i=0,j=data_len-1;ipub_key && db->pub_key + && !BN_cmp(da->pub_key,db->pub_key)) { + return 1; + } + return 0; +} +static int pub_cmp_gost01(const EVP_PKEY *a,const EVP_PKEY *b) +{ + const EC_KEY *ea = EVP_PKEY_get0((EVP_PKEY *)a); + const EC_KEY *eb = EVP_PKEY_get0((EVP_PKEY *)b); + const EC_POINT *ka,*kb; + int ret=0; + if (!ea || !eb) return 0; + ka = EC_KEY_get0_public_key(ea); + kb = EC_KEY_get0_public_key(eb); + if (!ka || !kb) return 0; + ret = (0==EC_POINT_cmp(EC_KEY_get0_group(ea),ka,kb,NULL)) ; + return ret; +} +static int pub_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) +{ + const BIGNUM *key; + if (!BIO_indent(out,indent,128)) return 0; + key = ((DSA *)EVP_PKEY_get0((EVP_PKEY *)pkey))->pub_key; + if (!key) return 0; + BN_print(out,key); + return 1; +} +static int pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) +{ + return 0; +} +static int pkey_size_gost(const EVP_PKEY *pk) +{ + return 64; +} +static int pkey_bits_gost(const EVP_PKEY *pk) +{ + return 256; +} +/* ----------------------------------------------------------------------*/ +int register_ameth_gost (int nid, EVP_PKEY_ASN1_METHOD **ameth, const char* pemstr, const char* info) { + *ameth = EVP_PKEY_asn1_new(nid, + ASN1_PKEY_SIGPARAM_NULL, pemstr, info); + if (!*ameth) return 0; + switch (nid) { + case NID_id_GostR3410_94_cc: + case NID_id_GostR3410_94: + EVP_PKEY_asn1_set_free (*ameth, pkey_free_gost94); + EVP_PKEY_asn1_set_private (*ameth, + priv_decode_gost, priv_encode_gost, + priv_print_gost); + + EVP_PKEY_asn1_set_param (*ameth, 0, 0, + param_missing_gost94, param_copy_gost94, + param_cmp_gost94,0 ); + EVP_PKEY_asn1_set_public (*ameth, + pub_decode_gost94, pub_encode_gost94, + pub_cmp_gost94, pub_print_gost94, + pkey_size_gost, pkey_bits_gost); + + EVP_PKEY_asn1_set_ctrl (*ameth, pkey_ctrl_gost); + break; + case NID_id_GostR3410_2001_cc: + case NID_id_GostR3410_2001: + EVP_PKEY_asn1_set_free (*ameth, pkey_free_gost01); + EVP_PKEY_asn1_set_private (*ameth, + priv_decode_gost, priv_encode_gost, + priv_print_gost); + + EVP_PKEY_asn1_set_param (*ameth, 0, 0, + param_missing_gost01, param_copy_gost01, + param_cmp_gost01, 0); + EVP_PKEY_asn1_set_public (*ameth, + pub_decode_gost01, pub_encode_gost01, + pub_cmp_gost01, pub_print_gost01, + pkey_size_gost, pkey_bits_gost); + + EVP_PKEY_asn1_set_ctrl (*ameth, pkey_ctrl_gost); + break; + } + return 1; +} diff --git a/engines/ccgost/crypt.h b/engines/ccgost/crypt.h new file mode 100644 index 0000000000..bdd3dc08a8 --- /dev/null +++ b/engines/ccgost/crypt.h @@ -0,0 +1,62 @@ +/********************************************************************** + * gost_crypt.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declarations for GOST 28147-89 encryption algorithm * + * OpenSSL 0.9.9 libraries required * + **********************************************************************/ +#ifndef GOST_CRYPT_H +#define GOST_CRYPT_H +#include +#include +#include +#include "gost89.h" +#ifdef __cplusplus + extern "C" { +#endif +/* Cipher context used for EVP_CIPHER operation */ +struct ossl_gost_cipher_ctx { + int paramNID; + off_t count; + int key_meshing; + gost_ctx cctx; +}; +/* Structure to map parameter NID to S-block */ +struct gost_cipher_info { + int nid; + gost_subst_block *sblock; + int key_meshing; +}; +#ifdef USE_SSL +/* Context for MAC */ +struct ossl_gost_imit_ctx { + gost_ctx cctx; + unsigned char buffer[8]; + unsigned char partial_block[8]; + off_t count; + int key_meshing; + int bytes_left; + int key_set; +}; +#endif +/* Table which maps parameter NID to S-blocks */ +extern struct gost_cipher_info gost_cipher_list[]; +/* Find encryption params from ASN1_OBJECT */ +const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj); +/* Implementation of GOST 28147-89 cipher in CFB and CNT modes */ +extern EVP_CIPHER cipher_gost; +#ifdef USE_SSL +#define EVP_MD_FLAG_NEEDS_KEY 0x20 +#define EVP_MD_CTRL_GET_TLS_MAC_KEY_LENGTH (EVP_MD_CTRL_ALG_CTRL+1) +#define EVP_MD_CTRL_SET_KEY (EVP_MD_CTRL_ALG_CTRL+2) +/* Ciphers and MACs specific for GOST TLS draft */ +extern EVP_CIPHER cipher_gost_vizircfb; +extern EVP_CIPHER cipher_gost_cpacnt; +extern EVP_MD imit_gost_vizir; +extern EVP_MD imit_gost_cpa; +#endif +#ifdef __cplusplus + }; +#endif +#endif diff --git a/engines/ccgost/e_gost_err.c b/engines/ccgost/e_gost_err.c new file mode 100644 index 0000000000..5ba09e885a --- /dev/null +++ b/engines/ccgost/e_gost_err.c @@ -0,0 +1,210 @@ +/* e_gost_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include +#include +#include "e_gost_err.h" + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +#define ERR_FUNC(func) ERR_PACK(0,func,0) +#define ERR_REASON(reason) ERR_PACK(0,0,reason) + +static ERR_STRING_DATA GOST_str_functs[]= + { +{ERR_FUNC(GOST_F_DECODE_GOST_ALGOR_PARAMS), "DECODE_GOST_ALGOR_PARAMS"}, +{ERR_FUNC(GOST_F_DECRYPT_CRYPTOCOM_KEY), "decrypt_cryptocom_key"}, +{ERR_FUNC(GOST_F_ENCODE_GOST_ALGOR_PARAMS), "ENCODE_GOST_ALGOR_PARAMS"}, +{ERR_FUNC(GOST_F_FILL_GOST2001_PARAMS), "FILL_GOST2001_PARAMS"}, +{ERR_FUNC(GOST_F_FILL_GOST94_PARAMS), "FILL_GOST94_PARAMS"}, +{ERR_FUNC(GOST_F_GET_ENCRYPTION_PARAMS), "get_encryption_params"}, +{ERR_FUNC(GOST_F_GOST2001_COMPUTE_PUBLIC), "GOST2001_COMPUTE_PUBLIC"}, +{ERR_FUNC(GOST_F_GOST2001_DO_SIGN), "GOST2001_DO_SIGN"}, +{ERR_FUNC(GOST_F_GOST2001_DO_VERIFY), "GOST2001_DO_VERIFY"}, +{ERR_FUNC(GOST_F_GOST89_GET_ASN1_PARAMETERS), "gost89_get_asn1_parameters"}, +{ERR_FUNC(GOST_F_GOST89_SET_ASN1_PARAMETERS), "gost89_set_asn1_parameters"}, +{ERR_FUNC(GOST_F_GOST94_COPY_PARAMETERS), "GOST94_COPY_PARAMETERS"}, +{ERR_FUNC(GOST_F_GOST_CIPHER_CTL), "gost_cipher_ctl"}, +{ERR_FUNC(GOST_F_GOST_COMPUTE_PUBLIC), "GOST_COMPUTE_PUBLIC"}, +{ERR_FUNC(GOST_F_GOST_DO_SIGN), "GOST_DO_SIGN"}, +{ERR_FUNC(GOST_F_GOST_DO_VERIFY), "GOST_DO_VERIFY"}, +{ERR_FUNC(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001), "MAKE_RFC4490_KEYTRANSPORT_2001"}, +{ERR_FUNC(GOST_F_PARAM_COPY_GOST01), "PARAM_COPY_GOST01"}, +{ERR_FUNC(GOST_F_PARAM_COPY_GOST94), "PARAM_COPY_GOST94"}, +{ERR_FUNC(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT), "PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT"}, +{ERR_FUNC(GOST_F_PKCS7_GOST94_KEY_TRANSPORT_DECRYPT), "PKCS7_GOST94_KEY_TRANSPORT_DECRYPT"}, +{ERR_FUNC(GOST_F_PKEY_GOST01CC_DECRYPT), "pkey_GOST01cc_decrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST01CC_ENCRYPT), "pkey_GOST01cc_encrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST01CP_ENCRYPT), "pkey_GOST01cp_encrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST01_KEYGEN), "PKEY_GOST01_KEYGEN"}, +{ERR_FUNC(GOST_F_PKEY_GOST94CC_DECRYPT), "pkey_GOST94cc_decrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST94CC_ENCRYPT), "pkey_GOST94cc_encrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST94CP_DECRYPT), "pkey_GOST94cp_decrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST94CP_ENCRYPT), "pkey_GOST94cp_encrypt"}, +{ERR_FUNC(GOST_F_PKEY_GOST94_KEYGEN), "PKEY_GOST94_KEYGEN"}, +{ERR_FUNC(GOST_F_PKEY_GOST_CTRL), "PKEY_GOST_CTRL"}, +{ERR_FUNC(GOST_F_PKEY_GOST_CTRL01_STR), "PKEY_GOST_CTRL01_STR"}, +{ERR_FUNC(GOST_F_PKEY_GOST_CTRL94_STR), "PKEY_GOST_CTRL94_STR"}, +{ERR_FUNC(GOST_F_PRIV_DECODE_GOST_94), "PRIV_DECODE_GOST_94"}, +{ERR_FUNC(GOST_F_PUB_DECODE_GOST01), "PUB_DECODE_GOST01"}, +{ERR_FUNC(GOST_F_PUB_DECODE_GOST94), "PUB_DECODE_GOST94"}, +{ERR_FUNC(GOST_F_PUB_ENCODE_GOST01), "PUB_ENCODE_GOST01"}, +{ERR_FUNC(GOST_F_UNPACK_CC_SIGNATURE), "UNPACK_CC_SIGNATURE"}, +{ERR_FUNC(GOST_F_UNPACK_CP_SIGNATURE), "UNPACK_CP_SIGNATURE"}, +{0,NULL} + }; + +static ERR_STRING_DATA GOST_str_reasons[]= + { +{ERR_REASON(GOST_R_BAD_KEY_PARAMETERS_FORMAT),"bad key parameters format"}, +{ERR_REASON(GOST_R_BAD_PKEY_PARAMETERS_FORMAT),"bad pkey parameters format"}, +{ERR_REASON(GOST_R_CANNOT_PACK_EPHEMERAL_KEY),"cannot pack ephemeral key"}, +{ERR_REASON(GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT),"ctx not initialized for encrypt"}, +{ERR_REASON(GOST_R_ERROR_COMPUTING_MAC) ,"error computing mac"}, +{ERR_REASON(GOST_R_ERROR_COMPUTING_SHARED_KEY),"error computing shared key"}, +{ERR_REASON(GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO),"error packing key transport info"}, +{ERR_REASON(GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO),"error parsing key transport info"}, +{ERR_REASON(GOST_R_ERROR_STORING_ENCRYPTED_KEY),"error storing encrypted key"}, +{ERR_REASON(GOST_R_ERROR_STORING_IV) ,"error storing iv"}, +{ERR_REASON(GOST_R_ERROR_STORING_MAC) ,"error storing mac"}, +{ERR_REASON(GOST_R_INCOMPATIBLE_ALGORITHMS),"incompatible algorithms"}, +{ERR_REASON(GOST_R_INVALID_CIPHER_PARAMS),"invalid cipher params"}, +{ERR_REASON(GOST_R_INVALID_CIPHER_PARAM_OID),"invalid cipher param oid"}, +{ERR_REASON(GOST_R_INVALID_DIGEST_TYPE) ,"invalid digest type"}, +{ERR_REASON(GOST_R_INVALID_ENCRYPTED_KEY_SIZE),"invalid encrypted key size"}, +{ERR_REASON(GOST_R_INVALID_GOST94_PARMSET),"invalid gost94 parmset"}, +{ERR_REASON(GOST_R_INVALID_IV_LENGTH) ,"invalid iv length"}, +{ERR_REASON(GOST_R_INVALID_PARAMSET) ,"invalid paramset"}, +{ERR_REASON(GOST_R_KEY_IS_NOT_INITALIZED),"key is not initalized"}, +{ERR_REASON(GOST_R_KEY_IS_NOT_INITIALIZED),"key is not initialized"}, +{ERR_REASON(GOST_R_KEY_PARAMETERS_MISSING),"key parameters missing"}, +{ERR_REASON(GOST_R_MALLOC_FAILURE) ,"malloc failure"}, +{ERR_REASON(GOST_R_NOT_ENOUGH_SPACE_FOR_KEY),"not enough space for key"}, +{ERR_REASON(GOST_R_NO_MEMORY) ,"no memory"}, +{ERR_REASON(GOST_R_NO_PARAMETERS_SET) ,"no parameters set"}, +{ERR_REASON(GOST_R_PUBLIC_KEY_UNDEFINED) ,"public key undefined"}, +{ERR_REASON(GOST_R_RANDOM_GENERATOR_ERROR),"random generator error"}, +{ERR_REASON(GOST_R_RANDOM_GENERATOR_FAILURE),"random generator failure"}, +{ERR_REASON(GOST_R_RANDOM_NUMBER_GENERATOR_FAILED),"random number generator failed"}, +{ERR_REASON(GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH),"session key mac does not match"}, +{ERR_REASON(GOST_R_SIGNATURE_MISMATCH) ,"signature mismatch"}, +{ERR_REASON(GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q),"signature parts greater than q"}, +{ERR_REASON(GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND),"unsupported cipher ctl command"}, +{ERR_REASON(GOST_R_UNSUPPORTED_PARAMETER_SET),"unsupported parameter set"}, +{0,NULL} + }; + +#endif + +#ifdef GOST_LIB_NAME +static ERR_STRING_DATA GOST_lib_name[]= + { +{0 ,GOST_LIB_NAME}, +{0,NULL} + }; +#endif + + +static int GOST_lib_error_code=0; +static int GOST_error_init=1; + +void ERR_load_GOST_strings(void) + { + if (GOST_lib_error_code == 0) + GOST_lib_error_code=ERR_get_next_error_library(); + + if (GOST_error_init) + { + GOST_error_init=0; +#ifndef OPENSSL_NO_ERR + ERR_load_strings(GOST_lib_error_code,GOST_str_functs); + ERR_load_strings(GOST_lib_error_code,GOST_str_reasons); +#endif + +#ifdef GOST_LIB_NAME + GOST_lib_name->error = ERR_PACK(GOST_lib_error_code,0,0); + ERR_load_strings(0,GOST_lib_name); +#endif + } + } + +void ERR_unload_GOST_strings(void) + { + if (GOST_error_init == 0) + { +#ifndef OPENSSL_NO_ERR + ERR_unload_strings(GOST_lib_error_code,GOST_str_functs); + ERR_unload_strings(GOST_lib_error_code,GOST_str_reasons); +#endif + +#ifdef GOST_LIB_NAME + ERR_unload_strings(0,GOST_lib_name); +#endif + GOST_error_init=1; + } + } + +void ERR_GOST_error(int function, int reason, char *file, int line) + { + if (GOST_lib_error_code == 0) + GOST_lib_error_code=ERR_get_next_error_library(); + ERR_PUT_error(GOST_lib_error_code,function,reason,file,line); + } diff --git a/engines/ccgost/e_gost_err.h b/engines/ccgost/e_gost_err.h new file mode 100644 index 0000000000..49f4cd5766 --- /dev/null +++ b/engines/ccgost/e_gost_err.h @@ -0,0 +1,150 @@ +/* ==================================================================== + * Copyright (c) 2001-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_GOST_ERR_H +#define HEADER_GOST_ERR_H + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_GOST_strings(void); +void ERR_unload_GOST_strings(void); +void ERR_GOST_error(int function, int reason, char *file, int line); +#define GOSTerr(f,r) ERR_GOST_error((f),(r),__FILE__,__LINE__) + +/* Error codes for the GOST functions. */ + +/* Function codes. */ +#define GOST_F_DECODE_GOST_ALGOR_PARAMS 131 +#define GOST_F_DECRYPT_CRYPTOCOM_KEY 120 +#define GOST_F_ENCODE_GOST_ALGOR_PARAMS 130 +#define GOST_F_FILL_GOST2001_PARAMS 99 +#define GOST_F_FILL_GOST94_PARAMS 100 +#define GOST_F_GET_ENCRYPTION_PARAMS 101 +#define GOST_F_GOST2001_COMPUTE_PUBLIC 102 +#define GOST_F_GOST2001_DO_SIGN 103 +#define GOST_F_GOST2001_DO_VERIFY 104 +#define GOST_F_GOST89_GET_ASN1_PARAMETERS 105 +#define GOST_F_GOST89_SET_ASN1_PARAMETERS 106 +#define GOST_F_GOST94_COPY_PARAMETERS 107 +#define GOST_F_GOST_CIPHER_CTL 108 +#define GOST_F_GOST_COMPUTE_PUBLIC 109 +#define GOST_F_GOST_DO_SIGN 110 +#define GOST_F_GOST_DO_VERIFY 111 +#define GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001 127 +#define GOST_F_PARAM_COPY_GOST01 132 +#define GOST_F_PARAM_COPY_GOST94 133 +#define GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT 121 +#define GOST_F_PKCS7_GOST94_KEY_TRANSPORT_DECRYPT 122 +#define GOST_F_PKEY_GOST01CC_DECRYPT 128 +#define GOST_F_PKEY_GOST01CC_ENCRYPT 129 +#define GOST_F_PKEY_GOST01CP_ENCRYPT 137 +#define GOST_F_PKEY_GOST01_KEYGEN 112 +#define GOST_F_PKEY_GOST94CC_DECRYPT 125 +#define GOST_F_PKEY_GOST94CC_ENCRYPT 123 +#define GOST_F_PKEY_GOST94CP_DECRYPT 126 +#define GOST_F_PKEY_GOST94CP_ENCRYPT 124 +#define GOST_F_PKEY_GOST94_KEYGEN 113 +#define GOST_F_PKEY_GOST_CTRL 114 +#define GOST_F_PKEY_GOST_CTRL01_STR 115 +#define GOST_F_PKEY_GOST_CTRL94_STR 116 +#define GOST_F_PRIV_DECODE_GOST_94 117 +#define GOST_F_PUB_DECODE_GOST01 136 +#define GOST_F_PUB_DECODE_GOST94 134 +#define GOST_F_PUB_ENCODE_GOST01 135 +#define GOST_F_UNPACK_CC_SIGNATURE 118 +#define GOST_F_UNPACK_CP_SIGNATURE 119 + +/* Reason codes. */ +#define GOST_R_BAD_KEY_PARAMETERS_FORMAT 128 +#define GOST_R_BAD_PKEY_PARAMETERS_FORMAT 129 +#define GOST_R_CANNOT_PACK_EPHEMERAL_KEY 114 +#define GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT 115 +#define GOST_R_ERROR_COMPUTING_MAC 116 +#define GOST_R_ERROR_COMPUTING_SHARED_KEY 117 +#define GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO 118 +#define GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO 119 +#define GOST_R_ERROR_STORING_ENCRYPTED_KEY 120 +#define GOST_R_ERROR_STORING_IV 121 +#define GOST_R_ERROR_STORING_MAC 122 +#define GOST_R_INCOMPATIBLE_ALGORITHMS 130 +#define GOST_R_INVALID_CIPHER_PARAMS 99 +#define GOST_R_INVALID_CIPHER_PARAM_OID 100 +#define GOST_R_INVALID_DIGEST_TYPE 101 +#define GOST_R_INVALID_ENCRYPTED_KEY_SIZE 123 +#define GOST_R_INVALID_GOST94_PARMSET 127 +#define GOST_R_INVALID_IV_LENGTH 102 +#define GOST_R_INVALID_PARAMSET 103 +#define GOST_R_KEY_IS_NOT_INITALIZED 104 +#define GOST_R_KEY_IS_NOT_INITIALIZED 105 +#define GOST_R_KEY_PARAMETERS_MISSING 131 +#define GOST_R_MALLOC_FAILURE 124 +#define GOST_R_NOT_ENOUGH_SPACE_FOR_KEY 125 +#define GOST_R_NO_MEMORY 106 +#define GOST_R_NO_PARAMETERS_SET 107 +#define GOST_R_PUBLIC_KEY_UNDEFINED 132 +#define GOST_R_RANDOM_GENERATOR_ERROR 108 +#define GOST_R_RANDOM_GENERATOR_FAILURE 133 +#define GOST_R_RANDOM_NUMBER_GENERATOR_FAILED 109 +#define GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH 126 +#define GOST_R_SIGNATURE_MISMATCH 110 +#define GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q 111 +#define GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND 112 +#define GOST_R_UNSUPPORTED_PARAMETER_SET 113 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/engines/ccgost/e_gost_err.proto b/engines/ccgost/e_gost_err.proto new file mode 100644 index 0000000000..c57bd1bd8f --- /dev/null +++ b/engines/ccgost/e_gost_err.proto @@ -0,0 +1,61 @@ +/* ==================================================================== + * Copyright (c) 2001-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_GOST_ERR_H +#define HEADER_GOST_ERR_H + +#define GOST_LIB_NAME "GOST engine" +#ifdef __cplusplus + extern "C" { +#endif diff --git a/engines/ccgost/engine.c b/engines/ccgost/engine.c new file mode 100644 index 0000000000..757793b396 --- /dev/null +++ b/engines/ccgost/engine.c @@ -0,0 +1,230 @@ +/********************************************************************** + * engine.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Main file of GOST engine * + * for OpenSSL * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include +#include "e_gost_err.h" +#include "md.h" +#include "crypt.h" +#include "meth.h" + +static const char *engine_gost_id = "gost"; +static const char *engine_gost_name = "Reference implementation of GOST engine"; + +/* Symmetric cipher and digest function registrar */ + +static int gost_ciphers(ENGINE *e, const EVP_CIPHER **cipher, + const int **nids, int nid); + +static int gost_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int ind); + +static int gost_pkey_meths (ENGINE *e, EVP_PKEY_METHOD **pmeth, + const int **nids, int nid); + +static int gost_pkey_asn1_meths (ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth, + const int **nids, int nid); + +static int gost_cipher_nids[] = + {NID_id_Gost28147_89, 0}; + +static int gost_digest_nids[] = + {NID_id_GostR3411_94, 0}; + +static int gost_pkey_meth_nids[] = + {NID_id_GostR3410_94_cc, NID_id_GostR3410_94, NID_id_GostR3410_2001_cc, + NID_id_GostR3410_2001, 0}; + +static EVP_PKEY_METHOD *pmeth_GostR3410_94_cc = NULL, *pmeth_GostR3410_94 = NULL, + *pmeth_GostR3410_2001_cc = NULL, *pmeth_GostR3410_2001 = NULL; + +static EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94_cc = NULL, *ameth_GostR3410_94 = NULL, + *ameth_GostR3410_2001_cc = NULL, *ameth_GostR3410_2001 = NULL; + + +static int gost_engine_init(ENGINE *e) { + return 1; +} +static int gost_engine_finish(ENGINE *e) { + return 1; +} + +static int gost_engine_destroy(ENGINE *e) { + return 1; +} + +static int bind_gost (ENGINE *e,const char *id) { + int ret = 0; + if (id && strcmp(id, engine_gost_id)) return 0; + + if (!ENGINE_set_id(e, engine_gost_id)) { + printf("ENGINE_set_id failed\n"); + goto end; + } + if (!ENGINE_set_name(e, engine_gost_name)) { + printf("ENGINE_set_name failed\n"); + goto end; + } + if (!ENGINE_set_digests(e, gost_digests)) { + printf("ENGINE_set_digests failed\n"); + goto end; + } + if (! ENGINE_set_ciphers(e, gost_ciphers)) { + printf("ENGINE_set_ciphers failed\n"); + goto end; + } + if (! ENGINE_set_pkey_meths(e, gost_pkey_meths)) { + printf("ENGINE_set_pkey_meths failed\n"); + goto end; + } + if (! ENGINE_set_pkey_asn1_meths(e, gost_pkey_asn1_meths)) { + printf("ENGINE_set_pkey_asn1_meths failed\n"); + goto end; + } + if ( ! ENGINE_set_destroy_function(e, gost_engine_destroy) + || ! ENGINE_set_init_function(e,gost_engine_init) + || ! ENGINE_set_finish_function(e,gost_engine_finish)) goto end; + + + + if (!register_ameth_gost(NID_id_GostR3410_94_cc, &ameth_GostR3410_94_cc, "GOST94CC", "GOST R 34.10-94, Cryptocom LTD implementation")) goto end; + if (!register_ameth_gost(NID_id_GostR3410_94, &ameth_GostR3410_94, "GOST94", "GOST R 34.10-94")) goto end; + if (!register_ameth_gost(NID_id_GostR3410_2001_cc, &ameth_GostR3410_2001_cc, "GOST2001CC", "GOST R 34.10-2001, Cryptocom LTD implementation")) goto end; + if (!register_ameth_gost(NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001", "GOST R 34.10-2001")) goto end; + + if (!register_pmeth_gost(NID_id_GostR3410_94_cc, &pmeth_GostR3410_94_cc, 0)) goto end; + if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0)) goto end; + if (!register_pmeth_gost(NID_id_GostR3410_2001_cc, &pmeth_GostR3410_2001_cc, 0)) goto end; + if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0)) goto end; + if ( ! ENGINE_register_ciphers(e) + || ! ENGINE_register_digests(e) + || ! ENGINE_register_pkey_meths(e) + /* These two actually should go in LIST_ADD command */ + || ! EVP_add_cipher(&cipher_gost) + || ! EVP_add_digest(&digest_gost) + ) goto end; + + ERR_load_GOST_strings(); + ret = 1; +end: + return ret; +} + +#ifdef _WIN32 +extern __declspec( dllexport ) +#endif + +//#ifndef OPENSSL_NO_DYNAMIC_ENGINE +IMPLEMENT_DYNAMIC_BIND_FN(bind_gost); + +#ifdef _WIN32 +extern __declspec( dllexport ) +#endif + +IMPLEMENT_DYNAMIC_CHECK_FN(); +//#else +static ENGINE *engine_gost(void) + { + ENGINE *ret = ENGINE_new(); + if(!ret) + return NULL; + if(!bind_gost(ret, engine_gost_id)) + { + ENGINE_free(ret); + return NULL; + } + return ret; + } + +void ENGINE_load_gost(void) + { + /* Copied from eng_[openssl|dyn].c */ + ENGINE *toadd = engine_gost(); + if(!toadd) return; + ENGINE_add(toadd); + ENGINE_free(toadd); + ERR_clear_error(); + } +//#endif /* OPENSSL_NO_DYNAMIC_ENGINE */ + +static int gost_digests(ENGINE *e, const EVP_MD **digest, + const int **nids, int nid) +{ + int ok =1 ; + if (!digest) { + *nids = gost_digest_nids; + return 1; + } + //printf("Digest no %d requested\n",nid); + if(nid == NID_id_GostR3411_94) { + *digest = &digest_gost; + } else { + ok =0; + *digest = NULL; + } + return ok; +} + +static int gost_ciphers (ENGINE *e,const EVP_CIPHER **cipher, + const int **nids, int nid) { + int ok = 1; + if (!cipher) { + *nids = gost_cipher_nids; + return 1; /* Only one cipher supported */ + } + + if(nid == NID_id_Gost28147_89) { + *cipher = &cipher_gost; + } else { + ok = 0; + *cipher = NULL; + } + return ok; +} + +static int gost_pkey_meths (ENGINE *e, EVP_PKEY_METHOD **pmeth, + const int **nids, int nid) +{ + if (!pmeth) { + *nids = gost_pkey_meth_nids; + return 4; + } + + switch (nid) { + case NID_id_GostR3410_94_cc: *pmeth = pmeth_GostR3410_94_cc; return 1; + case NID_id_GostR3410_94: *pmeth = pmeth_GostR3410_94; return 1; + case NID_id_GostR3410_2001_cc: *pmeth = pmeth_GostR3410_2001_cc; return 1; + case NID_id_GostR3410_2001: *pmeth = pmeth_GostR3410_2001; return 1; + default:; + } + + *pmeth = NULL; + return 0; +} + +static int gost_pkey_asn1_meths (ENGINE *e, EVP_PKEY_ASN1_METHOD **ameth, + const int **nids, int nid) +{ + if (!ameth) { + *nids = gost_pkey_meth_nids; + return 4; + } + switch (nid) { + case NID_id_GostR3410_94_cc: *ameth = ameth_GostR3410_94_cc; return 1; + case NID_id_GostR3410_94: *ameth = ameth_GostR3410_94; return 1; + case NID_id_GostR3410_2001_cc: *ameth = ameth_GostR3410_2001_cc; return 1; + case NID_id_GostR3410_2001: *ameth = ameth_GostR3410_2001; return 1; + default:; + } + + *ameth = NULL; + return 0; +} diff --git a/engines/ccgost/gost.ec b/engines/ccgost/gost.ec new file mode 100644 index 0000000000..6c2c85e57c --- /dev/null +++ b/engines/ccgost/gost.ec @@ -0,0 +1,5 @@ +L GOST e_gost_err.h e_gost_err.c +L NONE asymm.h NONE +L NONE md.h NONE +L NONE crypt.h NONE +L NONE gostkeyx.h NONE diff --git a/engines/ccgost/gost2001.c b/engines/ccgost/gost2001.c new file mode 100644 index 0000000000..c53bd6c7c5 --- /dev/null +++ b/engines/ccgost/gost2001.c @@ -0,0 +1,324 @@ +/********************************************************************** + * gost2001.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of GOST R 34.10-2001 * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include "tools.h" +#include "sign.h" +#include "paramset.h" +#include +#include +#include +#include +#include "e_gost_err.h" +#ifdef DEBUG_SIGN +extern +void dump_signature(const char *message,const unsigned char *buffer,size_t len); +void dump_dsa_sig(const char *message, DSA_SIG *sig); +#else + +#define dump_signature(a,b,c) +#define dump_dsa_sig(a,b) +#endif + +/* + * Fills EC_KEY structure hidden in the app_data field of DSA structure + * with parameter information, extracted from parameter array in + * params.c file. + * + * Also fils DSA->q field with copy of EC_GROUP order field to make + * DSA_size function work + */ +int fill_GOST2001_params(EC_KEY *eckey, int nid) { + R3410_2001_params *params = R3410_2001_paramset; + EC_GROUP *grp; + BIGNUM *p=NULL,*q=NULL,*a=NULL,*b=NULL,*x=NULL,*y=NULL; + EC_POINT *P=NULL; + BN_CTX *ctx=BN_CTX_new(); + int ok=0; + + BN_CTX_start(ctx); + p=BN_CTX_get(ctx); + a=BN_CTX_get(ctx); + b=BN_CTX_get(ctx); + x=BN_CTX_get(ctx); + y=BN_CTX_get(ctx); + q=BN_CTX_get(ctx); + while (params->nid!=NID_undef && params->nid != nid) params++; + if (params->nid == NID_undef) { + GOSTerr(GOST_F_FILL_GOST2001_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET); + goto err; + } + BN_hex2bn(&p,params->p); + BN_hex2bn(&a,params->a); + BN_hex2bn(&b,params->b); + + grp = EC_GROUP_new_curve_GFp(p,a,b,ctx); + + P = EC_POINT_new(grp); + + BN_hex2bn(&x,params->x); + BN_hex2bn(&y,params->y); + EC_POINT_set_affine_coordinates_GFp(grp,P,x,y,ctx); + BN_hex2bn(&q,params->q); +#ifdef DEBUG_KEYS + fprintf(stderr,"Set params index %d oid %s\nq=", + (params-R3410_2001_paramset),OBJ_nid2sn(params->nid)); + BN_print_fp(stderr,q); + fprintf(stderr,"\n"); +#endif + + EC_GROUP_set_generator(grp,P,q,NULL); + EC_GROUP_set_curve_name(grp,params->nid); + + EC_KEY_set_group(eckey,grp); + ok=1; +err: + EC_POINT_free(P); + EC_GROUP_free(grp); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ok; + +} + + +/* + * Computes gost2001 signature as DSA_SIG structure + * + * + */ +DSA_SIG *gost2001_do_sign(const unsigned char *dgst,int dlen, EC_KEY *eckey) { + DSA_SIG *newsig = NULL; + BIGNUM *md = hashsum2bn(dgst); + BIGNUM *order = NULL; + const EC_GROUP *group; + const BIGNUM *priv_key; + BIGNUM *r=NULL,*s=NULL,*X=NULL,*tmp=NULL,*tmp2=NULL, *k=NULL,*e=NULL; + EC_POINT *C=NULL; + BN_CTX *ctx = BN_CTX_new(); + BN_CTX_start(ctx); + OPENSSL_assert(dlen==32); + newsig=DSA_SIG_new(); + if (!newsig) + { + GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_NO_MEMORY); + goto err; + } + group = EC_KEY_get0_group(eckey); + order=BN_CTX_get(ctx); + EC_GROUP_get_order(group,order,ctx); + priv_key = EC_KEY_get0_private_key(eckey); + e = BN_CTX_get(ctx); + BN_mod(e,md,order,ctx); +#ifdef DEBUG_SIGN + fprintf(stderr,"digest as bignum="); + BN_print_fp(stderr,md); + fprintf(stderr,"\ndigest mod q="); + BN_print_fp(stderr,e); + fprintf(stderr,"\n"); +#endif + if (BN_is_zero(e)) + { + BN_one(e); + } + k =BN_CTX_get(ctx); + C=EC_POINT_new(group); + do { + do { + if (!BN_rand_range(k,order)) + { + GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); + DSA_SIG_free(newsig); + goto err; + } + if (!EC_POINT_mul(group,C,k,NULL,NULL,ctx)) { + GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB); + DSA_SIG_free(newsig); + goto err; + } + if (!X) X=BN_CTX_get(ctx); + if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx)) { + GOSTerr(GOST_F_GOST2001_DO_SIGN,ERR_R_EC_LIB); + DSA_SIG_free(newsig); + goto err; + } + if (!r) r=BN_CTX_get(ctx); + BN_nnmod(r,X,order,ctx); + } while (BN_is_zero(r)); + /* s = (r*priv_key+k*e) mod order */ + if (!tmp) tmp = BN_CTX_get(ctx); + BN_mod_mul(tmp,priv_key,r,order,ctx); + if (!tmp2) tmp2 = BN_CTX_get(ctx); + BN_mod_mul(tmp2,k,e,order,ctx); + if (!s) s=BN_CTX_get(ctx); + BN_mod_add(s,tmp,tmp2,order,ctx); + } while (BN_is_zero(s)); + + newsig->s=BN_dup(s); + newsig->r=BN_dup(r); +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + EC_POINT_free(C); + BN_free(md); + return newsig; +} +/* + * Verifies gost 2001 signature + * + */ +int gost2001_do_verify(const unsigned char *dgst,int dgst_len, + DSA_SIG *sig, EC_KEY *ec) { + BN_CTX *ctx=BN_CTX_new(); + const EC_GROUP *group = EC_KEY_get0_group(ec); + BIGNUM *order; + BIGNUM *md = NULL,*e=NULL,*R=NULL,*v=NULL,*z1=NULL,*z2=NULL; + BIGNUM *X=NULL,*tmp=NULL; + EC_POINT *C = NULL; + const EC_POINT *pub_key=NULL; + int ok=0; + + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + e = BN_CTX_get(ctx); + z1 = BN_CTX_get(ctx); + z2 = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + X= BN_CTX_get(ctx); + R=BN_CTX_get(ctx); + v=BN_CTX_get(ctx); + + EC_GROUP_get_order(group,order,ctx); + pub_key = EC_KEY_get0_public_key(ec); + if (BN_is_zero(sig->s) || BN_is_zero(sig->r) || + (BN_cmp(sig->s,order)>=1) || (BN_cmp(sig->r,order)>=1)) + { + GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); + goto err; + + } + md = hashsum2bn(dgst); + + BN_mod(e,md,order,ctx); +#ifdef DEBUG_SIGN + fprintf(stderr,"digest as bignum: "); + BN_print_fp(stderr,md); + fprintf(stderr,"\ndigest mod q: "); + BN_print_fp(stderr,e); +#endif + if (BN_is_zero(e)) BN_one(e); + v=BN_mod_inverse(v,e,order,ctx); + BN_mod_mul(z1,sig->s,v,order,ctx); + BN_sub(tmp,order,sig->r); + BN_mod_mul(z2,tmp,v,order,ctx); +#ifdef DEBUG_SIGN + fprintf(stderr,"\nInverted digest value: "); + BN_print_fp(stderr,v); + fprintf(stderr,"\nz1: "); + BN_print_fp(stderr,z1); + fprintf(stderr,"\nz2: "); + BN_print_fp(stderr,z2); +#endif + C = EC_POINT_new(group); + if (!EC_POINT_mul(group,C,z1,pub_key,z2,ctx)) + { + GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_get_affine_coordinates_GFp(group,C,X,NULL,ctx)) + { + GOSTerr(GOST_F_GOST2001_DO_VERIFY,ERR_R_EC_LIB); + goto err; + } + BN_mod(R,X,order,ctx); +#ifdef DEBUG_SIGN + fprintf(stderr,"\nX="); + BN_print_fp(stderr,X); + fprintf(stderr,"\nX mod q="); + BN_print_fp(stderr,R); + fprintf(stderr,"\n"); +#endif + if (BN_cmp(R,sig->r)!=0) { + GOSTerr(GOST_F_GOST2001_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH); + } else { + ok = 1; + } +err: + EC_POINT_free(C); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + BN_free(md); + return ok; +} +/* + * Computes GOST R 34.10-2001 public key + * + * + */ +int gost2001_compute_public(EC_KEY *ec) +{ + const EC_GROUP *group = EC_KEY_get0_group(ec); + EC_POINT *pub_key=NULL; + const BIGNUM *priv_key=NULL; + BN_CTX *ctx=NULL; + int ok=0; + + if (!group) { + GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITIALIZED); + return 0; + } + ctx=BN_CTX_new(); + BN_CTX_start(ctx); + if (!(priv_key=EC_KEY_get0_private_key(ec))) + { + GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB); + goto err; + } + + pub_key = EC_POINT_new(group); + if (!EC_POINT_mul(group,pub_key,priv_key,NULL,NULL,ctx)) + { + GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB); + goto err; + } + if (!EC_KEY_set_public_key(ec,pub_key)) { + GOSTerr(GOST_F_GOST2001_COMPUTE_PUBLIC,ERR_R_EC_LIB); + goto err; + } + ok = 256; +err: + BN_CTX_end(ctx); + EC_POINT_free(pub_key); + BN_CTX_free(ctx); + return ok; +} +/* + * + * Generates GOST R 34.10-2001 keypair + * + * + */ +int gost2001_keygen(EC_KEY *ec) { + BIGNUM *order = BN_new(),*d=BN_new(); + const EC_GROUP *group = EC_KEY_get0_group(ec); + EC_GROUP_get_order(group,order,NULL); + + do { + if (!BN_rand_range(d,order)) + { + GOSTerr(GOST_F_GOST2001_DO_SIGN,GOST_R_RANDOM_NUMBER_GENERATOR_FAILED); + BN_free(d); + BN_free(order); + return 0; + } + } while (BN_is_zero(d)); + EC_KEY_set_private_key(ec,d); + BN_free(d); + BN_free(order); + return gost2001_compute_public(ec); +} + diff --git a/engines/ccgost/gost2001_keyx.c b/engines/ccgost/gost2001_keyx.c new file mode 100644 index 0000000000..120ec69d3c --- /dev/null +++ b/engines/ccgost/gost2001_keyx.c @@ -0,0 +1,385 @@ +/********************************************************************** + * gost_keyx.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * VK0 34.10-2001 key exchange and GOST R 34.10-2001 * + * based PKCS7/SMIME support * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include +#include "gost89.h" +#include "gosthash.h" +#include "gost_asn1.h" +#include "e_gost_err.h" +#include "keywrap.h" +#include "crypt.h" +#include "sign.h" +#include "pmeth.h" +#include "tools.h" +#include "gostkeyx.h" + +/* Transform ECDH shared key into little endian as required by Cryptocom + * key exchange */ +static void *make_key_le(const void *in, size_t inlen, void *out, size_t *outlen) { + const char* inbuf= in; + char* outbuf= out; + int i; + if (*outlen < inlen) { + return NULL; + } + for (i=0;ieph_seckey)); + if (!ephemeral) goto err; + /* compute shared key */ + pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)); + if (!ECDH_compute_key(shared_key,32,pub_key_point,ephemeral,make_key_le)) + { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); + goto err; + } + /* encrypt session key */ + gost_init(&ctx, &GostR3411_94_CryptoProParamSet); + gost_key(&ctx,shared_key); + encrypt_cryptocom_key(key,key_len,encrypted_key,&ctx); + /* compute hmac of session key */ + if (!gost_mac(&ctx,32,key,32,hmac)) + { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC); + return -1; + } + gkt = GOST_KEY_TRANSPORT_new(); + if (!gkt) + { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_NO_MEMORY); + return -1; + } + /* Store IV which is always zero in our case */ + if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8)) + { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_IV); + goto err; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4)) + { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_MAC); + goto err; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32)) + { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY); + goto err; + } + + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) { + GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); + goto err; + } + ASN1_OBJECT_free(gkt->key_agreement_info->cipher); + gkt->key_agreement_info->cipher = OBJ_nid2obj(NID_id_Gost28147_89_cc); + if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret = 1; + ; +err: + if (gkt) GOST_KEY_TRANSPORT_free(gkt); + return ret; +} +/* + * EVP_PKEY_METHOD callback decrypt + * Implementation of GOST2001 key transport, cryptocom variation + */ +int pkey_GOST01cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len) { + /* Form DH params from compute shared key */ + EVP_PKEY *priv=EVP_PKEY_CTX_get0_pkey(pctx); + GOST_KEY_TRANSPORT *gkt = NULL; + const unsigned char *p=in; + unsigned char shared_key[32]; + unsigned char hmac[4],hmac_comp[4]; + unsigned char iv[8]; + int i; + gost_ctx ctx; + const EC_POINT *pub_key_point; + EVP_PKEY *eph_key; + + if (!key) { + *key_len = 32; + return 1; + } + /* Parse passed octet string and find out public key, iv and HMAC*/ + gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, + in_len); + if (!gkt) { + GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); + return 0; + } + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + /* Initialization vector is really ignored here */ + OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); + memcpy(iv,gkt->key_agreement_info->eph_iv->data,8); + /* HMAC should be computed and checked */ + OPENSSL_assert(gkt->key_info->imit->length==4); + memcpy(hmac,gkt->key_info->imit->data,4); + /* Compute shared key */ + pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key)); + i=ECDH_compute_key(shared_key,32,pub_key_point,EVP_PKEY_get0(priv),make_key_le); + EVP_PKEY_free(eph_key); + if (!i) + { + GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); + GOST_KEY_TRANSPORT_free(gkt); + return 0; + } + /* Decrypt session key */ + gost_init(&ctx, &GostR3411_94_CryptoProParamSet); + gost_key(&ctx,shared_key); + + if (!decrypt_cryptocom_key(key,*key_len,gkt->key_info->encrypted_key->data, + gkt->key_info->encrypted_key->length, &ctx)) + { + GOST_KEY_TRANSPORT_free(gkt); + return 0; + } + GOST_KEY_TRANSPORT_free(gkt); + /* check HMAC of session key*/ + if (!gost_mac(&ctx,32,key,32,hmac_comp)) { + GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_ERROR_COMPUTING_MAC); + return 0; + } + /* HMAC of session key is not correct */ + if (memcmp(hmac,hmac_comp,4)!=0) { + GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH); + return 0; + } + return 1; +} + +/* Implementation of CryptoPro VKO 34.10-2001 algorithm */ +static int VKO_compute_key(unsigned char *shared_key,size_t shared_key_size,const EC_POINT *pub_key,EC_KEY *priv_key,const unsigned char *ukm) { + unsigned char ukm_be[8],databuf[64],hashbuf[64]; + BIGNUM *UKM=NULL,*p=NULL,*order=NULL,*X=NULL,*Y=NULL; + const BIGNUM* key=EC_KEY_get0_private_key(priv_key); + EC_POINT *pnt=EC_POINT_new(EC_KEY_get0_group(priv_key)); + int i; + gost_hash_ctx hash_ctx; + BN_CTX *ctx = BN_CTX_new(); + + for (i=0;i<8;i++) { + ukm_be[7-i]=ukm[i]; + } + BN_CTX_start(ctx); + UKM=getbnfrombuf(ukm_be,8); + p=BN_CTX_get(ctx); + order = BN_CTX_get(ctx); + X=BN_CTX_get(ctx); + Y=BN_CTX_get(ctx); + EC_GROUP_get_order(EC_KEY_get0_group(priv_key),order,ctx); + BN_mod_mul(p,key,UKM,order,ctx); + EC_POINT_mul(EC_KEY_get0_group(priv_key),pnt,NULL,pub_key,p,ctx); + EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(priv_key), + pnt,X,Y,ctx); + /*Serialize elliptic curve point same way as we do it when saving + * key */ + store_bignum(Y,databuf,32); + store_bignum(X,databuf+32,32); + /* And reverse byte order of whole buffer */ + for (i=0;i<64;i++) { + hashbuf[63-i]=databuf[i]; + } + init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet); + start_hash(&hash_ctx); + hash_block(&hash_ctx,hashbuf,64); + finish_hash(&hash_ctx,shared_key); + done_gost_hash_ctx(&hash_ctx); + BN_free(UKM); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + EC_POINT_free(pnt); + return 32; +} + +/* Generates ephemeral key based on pubk algorithm + * computes shared key using VKO and returns filled up + * GOST_KEY_TRANSPORT structure + */ +/* Public, because it would be needed in SSL implementation */ +GOST_KEY_TRANSPORT *make_rfc4490_keytransport_2001(EVP_PKEY *pubk,BIGNUM *eph_key, + const unsigned char *key,size_t keylen, unsigned char *ukm, + size_t ukm_len) +{ + + const struct gost_cipher_info *param=get_encryption_params(NULL); + EC_KEY *ephemeral = NULL; + GOST_KEY_TRANSPORT *gkt=NULL; + const EC_POINT *pub_key_point = EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)); + unsigned char shared_key[32],crypted_key[44]; + gost_ctx ctx; + EVP_PKEY *newkey=NULL; + + /* Do not use vizir cipher parameters with cryptopro */ + if (!getenv("CRYPT_PARAMS") && param == gost_cipher_list) { + param= gost_cipher_list+1; + } + ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk),eph_key); + VKO_compute_key(shared_key,32,pub_key_point,ephemeral,ukm); + gost_init(&ctx,param->sblock); + keyWrapCryptoPro(&ctx,shared_key,ukm,key,crypted_key); + gkt = GOST_KEY_TRANSPORT_new(); + if (!gkt) { + goto memerr; + } + if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, + ukm,8)) { + goto memerr; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) { + goto memerr; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) { + goto memerr; + } + newkey = ec_ephemeral_key_to_EVP(pubk,NID_id_GostR3410_2001,ephemeral); + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,newkey)) { + GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); + goto err; + } + ASN1_OBJECT_free(gkt->key_agreement_info->cipher); + gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid); + EVP_PKEY_free(newkey); + return gkt; +memerr: + GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001, + GOST_R_MALLOC_FAILURE); +err: + GOST_KEY_TRANSPORT_free(gkt); + return NULL; +} + +/* + * EVP_PKEY_METHOD callback encrypt + * Implementation of GOST2001 key transport, cryptopo variation + */ + +int pkey_GOST01cp_encrypt (EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len, const unsigned char *key,size_t key_len) +{ + GOST_KEY_TRANSPORT *gkt=NULL; + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx); + unsigned char ukm[8]; + int ret=0; + if (RAND_bytes(ukm,8)<=0) { + GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, + GOST_R_RANDOM_GENERATOR_FAILURE); + return 0; + } + + if (!(gkt=make_rfc4490_keytransport_2001(pubk,gost_get_priv_key(data->eph_seckey),key, key_len,ukm,8))) { + goto err; + } + if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret =1; + GOST_KEY_TRANSPORT_free(gkt); + return ret; +err: + GOST_KEY_TRANSPORT_free(gkt); + return -1; +} +/* Public, because it would be needed in SSL implementation */ +int decrypt_rfc4490_shared_key_2001(EVP_PKEY *priv,GOST_KEY_TRANSPORT *gkt, + unsigned char *key_buf,int key_buf_len) +{ + unsigned char wrappedKey[44]; + unsigned char sharedKey[32]; + gost_ctx ctx; + const struct gost_cipher_info *param=NULL; + EVP_PKEY *eph_key=NULL; + + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + param = get_encryption_params(gkt->key_agreement_info->cipher); + gost_init(&ctx,param->sblock); + OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); + memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8); + OPENSSL_assert(gkt->key_info->encrypted_key->length==32); + memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32); + OPENSSL_assert(gkt->key_info->imit->length==4); + memcpy(wrappedKey+40,gkt->key_info->imit->data,4); + VKO_compute_key(sharedKey,32,EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key)), + EVP_PKEY_get0(priv),wrappedKey); + if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key_buf)) { + GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT, + GOST_R_ERROR_COMPUTING_SHARED_KEY); + goto err; + } + + EVP_PKEY_free(eph_key); + return 32; +err: + EVP_PKEY_free(eph_key); + return -1; +} +/* + * EVP_PKEY_METHOD callback decrypt + * Implementation of GOST2001 key transport, cryptopo variation + */ +int pkey_GOST01cp_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_len, const unsigned char *in, size_t in_len) { + const unsigned char *p = in; + EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx); + GOST_KEY_TRANSPORT *gkt = NULL; + int ret=0; + + if (!key) { + *key_len = 32; + return 1; + } + gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, + in_len); + if (!gkt) { + GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); + return -1; + } + ret = decrypt_rfc4490_shared_key_2001(priv,gkt,key,*key_len); + GOST_KEY_TRANSPORT_free(gkt); + return ret; +} diff --git a/engines/ccgost/gost89.c b/engines/ccgost/gost89.c new file mode 100644 index 0000000000..03675724cc --- /dev/null +++ b/engines/ccgost/gost89.c @@ -0,0 +1,383 @@ +/********************************************************************** + * gost89.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of GOST 28147-89 encryption algorithm * + * No OpenSSL libraries required to compile and use * + * this code * + **********************************************************************/ +#include +#include "gost89.h" +/* Substitution blocks from RFC 4357 + + Note: our implementation of gost 28147-89 algorithm + uses S-box matrix rotated 90 degrees counterclockwise, relative to + examples given in RFC. + + +*/ + +/* Substitution blocks from test examples for GOST R 34.11-94*/ +gost_subst_block GostR3411_94_TestParamSet = { + {0X1,0XF,0XD,0X0,0X5,0X7,0XA,0X4,0X9,0X2,0X3,0XE,0X6,0XB,0X8,0XC}, + {0XD,0XB,0X4,0X1,0X3,0XF,0X5,0X9,0X0,0XA,0XE,0X7,0X6,0X8,0X2,0XC}, + {0X4,0XB,0XA,0X0,0X7,0X2,0X1,0XD,0X3,0X6,0X8,0X5,0X9,0XC,0XF,0XE}, + {0X6,0XC,0X7,0X1,0X5,0XF,0XD,0X8,0X4,0XA,0X9,0XE,0X0,0X3,0XB,0X2}, + {0X7,0XD,0XA,0X1,0X0,0X8,0X9,0XF,0XE,0X4,0X6,0XC,0XB,0X2,0X5,0X3}, + {0X5,0X8,0X1,0XD,0XA,0X3,0X4,0X2,0XE,0XF,0XC,0X7,0X6,0X0,0X9,0XB}, + {0XE,0XB,0X4,0XC,0X6,0XD,0XF,0XA,0X2,0X3,0X8,0X1,0X0,0X7,0X5,0X9}, + {0X4,0XA,0X9,0X2,0XD,0X8,0X0,0XE,0X6,0XB,0X1,0XC,0X7,0XF,0X5,0X3} +}; +/* Substitution blocks for hash function 1.2.643.2.9.1.6.1 */ +gost_subst_block GostR3411_94_CryptoProParamSet= { + {0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC}, + {0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB}, + {0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3}, + {0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5}, + {0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3}, + {0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD}, + {0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8}, + {0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF} +} ; + +/* Test paramset from GOST 28147 */ +gost_subst_block Gost28147_TestParamSet = +{ + {0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8}, + {0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD}, + {0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4}, + {0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4}, + {0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8}, + {0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB}, + {0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5}, + {0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6} +}; + + + + +/* 1.2.643.2.2.31.1 */ +gost_subst_block Gost28147_CryptoProParamSetA= { + {0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4}, + {0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE}, + {0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6}, + {0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6}, + {0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6}, + {0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9}, + {0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1}, + {0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5} +}; +/* 1.2.643.2.2.31.2 */ +gost_subst_block Gost28147_CryptoProParamSetB= +{ + {0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC}, + {0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE}, + {0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5}, + {0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3}, + {0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8}, + {0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4}, + {0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE}, + {0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF} +}; +/* 1.2.643.2.2.31.3 */ +gost_subst_block Gost28147_CryptoProParamSetC= +{ + {0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8}, + {0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7}, + {0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD}, + {0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7}, + {0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4}, + {0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB}, + {0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3}, + {0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3} +}; + +/* 1.2.643.2.2.31.4 */ +gost_subst_block Gost28147_CryptoProParamSetD= +{ + {0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE}, + {0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7}, + {0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6}, + {0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1}, + {0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8}, + {0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2}, + {0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1}, + {0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3} +}; + + +const byte CryptoProKeyMeshingKey[]={ + 0x69, 0x00, 0x72, 0x22, 0x64, 0xC9, 0x04, 0x23, + 0x8D, 0x3A, 0xDB, 0x96, 0x46, 0xE9, 0x2A, 0xC4, + 0x18, 0xFE, 0xAC, 0x94, 0x00, 0xED, 0x07, 0x12, + 0xC0, 0x86, 0xDC, 0xC2, 0xEF, 0x4C, 0xA9, 0x2B +}; +/* Initialization of gost_ctx subst blocks*/ +void kboxinit(gost_ctx *c, const gost_subst_block *b) { + int i; + + for (i = 0; i < 256; i++) { + c->k87[i] = (b->k8[i>>4] <<4 | b->k7 [i &15])<<24; + c->k65[i] = (b->k6[i>>4] << 4 | b->k5 [i &15])<<16; + c->k43[i] = (b->k4[i>>4] <<4 | b->k3 [i &15])<<8; + c->k21[i] = b->k2[i>>4] <<4 | b->k1 [i &15]; + + } +} + +/* Part of GOST 28147 algorithm moved into separate function */ +static word32 +f(gost_ctx *c,word32 x) +{ x = c->k87[x>>24 & 255] | c->k65[x>>16 & 255]| + c->k43[x>> 8 & 255] | c->k21[x & 255]; + /* Rotate left 11 bits */ + return x<<11 | x>>(32-11); +} +/* Low-level encryption routine - encrypts one 64 bit block*/ +void gostcrypt(gost_ctx *c, const byte *in, byte *out) +{ + register word32 n1, n2; /* As named in the GOST */ + n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); + n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24); + /* Instead of swapping halves, swap names each round */ + + n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); + n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); + n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); + n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); + + n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); + n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); + n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); + n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); + + n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); + n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); + n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); + n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); + + n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]); + n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]); + n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]); + n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]); + + out[0] = (n2&0xff); out[1] = (n2>>8)&0xff; out[2]=(n2>>16)&0xff; out[3]=n2>>24; + out[4] = (n1&0xff); out[5] = (n1>>8)&0xff; out[6]=(n1>>16)&0xff; out[7]=n1>>24; +} +/* Low-level decryption routine. Decrypts one 64-bit block */ +void gostdecrypt(gost_ctx *c, const byte *in,byte *out) +{ + register word32 n1, n2; /* As named in the GOST */ + n1 = in[0]|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); + n2 = in[4]|(in[5]<<8)|(in[6]<<16)|(in[7]<<24); + + n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); + n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); + n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); + n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); + + n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]); + n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]); + n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]); + n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]); + + n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]); + n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]); + n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]); + n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]); + + n2 ^= f(c,n1+c->k[7]); n1 ^= f(c,n2+c->k[6]); + n2 ^= f(c,n1+c->k[5]); n1 ^= f(c,n2+c->k[4]); + n2 ^= f(c,n1+c->k[3]); n1 ^= f(c,n2+c->k[2]); + n2 ^= f(c,n1+c->k[1]); n1 ^= f(c,n2+c->k[0]); + out[0] = (n2&0xff); out[1] = (n2>>8)&0xff; out[2]=(n2>>16)&0xff; out[3]=n2>>24; + out[4] = (n1&0xff); out[5] = (n1>>8)&0xff; out[6]=(n1>>16)&0xff; out[7]=n1>>24; +} + +/* Encrypts several blocks in ECB mode */ +void gost_enc(gost_ctx *c,const byte *clear,byte *cipher, int blocks) +{ + int i; + for(i=0;ik[i]=k[j]|(k[j+1]<<8)|(k[j+2]<<16)|(k[j+3]<<24); + } +} +/* Retrieve 256-bit key from context */ +void gost_get_key(gost_ctx *c, byte *k) +{ + int i,j; + for(i=0,j=0;i<8;i++,j+=4) { + k[j]=c->k[i]& 0xFF; + k[j+1]=(c->k[i]>>8 )&0xFF; + k[j+2]=(c->k[i]>>16) &0xFF; + k[j+3]=(c->k[i]>>24) &0xFF; + } + +} +/* Initalize context. Provides default value for subst_block */ +void gost_init(gost_ctx *c, const gost_subst_block *b) +{ + if(!b) { + b=&GostR3411_94_TestParamSet; + } + kboxinit(c,b); +} +/* Cleans up key from context */ +void gost_destroy(gost_ctx *c) +{ + int i; for(i=0;i<8;i++) c->k[i]=0; +} + +/* Compute GOST 28147 mac block + * + * Parameters + * gost_ctx *c - context initalized with substitution blocks and key + * buffer - 8-byte mac state buffer + * block 8-byte block to process. + * */ +void mac_block(gost_ctx *c,byte *buffer,const byte *block) { + + register word32 n1, n2; /* As named in the GOST */ + int i; + for (i=0; i<8; i++) { + buffer[i]^=block[i]; + } + n1 = buffer[0]|(buffer[1]<<8)|(buffer[2]<<16)|(buffer[3]<<24); + n2 = buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24); + /* Instead of swapping halves, swap names each round */ + + n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); + n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); + n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); + n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); + + n2 ^= f(c,n1+c->k[0]); n1 ^= f(c,n2+c->k[1]); + n2 ^= f(c,n1+c->k[2]); n1 ^= f(c,n2+c->k[3]); + n2 ^= f(c,n1+c->k[4]); n1 ^= f(c,n2+c->k[5]); + n2 ^= f(c,n1+c->k[6]); n1 ^= f(c,n2+c->k[7]); + + buffer[0] = (n1&0xff); buffer[1] = (n1>>8)&0xff; buffer[2]=(n1>>16)&0xff; buffer[3]=n1>>24; + buffer[4] = (n2&0xff); buffer[5] = (n2>>8)&0xff; buffer[6]=(n2>>16)&0xff; buffer[7]=n2>>24; +} + +/* Get mac with specified number of bits from MAC state buffer */ +void get_mac(byte *buffer,int nbits,byte *out) { + int nbytes= nbits >> 3; + int rembits = nbits & 7; + int mask =rembits?((1 2147483647L +typedef unsigned int u4; +#else +typedef unsigned long u4; +#endif +/* Typedef for unsigned 8-bit integer */ +typedef unsigned char byte; + +/* Internal representation of GOST substitution blocks */ +typedef struct { + byte k8[16]; + byte k7[16]; + byte k6[16]; + byte k5[16]; + byte k4[16]; + byte k3[16]; + byte k2[16]; + byte k1[16]; +} gost_subst_block; + + +/* Cipher context includes key and preprocessed substitution block */ +typedef struct { + u4 k[8]; + /* Constant s-boxes -- set up in gost_init(). */ + u4 k87[256],k65[256],k43[256],k21[256]; +} gost_ctx; +/* Note: encrypt and decrypt expect full blocks--padding blocks is + caller's responsibility. All bulk encryption is done in + ECB mode by these calls. Other modes may be added easily + enough. */ +/* Encrypt several full blocks in ECB mode */ +void gost_enc(gost_ctx *ctx, const byte *clear,byte *cipher, int blocks); +/* Decrypt several full blocks in ECB mode */ +void gost_dec(gost_ctx *ctx, const byte *cipher,byte *clear, int blocks); +/* Encrypts several full blocks in CFB mode using 8byte IV */ +void gost_enc_cfb(gost_ctx *ctx,const byte *iv,const byte *clear,byte *cipher,int blocks); +/* Decrypts several full blocks in CFB mode using 8byte IV */ +void gost_dec_cfb(gost_ctx *ctx,const byte *iv,const byte *cipher,byte *clear,int blocks); + +/* Encrypt one block */ +void gostcrypt(gost_ctx *c, const byte *in, byte *out); +/* Decrypt one block */ +void gostdecrypt(gost_ctx *c, const byte *in,byte *out); +/* Set key into context */ +void gost_key(gost_ctx *ctx, const byte *key); +/* Get key from context */ +void gost_get_key(gost_ctx *ctx, byte *key); +/* Set S-blocks into context */ +void gost_init(gost_ctx *ctx, const gost_subst_block *subst_block); +/* Clean up context */ +void gost_destroy(gost_ctx *ctx); +/* Intermediate function used for calculate hash */ +void gost_enc_with_key(gost_ctx *,byte *key,byte *inblock,byte *outblock); +/* Compute MAC of given length in bits from data */ +int gost_mac(gost_ctx *ctx,int hmac_len,const unsigned char *data, + unsigned int data_len,unsigned char *hmac) ; +/* Compute MAC of given length in bits from data, using non-zero 8-byte + * IV (non-standard, for use in CryptoPro key transport only */ +int gost_mac_iv(gost_ctx *ctx,int hmac_len,const unsigned char *iv,const unsigned char *data, + unsigned int data_len,unsigned char *hmac) ; +/* Perform one step of MAC calculation like gostcrypt */ +void mac_block(gost_ctx *c,byte *buffer,const byte *block); +/* Extracts MAC value from mac state buffer */ +void get_mac(byte *buffer,int nbits,byte *out); +/* Implements cryptopro key meshing algorithm. Expect IV to be 8-byte size*/ +void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv); +/* Parameter sets specified in RFC 4357 */ +extern gost_subst_block GostR3411_94_TestParamSet; +extern gost_subst_block GostR3411_94_CryptoProParamSet; +extern gost_subst_block Gost28147_TestParamSet; +extern gost_subst_block Gost28147_CryptoProParamSetA; +extern gost_subst_block Gost28147_CryptoProParamSetB; +extern gost_subst_block Gost28147_CryptoProParamSetC; +extern gost_subst_block Gost28147_CryptoProParamSetD; +extern const byte CryptoProKeyMeshingKey[]; +#if __LONG_MAX__ > 2147483647L +typedef unsigned int word32; +#else +typedef unsigned long word32; +#endif + +#endif diff --git a/engines/ccgost/gost94_keyx.c b/engines/ccgost/gost94_keyx.c new file mode 100644 index 0000000000..4cf8a0ba80 --- /dev/null +++ b/engines/ccgost/gost94_keyx.c @@ -0,0 +1,420 @@ +/********************************************************************** + * gost94_keyx.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implements generation and parsing of GOST_KEY_TRANSPORT for * + * GOST R 34.10-94 algorithms * + * * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include +#include + +#include "gostkeyx.h" +#include "gost_asn1.h" +#include "gost89.h" +#include "gosthash.h" +#include "crypt.h" +#include "e_gost_err.h" +#include "pmeth.h" +#include "keywrap.h" +#include "tools.h" +/* Common functions for both 94 and 2001 key exchange schemes */ +int decrypt_cryptocom_key(unsigned char *sess_key,int max_key_len, + const unsigned char *crypted_key,int crypted_key_len, gost_ctx *ctx) +{ + int i; + int j; + int blocks = crypted_key_len >>3; + unsigned char gamma[8]; + if (max_key_len 0;i--) + { + gostcrypt(ctx,crypted_key+(i-1)*8,gamma); + for(j=0;j<8;j++) + { + sess_key[i*8+j]=gamma[j]^crypted_key[i*8+j]; + } + } + gostcrypt(ctx,sess_key+crypted_key_len-8,gamma); + for(j=0;j<8;j++) + { + sess_key[j]=gamma[j]^crypted_key[j]; + } + return 1; +} +int encrypt_cryptocom_key(const unsigned char *sess_key,int key_len, + unsigned char *crypted_key, gost_ctx *ctx) +{ + int i; + int j; + unsigned char gamma[8]; + memcpy(gamma,sess_key+key_len-8,8); + for (i=0;ipub_key,dh)) return 0; + /* Fold it down to 256 bit */ + /* According to GOST either 2^1020g = BN_dup(pubk->pkey.dsa->g); + dh->p = BN_dup(pubk->pkey.dsa->p); + dh->priv_key = BN_dup(ephemeral_key); + /* Generate ephemeral key pair */ + if (!DH_generate_key(dh)) { + DH_free(dh); + return NULL; + } + return dh; +} +/* + * Computes 256 bit Key exchange key as specified in RFC 4357 + */ +static int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key) +{ + unsigned char dh_key [128]; + gost_hash_ctx hash_ctx; + memset(dh_key,0,128); + if (!compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh)) return 0; + init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet); + start_hash(&hash_ctx); + hash_block(&hash_ctx,dh_key,128); + finish_hash(&hash_ctx,shared_key); + done_gost_hash_ctx(&hash_ctx); + return 1; +} +/* EVP_PKEY_METHOD callback encrypt for + * GOST R 34.10-94 cryptopro modification + */ + +int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len ) +{ + GOST_KEY_TRANSPORT *gkt=NULL; + DH *dh = NULL; + unsigned char shared_key[32], ukm[8],crypted_key[44]; + const struct gost_cipher_info *param=get_encryption_params(NULL); + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + int size=-1; + gost_ctx cctx; + + + if (!(data->eph_seckey)) { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT); + return -1; + } + + dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey)); + gost_init(&cctx,param->sblock); + make_cp_exchange_key(dh,pubk,shared_key); + if (RAND_bytes(ukm,8)<=0) { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_RANDOM_GENERATOR_FAILURE); + return -1; + } + keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key); + gkt = GOST_KEY_TRANSPORT_new(); + if (!gkt) { + goto memerr; + } + if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, + ukm,8)) { + goto memerr; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) { + goto memerr; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) { + goto memerr; + } + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); + goto err; + } + ASN1_OBJECT_free(gkt->key_agreement_info->cipher); + gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid); + *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out); + if (!size) { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO); + size=-1; + } + GOST_KEY_TRANSPORT_free(gkt); + DH_free(dh); + return 1; +memerr: + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_MALLOC_FAILURE); +err: + GOST_KEY_TRANSPORT_free(gkt); + DH_free(dh); + return -1; +} +/* EVP_PKEY_METHOD callback encrypt for + * GOST R 34.10-94 cryptocom modification + */ + +int pkey_GOST94cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len) +{ + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(ctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + /* create DH structure filling parameters from passed pub_key */ + DH *dh = NULL; + GOST_KEY_TRANSPORT *gkt = NULL; + gost_ctx cctx; + EVP_PKEY *newkey=NULL; + unsigned char shared_key[32],encrypted_key[32],hmac[4], + iv[8]={0,0,0,0,0,0,0,0}; + + if (! data->eph_seckey) { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_CTX_NOT_INITIALIZED_FOR_ENCRYPT); + return -1; + } + dh = make_ephemeral_key(pubk,gost_get_priv_key(data->eph_seckey)); + if (!dh) goto err; + /* compute shared key */ + if (!make_gost_shared_key(dh,pubk,shared_key)) + { + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); + goto err; + } + /* encrypt session key */ + gost_init(&cctx, &GostR3411_94_CryptoProParamSet); + gost_key(&cctx,shared_key); + encrypt_cryptocom_key(key,key_len,encrypted_key,&cctx); + /* compute hmac of session key */ + if (!gost_mac(&cctx,32,key,32,hmac)) + { + DH_free(dh); + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC); + return -1; + } + gkt = GOST_KEY_TRANSPORT_new(); + if (!gkt) + { + DH_free(dh); + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_NO_MEMORY); + return -1; + } + /* Store IV which is always zero in our case */ + if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8)) + { + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_IV); + goto err; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4)) + { + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_MAC); + goto err; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32)) + { + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY); + goto err; + } + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey)) { + GOSTerr(GOST_F_PKEY_GOST94CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); + goto err; + } + ASN1_OBJECT_free(gkt->key_agreement_info->cipher); + gkt->key_agreement_info->cipher = OBJ_nid2obj(NID_id_Gost28147_89_cc); + *outlen = i2d_GOST_KEY_TRANSPORT(gkt,&out); +err: + if (gkt) GOST_KEY_TRANSPORT_free(gkt); + if (dh) DH_free(dh); + if (newkey) EVP_PKEY_free(newkey); + return 1; +} + +/* EVP_PLEY_METHOD callback decrypt for + * GOST R 34.10-94 cryptopro modification + */ +int pkey_GOST94cp_decrypt (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len,const unsigned char *in, size_t in_len) { + DH *dh = DH_new(); + const unsigned char *p = in; + GOST_KEY_TRANSPORT *gkt = NULL; + unsigned char wrappedKey[44]; + unsigned char sharedKey[32]; + gost_ctx cctx; + const struct gost_cipher_info *param=NULL; + EVP_PKEY *eph_key=NULL; + EVP_PKEY *priv= EVP_PKEY_CTX_get0_pkey(ctx); + + if (!key) { + *key_len = 32; + return 1; + } + + dh->g = BN_dup(priv->pkey.dsa->g); + dh->p = BN_dup(priv->pkey.dsa->p); + dh->priv_key = BN_dup(priv->pkey.dsa->priv_key); + gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, + in_len); + if (!gkt) { + GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); + DH_free(dh); + return 0; + } + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + param = get_encryption_params(gkt->key_agreement_info->cipher); + gost_init(&cctx,param->sblock); + OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); + memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8); + OPENSSL_assert(gkt->key_info->encrypted_key->length==32); + memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32); + OPENSSL_assert(gkt->key_info->imit->length==4); + memcpy(wrappedKey+40,gkt->key_info->imit->data,4); + make_cp_exchange_key(dh,eph_key,sharedKey); + if (!keyUnwrapCryptoPro(&cctx,sharedKey,wrappedKey,key)) { + GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, + GOST_R_ERROR_COMPUTING_SHARED_KEY); + goto err; + } + + EVP_PKEY_free(eph_key); + GOST_KEY_TRANSPORT_free(gkt); + DH_free(dh); + return 1; +err: + EVP_PKEY_free(eph_key); + GOST_KEY_TRANSPORT_free(gkt); + DH_free(dh); + return -1; + +} +/* EVP_PKEY_METHOD callback decrypt for + * GOST R 34.10-94 cryptocom modification + */ + +int pkey_GOST94cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len) +{ + /* Form DH params from compute shared key */ + GOST_KEY_TRANSPORT *gkt = NULL; + const unsigned char *p=in; + unsigned char shared_key[32]; + unsigned char hmac[4],hmac_comp[4]; + unsigned char iv[8]; + int i; + gost_ctx ctx; + DH *dh = DH_new(); + EVP_PKEY *eph_key; + EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx); + + if (!key) { + *key_len = 32; + return 1; + } + /* Construct DH structure from the our GOST private key */ + dh->g = BN_dup(priv->pkey.dsa->g); + dh->p = BN_dup(priv->pkey.dsa->p); + dh->priv_key = BN_dup(priv->pkey.dsa->priv_key); + /* Parse passed octet string and find out public key, iv and HMAC*/ + gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, + in_len); + if (!gkt) { + GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); + DH_free(dh); + return 0; + } + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + /* Initialization vector is really ignored here */ + OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8); + memcpy(iv,gkt->key_agreement_info->eph_iv->data,8); + /* HMAC should be computed and checked */ + OPENSSL_assert(gkt->key_info->imit->length==4); + memcpy(hmac,gkt->key_info->imit->data,4); + /* Compute shared key */ + i=make_gost_shared_key(dh,eph_key,shared_key); + EVP_PKEY_free(eph_key); + DH_free(dh); + if (!i) + { + GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY); + GOST_KEY_TRANSPORT_free(gkt); + return 0; + } + /* Decrypt session key */ + gost_init(&ctx, &GostR3411_94_CryptoProParamSet); + gost_key(&ctx,shared_key); + + if (!decrypt_cryptocom_key(key,*key_len,gkt->key_info->encrypted_key->data, + gkt->key_info->encrypted_key->length, &ctx)) + { + GOST_KEY_TRANSPORT_free(gkt); + return 0; + } + GOST_KEY_TRANSPORT_free(gkt); + /* check HMAC of session key*/ + if (!gost_mac(&ctx,32,key,32,hmac_comp)) { + GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_ERROR_COMPUTING_MAC); + return 0; + } + /* HMAC of session key is not correct */ + if (memcmp(hmac,hmac_comp,4)!=0) { + GOSTerr(GOST_F_PKEY_GOST94CC_DECRYPT,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH); + return 0; + } + return 1; +} diff --git a/engines/ccgost/gost_asn1.c b/engines/ccgost/gost_asn1.c new file mode 100644 index 0000000000..e7303b7f92 --- /dev/null +++ b/engines/ccgost/gost_asn1.c @@ -0,0 +1,55 @@ +/********************************************************************** + * gost_keytrans.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * ASN1 structure definition for GOST key transport * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include "gost_asn1.h" + +ASN1_NDEF_SEQUENCE(GOST_KEY_TRANSPORT) = { + ASN1_SIMPLE(GOST_KEY_TRANSPORT, key_info, GOST_KEY_INFO), + ASN1_IMP(GOST_KEY_TRANSPORT, key_agreement_info, GOST_KEY_AGREEMENT_INFO, 0) +} ASN1_NDEF_SEQUENCE_END(GOST_KEY_TRANSPORT) + +IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_TRANSPORT) + +ASN1_NDEF_SEQUENCE(GOST_KEY_INFO) = { + ASN1_SIMPLE(GOST_KEY_INFO, encrypted_key, ASN1_OCTET_STRING), + ASN1_SIMPLE(GOST_KEY_INFO, imit, ASN1_OCTET_STRING) +} ASN1_NDEF_SEQUENCE_END(GOST_KEY_INFO) + +IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_INFO) + +ASN1_NDEF_SEQUENCE(GOST_KEY_AGREEMENT_INFO) = { + ASN1_SIMPLE(GOST_KEY_AGREEMENT_INFO, cipher, ASN1_OBJECT), + ASN1_IMP(GOST_KEY_AGREEMENT_INFO, ephem_key, X509_PUBKEY, 0), + ASN1_SIMPLE(GOST_KEY_AGREEMENT_INFO, eph_iv, ASN1_OCTET_STRING) +} ASN1_NDEF_SEQUENCE_END(GOST_KEY_AGREEMENT_INFO) + +IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_AGREEMENT_INFO) + +ASN1_NDEF_SEQUENCE(GOST_KEY_PARAMS) = { + ASN1_SIMPLE(GOST_KEY_PARAMS, key_params, ASN1_OBJECT), + ASN1_SIMPLE(GOST_KEY_PARAMS, hash_params, ASN1_OBJECT), + ASN1_OPT(GOST_KEY_PARAMS, cipher_params, ASN1_OBJECT), +} ASN1_NDEF_SEQUENCE_END(GOST_KEY_PARAMS); + +IMPLEMENT_ASN1_FUNCTIONS(GOST_KEY_PARAMS) + +ASN1_NDEF_SEQUENCE(GOST_CIPHER_PARAMS) = { + ASN1_SIMPLE(GOST_CIPHER_PARAMS, iv, ASN1_OCTET_STRING), + ASN1_SIMPLE(GOST_CIPHER_PARAMS, enc_param_set, ASN1_OBJECT), +} ASN1_NDEF_SEQUENCE_END(GOST_CIPHER_PARAMS); + +IMPLEMENT_ASN1_FUNCTIONS(GOST_CIPHER_PARAMS); + +ASN1_NDEF_SEQUENCE(GOST_CLIENT_KEY_EXCHANGE_PARAMS) = { //FIXME incomplete + ASN1_SIMPLE(GOST_CLIENT_KEY_EXCHANGE_PARAMS, gkt, GOST_KEY_TRANSPORT) +} ASN1_NDEF_SEQUENCE_END(GOST_CLIENT_KEY_EXCHANGE_PARAMS); + +IMPLEMENT_ASN1_FUNCTIONS(GOST_CLIENT_KEY_EXCHANGE_PARAMS); diff --git a/engines/ccgost/gost_asn1.h b/engines/ccgost/gost_asn1.h new file mode 100644 index 0000000000..81075e47d3 --- /dev/null +++ b/engines/ccgost/gost_asn1.h @@ -0,0 +1,57 @@ +/********************************************************************** + * gost_keytrans.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * ASN1 structure declaration for GOST key transport * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#ifndef GOST_KEY_TRANS_H +#define GOST_KEY_TRANS_H +#include +#include + + +typedef struct { + ASN1_OCTET_STRING *encrypted_key; + ASN1_OCTET_STRING *imit; +} GOST_KEY_INFO; + +DECLARE_ASN1_FUNCTIONS(GOST_KEY_INFO) + +typedef struct { + ASN1_OBJECT *cipher; + X509_PUBKEY *ephem_key; + ASN1_OCTET_STRING *eph_iv; +} GOST_KEY_AGREEMENT_INFO; + +DECLARE_ASN1_FUNCTIONS(GOST_KEY_AGREEMENT_INFO) + +typedef struct { + GOST_KEY_INFO *key_info; + GOST_KEY_AGREEMENT_INFO *key_agreement_info; +} GOST_KEY_TRANSPORT; + +DECLARE_ASN1_FUNCTIONS(GOST_KEY_TRANSPORT) + +typedef struct { //FIXME incomplete + GOST_KEY_TRANSPORT *gkt; +} GOST_CLIENT_KEY_EXCHANGE_PARAMS; + +DECLARE_ASN1_FUNCTIONS(GOST_CLIENT_KEY_EXCHANGE_PARAMS) +typedef struct { + ASN1_OBJECT *key_params; + ASN1_OBJECT *hash_params; + ASN1_OBJECT *cipher_params; +} GOST_KEY_PARAMS; + +DECLARE_ASN1_FUNCTIONS(GOST_KEY_PARAMS) + +typedef struct { + ASN1_OCTET_STRING *iv; + ASN1_OBJECT *enc_param_set; +} GOST_CIPHER_PARAMS; + +DECLARE_ASN1_FUNCTIONS(GOST_CIPHER_PARAMS) + +#endif diff --git a/engines/ccgost/gost_crypt.c b/engines/ccgost/gost_crypt.c new file mode 100644 index 0000000000..9b3803d8fd --- /dev/null +++ b/engines/ccgost/gost_crypt.c @@ -0,0 +1,579 @@ +/********************************************************************** +* gost_crypt.c * +* Copyright (c) 2005-2006 Cryptocom LTD * +* This file is distributed under the same license as OpenSSL * +* * +* OpenSSL interface to GOST 28147-89 cipher functions * +* Requires OpenSSL 0.9.9 for compilation * +**********************************************************************/ +#include +#include "crypt.h" +#include "gost89.h" +#include +#include "e_gost_err.h" +#include "gost_asn1.h" +static int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +#ifdef USE_SSL +/* Specialized init functions which set specific parameters */ +static int gost_cipher_init_vizir(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +static int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); +#endif +/* Handles block of data in CFB mode */ +static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl); +/* Handles block of data in CNT mode */ +static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl); +/* Cleanup function */ +static int gost_cipher_cleanup(EVP_CIPHER_CTX *); +/* set/get cipher parameters */ +static int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params); +static int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params); +/* Control function */ +static int gost_cipher_ctl(EVP_CIPHER_CTX *ctx,int type,int arg,void *ptr); + +EVP_CIPHER cipher_gost = + { + NID_id_Gost28147_89, + 1,/*block_size*/ + 32,/*key_size*/ + 8,/*iv_len - ñèíõðîïîñûëêà*/ + EVP_CIPH_CFB_MODE| EVP_CIPH_NO_PADDING | + EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT, + gost_cipher_init, + gost_cipher_do_cfb, + gost_cipher_cleanup, + sizeof(struct ossl_gost_cipher_ctx),/* ctx_size */ + gost89_set_asn1_parameters, + gost89_get_asn1_parameters, + gost_cipher_ctl, + NULL, + }; + +#ifdef USE_SSL +static EVP_CIPHER cipher_gost_vizircfb = + { + NID_undef, + 1,/*block_size*/ + 32,/*key_size*/ + 8,/*iv_len - ñèíõðîïîñûëêà*/ + EVP_CIPH_CFB_MODE| EVP_CIPH_NO_PADDING | + EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT, + gost_cipher_init_vizir, + gost_cipher_do_cfb, + gost_cipher_cleanup, + sizeof(struct ossl_gost_cipher_ctx), /* ctx_size */ + gost89_set_asn1_parameters, + gost89_get_asn1_parameters, + gost_cipher_ctl, + NULL, + }; + +static EVP_CIPHER cipher_gost_cpacnt = + { + NID_undef, + 1,/*block_size*/ + 32,/*key_size*/ + 8,/*iv_len - ñèíõðîïîñûëêà*/ + EVP_CIPH_OFB_MODE| EVP_CIPH_NO_PADDING | + EVP_CIPH_CUSTOM_IV| EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT, + gost_cipher_init_cpa, + gost_cipher_do_cnt, + gost_cipher_cleanup, + sizeof(struct ossl_gost_cipher_ctx), /* ctx_size */ + gost89_set_asn1_parameters, + gost89_get_asn1_parameters, + gost_cipher_ctl, + NULL, + }; +/* Implementation of GOST 28147-89 in MAC (imitovstavka) mode */ +/* Init functions which set specific parameters */ +static int gost_imit_init_vizir(EVP_MD_CTX *ctx); +static int gost_imit_init_cpa(EVP_MD_CTX *ctx); +/* process block of data */ +static int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count); +/* Return computed value */ +static int gost_imit_final(EVP_MD_CTX *ctx,unsigned char *md); +/* Copies context */ +static int gost_imit_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from); +static int gost_imit_cleanup(EVP_MD_CTX *ctx); +/* Control function, knows how to set MAC key.*/ +static int gost_imit_ctrl(EVP_MD_CTX *ctx,int type, int arg, void *ptr); + +EVP_MD imit_gost_vizir = + { + NID_undef, + NID_undef, + 4, + EVP_MD_FLAG_NEEDS_KEY, + gost_imit_init_vizir, + gost_imit_update, + gost_imit_final, + gost_imit_copy, + gost_imit_cleanup, + gost_imit_ctrl, + NULL, + NULL, + {0,0,0,0,0}, + 8, + sizeof(struct ossl_gost_imit_ctx) + }; + +EVP_MD imit_gost_cpa = + { + NID_undef, + NID_undef, + 4, + EVP_MD_FLAG_NEEDS_KEY, + gost_imit_init_cpa, + gost_imit_update, + gost_imit_final, + gost_imit_copy, + gost_imit_cleanup, + gost_imit_ctrl, + NULL, + NULL, + {0,0,0,0,0}, + 8, + sizeof(struct ossl_gost_imit_ctx) + }; + +#endif +/* +* Correspondence between gost parameter OIDs and substitution blocks +* NID field is filed by register_gost_NID function in engine.c +* upon engine initialization +*/ + +struct gost_cipher_info gost_cipher_list[]={ +/* NID */ /* Subst block */ /* Key meshing*/ +/*{NID_id_GostR3411_94_CryptoProParamSet,&GostR3411_94_CryptoProParamSet,0},*/ +{NID_id_Gost28147_89_cc,&GostR3411_94_CryptoProParamSet,0}, +{NID_id_Gost28147_89_CryptoPro_A_ParamSet,&Gost28147_CryptoProParamSetA,1}, +{NID_id_Gost28147_89_CryptoPro_B_ParamSet,&Gost28147_CryptoProParamSetB,1}, +{NID_id_Gost28147_89_CryptoPro_C_ParamSet,&Gost28147_CryptoProParamSetC,1}, +{NID_id_Gost28147_89_CryptoPro_D_ParamSet,&Gost28147_CryptoProParamSetD,1}, +{NID_undef,NULL,0} +}; + +/* get encryption parameters from crypto network settings +FIXME For now we use environment var CRYPT_PARAMS as place to +store these settings. Actually, it is better to use engine control command, read from configuration file to set them */ +const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj) { +int nid; +struct gost_cipher_info *param; +if (!obj) { + const char * params = getenv("CRYPT_PARAMS"); + if (!params || !strlen(params)) + return &gost_cipher_list[0]; + + nid = OBJ_txt2nid(params); + if (nid == NID_undef) { + GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS, + GOST_R_INVALID_CIPHER_PARAM_OID); + return NULL; + } +} else { + nid= OBJ_obj2nid(obj); +} +for (param=gost_cipher_list;param->sblock!=NULL && param->nid!=nid; + param++); +if (!param->sblock) { + GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS,GOST_R_INVALID_CIPHER_PARAMS); + return NULL; + +} +return param; + +} +/* Sets cipher param from paramset NID. */ +int gost_cipher_set_param(struct ossl_gost_cipher_ctx *c,int nid) { +const struct gost_cipher_info *param; +param=get_encryption_params((nid==NID_undef?NULL:OBJ_nid2obj(nid))); +if (!param) return 0; + +c->paramNID = param->nid; +c->key_meshing=param->key_meshing; +c->count=0; +gost_init(&(c->cctx), param->sblock); +return 1; +} +/* Initializes EVP_CIPHER_CTX by paramset NID */ +static int gost_cipher_init_param(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc, int paramNID,int mode) { +struct ossl_gost_cipher_ctx *c=ctx->cipher_data; +if (!gost_cipher_set_param(c,paramNID)) return 0; +if (key) gost_key(&(c->cctx),key); +if(iv) memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); +memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); +return 1; +} + +/* Initializes EVP_CIPHER_CTX with fixed cryptopro A paramset */ +int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) { +struct ossl_gost_cipher_ctx *c=ctx->cipher_data; +gost_init(&(c->cctx),&Gost28147_CryptoProParamSetA); +c->key_meshing=1; +c->count=0; +gost_key(&(c->cctx),key); +if(iv) memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); +memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); +return 1; +} +/* Initializes EVP_CIPHER_CTX with fixed vizir paramset */ +int gost_cipher_init_vizir(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) { +struct ossl_gost_cipher_ctx *c=ctx->cipher_data; +gost_init(&(c->cctx),&GostR3411_94_CryptoProParamSet); +c->key_meshing=0; +c->count=0; +gost_key(&(c->cctx),key); + +if(iv) memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); +memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); +return 1; +} + +/* Initializes EVP_CIPHER_CTX with default values */ +int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) { +return gost_cipher_init_param(ctx,key,iv,enc,NID_undef,EVP_CIPH_CFB_MODE); +} +/* Wrapper around gostcrypt function from gost89.c which perform +* key meshing when nesseccary +*/ +static void gost_crypt_mesh (void *ctx,unsigned char *iv,unsigned char *buf) { + struct ossl_gost_cipher_ctx *c = ctx; + if (c->count&&c->key_meshing && c->count%1024==0) { + cryptopro_key_meshing(&(c->cctx),iv); + } + gostcrypt(&(c->cctx),iv,buf); + c->count+=8; +} + +static void gost_cnt_next (void *ctx, unsigned char *iv, unsigned char *buf) { +struct ossl_gost_cipher_ctx *c = ctx; +word32 g,go; +unsigned char buf1[8]; +if (c->count && c->key_meshing && c->count %1024 ==0) { + cryptopro_key_meshing(&(c->cctx),iv); +} +if (c->count==0) { +gostcrypt(&(c->cctx),iv,buf1); +} else { + memcpy(buf1,iv,8); +} + g = buf1[0]|(buf1[1]<<8)|(buf1[2]<<16)|(buf1[3]<<24); + g += 0x01010101; + buf1[0]=g&0xff; buf1[1]=(g>>8)&0xff; buf1[2]=(g>>16)&0xff; buf1[3]=(g>>24)&0xff; + g = buf1[4]|(buf1[5]<<8)|(buf1[6]<<16)|(buf1[7]<<24); + go = g; + g += 0x01010104; + if (go > g) /* overflow*/ + g++; + buf1[4]=g&0xff; buf1[5]=(g>>8)&0xff; buf1[6]=(g>>16)&0xff; buf1[7]=(g>>24)&0xff; + memcpy(iv,buf1,8); + gostcrypt(&(c->cctx),buf1,buf); +c->count +=8; +} + +/* GOST encryption in CFB mode */ +int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl) { +const unsigned char *in_ptr=in; +unsigned char *out_ptr=out; +int i=0; +int j; +/* process partial block if any */ +if (ctx->num) +{ + for (j=ctx->num,i=0;j<8 && iencrypt) ctx->buf[j+8]=*in_ptr; + *out_ptr=ctx->buf[j]^(*in_ptr); + if (ctx->encrypt) ctx->buf[j+8]=*out_ptr; + } + if (j==8) { + memcpy(ctx->iv,ctx->buf+8,8); + ctx->num=0; + } else { + ctx->num=j; + return 1; + } +} + +for (;i+8cipher_data,ctx->iv,ctx->buf); + /*xor next block of input text with it and output it*/ + /*output this block */ + if (!ctx->encrypt) memcpy(ctx->iv,in_ptr,8); + for (j=0;j<8;j++) { + out_ptr[j]=ctx->buf[j]^in_ptr[j]; + } + /* Encrypt */ + /* Next iv is next block of cipher text*/ + if (ctx->encrypt) memcpy(ctx->iv,out_ptr,8); +} +/* Process rest of buffer */ +if (icipher_data,ctx->iv,ctx->buf); + if (!ctx->encrypt) memcpy(ctx->buf+8,in_ptr,j); + for (j=0;ibuf[j]^in_ptr[j]; + } + ctx->num = j; + if (ctx->encrypt) memcpy(ctx->buf+8,out_ptr,j); +} else { + ctx->num = 0; +} +return 1; +} +int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl) { +const unsigned char *in_ptr=in; +unsigned char *out_ptr=out; +int i=0; +int j; +/* process partial block if any */ +if (ctx->num) +{ + for (j=ctx->num,i=0;j<8 && ibuf[j]^(*in_ptr); + } + if (j==8) { + ctx->num=0; + } else { + ctx->num=j; + return 1; + } +} + +for (;i+8cipher_data,ctx->iv,ctx->buf); + /*xor next block of input text with it and output it*/ + /*output this block */ + for (j=0;j<8;j++) { + out_ptr[j]=ctx->buf[j]^in_ptr[j]; + } +} +/* Process rest of buffer */ +if (icipher_data,ctx->iv,ctx->buf); + for (j=0;ibuf[j]^in_ptr[j]; + } + ctx->num = j; +} else { + ctx->num = 0; +} +return 1; +} +/* Cleaning up of EVP_CIPHER_CTX */ +int gost_cipher_cleanup(EVP_CIPHER_CTX *ctx) +{ +gost_destroy((gost_ctx *)ctx->cipher_data); +return 1; + +} +/* Control function for gost cipher */ +int gost_cipher_ctl(EVP_CIPHER_CTX *ctx,int type,int arg,void *ptr) +{ +switch (type) +{ + case EVP_CTRL_RAND_KEY: + { + if (RAND_bytes((unsigned char *)ptr,ctx->key_len)<=0) + { + GOSTerr(GOST_F_GOST_CIPHER_CTL,GOST_R_RANDOM_GENERATOR_ERROR); + return -1; + } + break; + } + default: + GOSTerr(GOST_F_GOST_CIPHER_CTL,GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND); + return -1; +} +return 1; +} + +/* Set cipher parameters from ASN1 structure */ +int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params) +{ +int len=0; +unsigned char *buf=NULL; +unsigned char *p=NULL; +struct ossl_gost_cipher_ctx *c = ctx->cipher_data; +GOST_CIPHER_PARAMS *gcp = GOST_CIPHER_PARAMS_new(); +ASN1_OCTET_STRING *os = NULL; +if (!gcp) { + GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY); + return 0; +} +if (!ASN1_OCTET_STRING_set(gcp->iv, ctx->iv, ctx->cipher->iv_len)) { + GOST_CIPHER_PARAMS_free(gcp); + GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY); + return 0; +} +ASN1_OBJECT_free(gcp->enc_param_set); +gcp->enc_param_set = OBJ_nid2obj(c->paramNID); + +len = i2d_GOST_CIPHER_PARAMS(gcp, NULL); +p = buf = (unsigned char*)OPENSSL_malloc(len); +if (!buf) { + GOST_CIPHER_PARAMS_free(gcp); + GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY); + return 0; +} +i2d_GOST_CIPHER_PARAMS(gcp, &p); +GOST_CIPHER_PARAMS_free(gcp); + +os = ASN1_OCTET_STRING_new(); + +if(!os || !ASN1_OCTET_STRING_set(os, buf, len)) { + OPENSSL_free(buf); + GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, GOST_R_NO_MEMORY); + return 0; +} +OPENSSL_free(buf); + +ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os); +return 1; +} +/* Store parameters into ASN1 structure */ +int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx,ASN1_TYPE *params) +{ +int ret = -1; +int len; +GOST_CIPHER_PARAMS *gcp = NULL; +unsigned char *p = params->value.sequence->data; +struct ossl_gost_cipher_ctx *c=ctx->cipher_data; +if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) { + return ret; +} + +gcp = d2i_GOST_CIPHER_PARAMS(NULL, (const unsigned char **)&p, + params->value.sequence->length); + +len = gcp->iv->length; +if (len != ctx->cipher->iv_len) { + GOST_CIPHER_PARAMS_free(gcp); + GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS, + GOST_R_INVALID_IV_LENGTH); + return -1; +} +if (!gost_cipher_set_param(c,OBJ_obj2nid(gcp->enc_param_set))) { + GOST_CIPHER_PARAMS_free(gcp); + return -1; +} +memcpy(ctx->oiv, gcp->iv->data, len); + +GOST_CIPHER_PARAMS_free(gcp); + +return 1; + +} + +#ifdef USE_SSL + +int gost_imit_init_vizir(EVP_MD_CTX *ctx) { +struct ossl_gost_imit_ctx *c = ctx->md_data; +memset(c,0,sizeof(struct ossl_gost_imit_ctx)); +gost_init(&(c->cctx),&GostR3411_94_CryptoProParamSet); +return 1; +} +int gost_imit_init_cpa(EVP_MD_CTX *ctx) { +struct ossl_gost_imit_ctx *c = ctx->md_data; +memset(c,0,sizeof(struct ossl_gost_imit_ctx)); +c->key_meshing=1; +gost_init(&(c->cctx),&Gost28147_CryptoProParamSetA); +return 1; +} + +static void mac_block_mesh(struct ossl_gost_imit_ctx *c,unsigned char *data) +{ + char buffer[8]; + /* We are using local buffer for iv because CryptoPro doesn't + * interpret internal state of MAC algorithm as iv during keymeshing + * (but does initialize internal state from iv in key transport + */ + if (c->key_meshing&& c->count && c->count %1024 ==0) { + cryptopro_key_meshing(&(c->cctx),buffer); + } + mac_block(&(c->cctx),c->buffer,data); + c->count +=8; +} + +int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + struct ossl_gost_imit_ctx *c = ctx->md_data; + const unsigned char *p = data; + size_t bytes = count,i; + if (!(c->key_set)) return 0; + if (c->bytes_left) { + for (i=c->bytes_left;i<8&&bytes>0;bytes--,i++,p++) { + c->partial_block[i]=*p; + } + if (i==8) { + mac_block_mesh(c,c->partial_block); + } else { + c->bytes_left = i; + return 1; + } + } + while (bytes>8) { + mac_block_mesh(c,p); + p+=8; + bytes-=8; + } + if (bytes>0) { + memcpy(c->partial_block,p,bytes); + c->bytes_left=bytes; + } + return 1; +} + +int gost_imit_final(EVP_MD_CTX *ctx,unsigned char *md) { + struct ossl_gost_imit_ctx *c = ctx->md_data; + if (c->bytes_left) { + int i; + for (i=c->bytes_left;i<8;i++) { + c->partial_block[i]=0; + } + mac_block_mesh(c,c->partial_block); + } + get_mac(c->buffer,32,md); + return 1; +} +int gost_imit_ctrl(EVP_MD_CTX *ctx,int type, int arg, void *ptr) { + switch (type) { + case EVP_MD_CTRL_GET_TLS_MAC_KEY_LENGTH: + *((unsigned int*)(ptr)) = 32; + return 1; + case EVP_MD_CTRL_SET_KEY: + { + gost_key(&(((struct ossl_gost_imit_ctx*)(ctx->md_data))->cctx),ptr) ; + ((struct ossl_gost_imit_ctx*)(ctx->md_data))->key_set = 1; + + } + default: + return 0; + } +} +int gost_imit_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from) { + memcpy(to->md_data,from->md_data,sizeof(struct ossl_gost_imit_ctx)); + return 1; +} +/* Clean up imit ctx */ +int gost_imit_cleanup(EVP_MD_CTX *ctx) { + memset(ctx->md_data,0,sizeof(struct ossl_gost_imit_ctx)); + return 1; + +} +#endif diff --git a/engines/ccgost/gost_sign.c b/engines/ccgost/gost_sign.c new file mode 100644 index 0000000000..d4c9e5d3ff --- /dev/null +++ b/engines/ccgost/gost_sign.c @@ -0,0 +1,302 @@ +/********************************************************************** + * gost_sign.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of GOST R 34.10-94 signature algoritgthm * + * for OpenSSL * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include +#include + +#include "sign.h" +#include "paramset.h" +#include "tools.h" +#include "e_gost_err.h" + +#ifdef DEBUG_SIGN +void dump_signature(const char *message,const unsigned char *buffer,size_t len) { + size_t i; + fprintf(stderr,"signature %s Length=%d",message,len); + for (i=0; iq,ctx); + if (BN_is_zero(tmp)) + { + BN_one(md); + } + do { + do { + /*Generate random number k less than q*/ + BN_rand_range(k,dsa->q); + /* generate r = (a^x mod p) mod q */ + BN_mod_exp(tmp,dsa->g, k, dsa->p,ctx); + if (!(newsig->r)) newsig->r=BN_new(); + BN_mod(newsig->r,tmp,dsa->q,ctx); + } while (BN_is_zero(newsig->r)); + /* generate s = (xr + k(Hm)) mod q */ + BN_mod_mul(tmp,dsa->priv_key,newsig->r,dsa->q,ctx); + BN_mod_mul(tmp2,k,md,dsa->q,ctx); + if (!newsig->s) newsig->s=BN_new(); + BN_mod_add(newsig->s,tmp,tmp2,dsa->q,ctx); + } while (BN_is_zero(newsig->s)); +err: + BN_free(md); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return newsig; +} + + +/* + * Packs signature according to Cryptocom rules + * and frees up DSA_SIG structure + */ + +int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen) +{ + + *siglen = 2*order; + memset(sig,0,*siglen); + store_bignum(s->r, sig,order); + store_bignum(s->s, sig + order,order); + dump_signature("serialized",sig,*siglen); + DSA_SIG_free(s); + return 1; +} +/* + * Packs signature according to Cryptopro rules + * and frees up DSA_SIG structure + */ +int pack_sign_cp(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen) +{ + + *siglen = 2*order; + memset(sig,0,*siglen); + store_bignum(s->s, sig, order); + store_bignum(s->r, sig+order,order); + dump_signature("serialized",sig,*siglen); + DSA_SIG_free(s); + return 1; +} + + + + +/* + * Verifies signature passed as DSA_SIG structure + * + */ + +int gost_do_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa) +{ + BIGNUM *md, *tmp=NULL; + BIGNUM *q2=NULL; + BIGNUM *u=NULL,*v=NULL,*z1=NULL,*z2=NULL; + BIGNUM *tmp2=NULL,*tmp3=NULL; + int ok; + BN_CTX *ctx = BN_CTX_new(); + + BN_CTX_start(ctx); + if (BN_cmp(sig->s,dsa->q)>=1|| + BN_cmp(sig->r,dsa->q)>=1) + { + GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q); + return 0; + } + md=hashsum2bn(dgst); + + tmp=BN_CTX_get(ctx); + v=BN_CTX_get(ctx); + q2=BN_CTX_get(ctx); + z1=BN_CTX_get(ctx); + z2=BN_CTX_get(ctx); + tmp2=BN_CTX_get(ctx); + tmp3=BN_CTX_get(ctx); + u = BN_CTX_get(ctx); + + BN_mod(tmp,md,dsa->q,ctx); + if (BN_is_zero(tmp)) { + BN_one(md); + } + BN_copy(q2,dsa->q); + BN_sub_word(q2,2); + BN_mod_exp(v,md,q2,dsa->q,ctx); + BN_mod_mul(z1,sig->s,v,dsa->q,ctx); + BN_sub(tmp,dsa->q,sig->r); + BN_mod_mul(z2,tmp,v,dsa->p,ctx); + BN_mod_exp(tmp,dsa->g,z1,dsa->p,ctx); + BN_mod_exp(tmp2,dsa->pub_key,z2,dsa->p,ctx); + BN_mod_mul(tmp3,tmp,tmp2,dsa->p,ctx); + BN_mod(u,tmp3,dsa->q,ctx); + ok= BN_cmp(u,sig->r); + + BN_free(md); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + if (ok!=0) { + GOSTerr(GOST_F_GOST_DO_VERIFY,GOST_R_SIGNATURE_MISMATCH); + } + return (ok==0); +} + +/* + * Computes public keys for GOST R 34.10-94 algorithm + * + */ +int gost94_compute_public(DSA *dsa) +{ + /* Now fill algorithm parameters with correct values */ + BN_CTX *ctx = BN_CTX_new(); + if (!dsa->g) { + GOSTerr(GOST_F_GOST_COMPUTE_PUBLIC,GOST_R_KEY_IS_NOT_INITALIZED); + return 0; + } + /* Compute public key y = a^x mod p */ + dsa->pub_key=BN_new(); + BN_mod_exp(dsa->pub_key, dsa->g,dsa->priv_key,dsa->p,ctx); + BN_CTX_free(ctx); + return 1; +} + +/* + * Fill GOST 94 params, searching them in R3410_paramset array + * by nid of paramset + * + */ +int fill_GOST94_params(DSA *dsa,int nid) { + R3410_params *params=R3410_paramset; + while (params->nid!=NID_undef && params->nid !=nid) params++; + if (params->nid == NID_undef) + { + GOSTerr(GOST_F_FILL_GOST94_PARAMS,GOST_R_UNSUPPORTED_PARAMETER_SET); + return 0; + } +#define dump_signature(a,b,c) + if (dsa->p) { BN_free(dsa->p); } + dsa->p=NULL; + BN_dec2bn(&(dsa->p),params->p); + if (dsa->q) { BN_free(dsa->q); } + dsa->q=NULL; + BN_dec2bn(&(dsa->q),params->q); + if (dsa->g) { BN_free(dsa->g); } + dsa->g=NULL; + BN_dec2bn(&(dsa->g),params->a); + return 1; +} + +/* + * Generate GOST R 34.10-94 keypair + * + * + */ +int gost_sign_keygen(DSA *dsa) +{ + dsa->priv_key = BN_new(); + BN_rand_range(dsa->priv_key,dsa->q); + return gost94_compute_public( dsa); +} +/* Unpack signature according to cryptocom rules */ + +DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen) +{ + DSA_SIG *s; + s = DSA_SIG_new(); + if (s == NULL) { + GOSTerr(GOST_F_UNPACK_CC_SIGNATURE,GOST_R_NO_MEMORY); + return(NULL); + } + s->r = getbnfrombuf(sig, siglen/2); + s->s = getbnfrombuf(sig + siglen/2, siglen/2); + return s; +} +/* Unpack signature according to cryptopro rules */ +DSA_SIG *unpack_cp_signature(const unsigned char *sig,size_t siglen) +{ + DSA_SIG *s; + + s = DSA_SIG_new(); + if (s == NULL) { + GOSTerr(GOST_F_UNPACK_CP_SIGNATURE,GOST_R_NO_MEMORY); + return NULL; + } + s->s = getbnfrombuf(sig , siglen/2); + s->r = getbnfrombuf(sig + siglen/2, siglen/2); + return s; +} +/* Convert little-endian byte array into bignum */ +BIGNUM *hashsum2bn(const unsigned char *dgst) +{ unsigned char buf[32]; + int i; + for (i=0;i<32;i++) { + buf[31-i]=dgst[i]; + } + return getbnfrombuf(buf,32); +} + +/* Convert byte buffer to bignum, skipping leading zeros*/ +BIGNUM *getbnfrombuf(const unsigned char *buf,size_t len) { + while (*buf==0&&len>0) { + buf++; len--; + } + if (len) { + return BN_bin2bn(buf,len,NULL); + } else { + BIGNUM *b=BN_new(); + BN_zero(b); + return b; + } +} +/* Pack bignum into byte buffer of given size, filling all leading bytes + * by zeros */ +int store_bignum(BIGNUM *bn, unsigned char *buf,int len) { + int bytes = BN_num_bytes(bn); + if (bytes>len) return 0; + memset(buf,0,len); + BN_bn2bin(bn,buf+len-bytes); + return 1; +} + diff --git a/engines/ccgost/gosthash.c b/engines/ccgost/gosthash.c new file mode 100644 index 0000000000..5978dbabaa --- /dev/null +++ b/engines/ccgost/gosthash.c @@ -0,0 +1,256 @@ +/********************************************************************** + * gosthash.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of GOST R 34.11-94 hash function * + * uses on gost89.c and gost89.h Doesn't need OpenSSL * + **********************************************************************/ +#include + +#include "gost89.h" +#include "gosthash.h" + + +/* Use OPENSSL_malloc for memory allocation if compiled with + * -DOPENSSL_BUILD, and libc malloc otherwise + */ +#ifndef MYALLOC +# ifdef OPENSSL_BUILD +# include +# define MYALLOC(size) OPENSSL_malloc(size) +# define MYFREE(ptr) OPENSSL_free(ptr) +# else +# define MYALLOC(size) malloc(size) +# define MYFREE(ptr) free(ptr) +# endif +#endif +/* Following functions are various bit meshing routines used in + * GOST R 34.11-94 algorithms */ +static void swap_bytes (byte *w, byte *k) +{ + int i,j; + for (i=0;i<4;i++) + for (j=0;j<8;j++) + k[i+4*j]=w[8*i+j]; + +} +/* was A_A */ +static void circle_xor8 (const byte *w, byte *k) +{ + byte buf[8]; + int i; + memcpy(buf,w,8); + memcpy(k,w+8,24); + for(i=0;i<8;i++) + k[i+24]=buf[i]^k[i]; +} +/* was R_R */ +static void transform_3 (byte *data) +{ + unsigned short int acc; + acc=(data[0]^data[2]^data[4]^data[6]^data[24]^data[30])| + ((data[1]^data[3]^data[5]^data[7]^data[25]^data[31])<<8); + memmove(data,data+2,30); + data[30]=acc&0xff; + data[31]=acc>>8; +} + +/* Adds blocks of N bytes modulo 2**(8*n). Returns carry*/ +static int add_blocks(int n,byte *left, const byte *right) +{ + int i; + int carry=0; + int sum; + for (i=0;i>8; + } + return carry; +} +/* Xor two sequences of bytes */ +static void xor_blocks (byte *result,const byte *a,const byte *b,size_t len) { + size_t i; + for (i=0;icipher_ctx = (gost_ctx *)MYALLOC(sizeof(gost_ctx)); + if (!ctx->cipher_ctx) { + return 0; + } + gost_init(ctx->cipher_ctx,subst_block); + return 1; +} +/* + * Free cipher CTX if it is dynamically allocated. Do not use + * if cipher ctx is statically allocated as in OpenSSL implementation of + * GOST hash algroritm + * + */ +void done_gost_hash_ctx(gost_hash_ctx *ctx) +{ + /* No need to use gost_destroy, because cipher keys are not really + * secret when hashing */ + MYFREE(ctx->cipher_ctx); +} +/* + * reset state of hash context to begin hashing new message + */ +int start_hash(gost_hash_ctx *ctx) { + if (!ctx->cipher_ctx) return 0; + memset(&(ctx->H),0,32); + memset(&(ctx->S),0,32); + ctx->len = 0L; + ctx->left=0; + return 1; +} +/* + * Hash block of arbitrary length + * + * + */ +int hash_block(gost_hash_ctx *ctx,const byte *block, size_t length) { + const byte *curptr=block; + const byte *barrier=block+(length-32);/* Last byte we can safely hash*/ + gost_ctx *save_c = ctx->cipher_ctx; + if (ctx->left) { + /*There are some bytes from previous step*/ + int add_bytes = 32-ctx->left; + if (add_bytes>length) { + add_bytes = length; + } + memcpy(&(ctx->remainder[ctx->left]),block,add_bytes); + ctx->left+=add_bytes; + if (ctx->left<32) { + return 1; + } + if (ctx->left>32) { + abort(); + } + curptr=block+add_bytes; + hash_step(ctx->cipher_ctx,ctx->H,ctx->remainder); + if (save_c!=ctx->cipher_ctx) { + abort(); + } + add_blocks(32,ctx->S,ctx->remainder); + if (save_c!=ctx->cipher_ctx) { + abort(); + } + ctx->len+=32; + ctx->left=0; + } + while (curptr<=barrier) + { + hash_step(ctx->cipher_ctx,ctx->H,curptr); + if (save_c!=ctx->cipher_ctx) { + abort(); + } + + add_blocks(32,ctx->S,curptr); + if (save_c!=ctx->cipher_ctx) { + abort(); + } + ctx->len+=32; + curptr+=32; + } + if (curptr!=block+length) { + ctx->left=block+length-curptr; + if (ctx->left>32) { + abort(); + } + memcpy(ctx->remainder,curptr,ctx->left); + } + return 1; +} +/* + * Compute hash value from current state of ctx + * state of hash ctx becomes invalid and cannot be used for further + * hashing. + */ +int finish_hash(gost_hash_ctx *ctx,byte *hashval) { + byte buf[32]; + byte H[32]; + byte S[32]; + long long fin_len=ctx->len; + byte *bptr; + memcpy(H,ctx->H,32); + memcpy(S,ctx->S,32); + if (ctx->left) { + memset(buf,0,32); + memcpy(buf,ctx->remainder,ctx->left); + hash_step(ctx->cipher_ctx,H,buf); + add_blocks(32,S,buf); + fin_len+=ctx->left; + } + memset(buf,0,32); + bptr=buf; + fin_len<<=3; /* Hash length in BITS!!*/ + while(fin_len>0) { + *(bptr++)=fin_len&0xFF; + fin_len>>=8; + }; + hash_step(ctx->cipher_ctx,H,buf); + hash_step(ctx->cipher_ctx,H,S); + memcpy(hashval,H,32); + return 1; +} + diff --git a/engines/ccgost/gosthash.h b/engines/ccgost/gosthash.h new file mode 100644 index 0000000000..d9889cae2d --- /dev/null +++ b/engines/ccgost/gosthash.h @@ -0,0 +1,39 @@ +/********************************************************************** + * gosthash.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of GOST R 34.11-94 hash functions * + * uses and gost89.h Doesn't need OpenSSL * + **********************************************************************/ +#ifndef GOSTHASH_H +#define GOSTHASH_H +#include "gost89.h" +#include +typedef struct gost_hash_ctx { + long long len; + gost_ctx *cipher_ctx; + int left; + byte H[32]; + byte S[32]; + byte remainder[32]; +} gost_hash_ctx; + + +/* Initalizes gost hash ctx, including creation of gost cipher ctx */ + +int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block); +void done_gost_hash_ctx(gost_hash_ctx *ctx); + +/* Cleans up all fields, except cipher ctx preparing ctx for computing + * of new hash value */ +int start_hash(gost_hash_ctx *ctx); + +/* Hashes block of data */ +int hash_block(gost_hash_ctx *ctx, const byte *block, size_t length); + +/* Finalizes computation of hash and fills buffer (which should be at + * least 32 bytes long) with value of computed hash. */ +int finish_hash(gost_hash_ctx *ctx, byte *hashval); + +#endif diff --git a/engines/ccgost/gostkeyx.h b/engines/ccgost/gostkeyx.h new file mode 100644 index 0000000000..56fc6a2372 --- /dev/null +++ b/engines/ccgost/gostkeyx.h @@ -0,0 +1,42 @@ +#ifndef GOSTKEYX_H +#define GOSTKEYX_H +/********************************************************************** + * gostkeyx.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of the key transport functions for GOST pkey methods * + * * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include "gost89.h" +/* EVP_PKEY_METHOD callbacks */ +/* From gost94_keyx.c */ +int pkey_GOST94cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len ); +int pkey_GOST94cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len); + +int pkey_GOST94cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* in, size_t in_len ); +int pkey_GOST94cc_decrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * in,size_t in_len); +/* From gost2001_keyx.c */ +int pkey_GOST01cp_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* key, size_t key_len ); +int pkey_GOST01cc_encrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * key,size_t key_len); + +int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* in, size_t in_len ); +int pkey_GOST01cc_decrypt (EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char * in,size_t in_len); + +/* Internal functions to make error processing happy */ +int decrypt_cryptocom_key(unsigned char *sess_key,int max_key_len, + const unsigned char *crypted_key,int crypted_key_len, gost_ctx *ctx); +int encrypt_cryptocom_key(const unsigned char *sess_key,int key_len, + unsigned char *crypted_key, gost_ctx *ctx); +/*int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh) ;*/ +/* + * Computes 256 bit key exchange key for CryptoCom variation of GOST 94 + * algorithm + *//* +int make_gost_shared_key(DH *dh,EVP_PKEY *pubk,unsigned char *shared_key) ; +DH *make_ephemeral_key(EVP_PKEY *pubk,BIGNUM *ephemeral_key); +int make_cp_exchange_key(DH *dh,EVP_PKEY *pubk, unsigned char *shared_key); +*/ +#endif diff --git a/engines/ccgost/gostsum.1 b/engines/ccgost/gostsum.1 new file mode 100644 index 0000000000..3dfd7e40d0 --- /dev/null +++ b/engines/ccgost/gostsum.1 @@ -0,0 +1,78 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.TH MD5SUM 1 "29th November 1995" "Lankester et al." "Debian GNU/Linux" +.SH NAME +gostsum \- generates or checks GOST R34.11-94 message digests + +.SH SYNOPSIS +.B gostsum +[\-bv] [\-c [file]] | [file...] + +.SH DESCRIPTION +.B gostsum +generates or checks GOST hash sums. The algorithm to generate the +is reasonably fast and strong enough for most cases. Exact +specification of the algorithm is in +.I GOST R34.11-94. + +Normally +.B gostsum +generates checksums of all files given to it as a parameter and prints +the checksums followed by the filenames. If, however, +.B \-c +is specified, only one filename parameter is allowed. This file should +contain checksums and filenames to which these checksums refer to, and +the files listed in that file are checked against the checksums listed +there. See option +.B \-c +for more information. + +.SS OPTIONS +.TP +.B \-b +Use binary mode. In unix environment, only difference between this and +the normal mode is an asterisk preceding the filename in the output. +.TP +.B \-c +Check md5sum of all files listed in +.I file +against the checksum listed in the same file. The actual format of that +file is the same as output of +.B md5sum. +That is, each line in the file describes a file. A line looks like: + +.B + +So, for example, if a file was created and its message digest calculated +like so: + +.B echo foo > hash\-test\-file; gost5sum hash\-test\-file + +.B gost5sum +would report: + +.B d3b07384d113edec49eaa6238ad5ff00\ md5\-test\-file + +.TP +.B \-v +Be more verbose. Print filenames when checking (with \-c). + +.TP +.B -t +Use test parameter set. +.B gostsum supports two sets of parameters (which are really parameters +of GOST 28147-89 block cipher) specified in the IETF draft +.B draft-popov-cryptopro-cpalgs-02.txt +By default, cryptopro paramset is used. This option enables use of test +paramset as specified in appendices to the GOST. + +.SH BUGS + +This manpage is not quite accurate and has formatting inconsistent +with other manpages. + +.B gostsum +does not accept standard options like +.BR \-\-help . + +.SH AUTHOR + diff --git a/engines/ccgost/gostsum.c b/engines/ccgost/gostsum.c new file mode 100644 index 0000000000..92bd5f9419 --- /dev/null +++ b/engines/ccgost/gostsum.c @@ -0,0 +1,184 @@ +/********************************************************************** + * gostsum.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Almost drop-in replacement for md5sum and sha1sum * + * which computes GOST R 34.11-94 hashsum instead * + * * + **********************************************************************/ +#include +#include +#include +#include +#include +#include +#include "gosthash.h" +#define BUF_SIZE 262144 +int hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode); +int hash_stream(gost_hash_ctx *ctx,int fd, char *sum); +int get_line(FILE *f,char *hash,char *filename); +void help() +{ + fprintf(stderr,"gostsum [-bvt] [-c [file]]| [files]\n" + "\t-c check message digests (default is generate)\n" + "\t-v verbose, print file names when checking\n" + "\t-b read files in binary mode\n" + "\t-t use test GOST paramset (default is CryptoPro paramset)\n" +"The input for -c should be the list of message digests and file names\n" +"that is printed on stdout by this program when it generates digests.\n"); +exit(3); +} + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +int main(int argc,char **argv) +{ + int c,i; + int verbose=0; + int errors=0; + int open_mode = O_RDONLY; + gost_subst_block *b= &GostR3411_94_CryptoProParamSet; + FILE *check_file = NULL; + gost_hash_ctx ctx; + + while( (c=getopt(argc,argv,"bc::tv"))!=-1) + { + switch (c) + { + case 'v': verbose=1; break; + case 't': b= &GostR3411_94_TestParamSet; break; + case 'b': open_mode |= O_BINARY; break; + case 'c': if (optarg) { + check_file = fopen(optarg,"r"); + if (!check_file) { + perror(optarg); + exit(2); + } + } else { + check_file= stdin; + } + break; + default: + fprintf(stderr,"invalid option %c",optopt); + help(); + } + } + init_gost_hash_ctx(&ctx,b); + if (check_file) + { + char inhash[65],calcsum[65],filename[PATH_MAX]; + int failcount=0,count=0;; + if (check_file==stdin && optind0) { + hash_block(ctx,buffer,bytes); + } + if (bytes<0) { + return 0; + } + finish_hash(ctx,buffer); + for (i=0;i<32;i++) { + sprintf(sum+2*i,"%02x",buffer[31-i]); + } + return 1; +} + +int get_line(FILE *f,char *hash,char *filename) { + int i; + if (fread(hash,1,64,f)<64) return 0; + hash[64]=0; + for (i=0;i<64;i++) + { + if (hash[i]<'0' || (hash[i]>'9' && hash[i]<'A') || (hash[i]>'F' + && hash[i]<'a')||hash[i]>'f') + { + fprintf(stderr,"Not a hash value '%s'\n",hash); + return 0; + } + } + if (fgetc(f)!=' ') { + fprintf(stderr,"Malformed input line\n"); + return 0; + } + i=strlen(fgets(filename,PATH_MAX,f)); + while (filename[--i]=='\n'||filename[i]=='\r') filename[i]=0; + return 1; +} diff --git a/engines/ccgost/keywrap.c b/engines/ccgost/keywrap.c new file mode 100644 index 0000000000..4e7d675a73 --- /dev/null +++ b/engines/ccgost/keywrap.c @@ -0,0 +1,97 @@ +/********************************************************************** + * keywrap.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of CryptoPro key wrap algorithm, as defined in * + * RFC 4357 p 6.3 and 6.4 * + * Doesn't need OpenSSL * + **********************************************************************/ +#include +#include "gost89.h" +#include "keywrap.h" + +/* Diversifies key using random UserKey Material + * Implements RFC 4357 p 6.5 key diversification algorithm + * + * inputKey - 32byte key to be diversified + * ukm - 8byte user key material + * outputKey - 32byte buffer to store diversified key + * + */ +void keyDiversifyCryptoPro(gost_ctx *ctx,const unsigned char *inputKey, const unsigned char *ukm, unsigned char *outputKey) +{ + + u4 k,s1,s2; + int i,j,mask; + unsigned char S[8]; + memcpy(outputKey,inputKey,32); + for (i=0;i<8;i++) { + /* Make array of integers from key */ + /* Compute IV S*/ + s1=0,s2=0; + for (j=0,mask=1;j<8;j++,mask<<=1) { + k=((u4)outputKey[4*j])|(outputKey[4*j+1]<<8)| + (outputKey[4*j+2]<<16)|(outputKey[4*j+3]<<24); + if (mask & ukm[i]) { + s1+=k; + } else { + s2+=k; + } + } + S[0]=s1&0xff; S[1]=(s1>>8)&0xff; S[2]=(s1>>16)&0xff; S[3]=(s1>>24)&0xff; + S[4]=s2&0xff; S[5]=(s2>>8)&0xff; S[6]=(s2>>16)&0xff; S[7]=(s2>>24)&0xff; + gost_key(ctx,outputKey); + gost_enc_cfb(ctx,S,outputKey,outputKey,4); + } +} + + +/* + * Wraps key using RFC 4357 6.3 + * ctx - gost encryption context, initialized with some S-boxes + * keyExchangeKey (KEK) 32-byte (256-bit) shared key + * ukm - 8 byte (64 bit) user key material, + * sessionKey - 32-byte (256-bit) key to be wrapped + * wrappedKey - 44-byte buffer to store wrapped key + */ + +int keyWrapCryptoPro(gost_ctx *ctx,const unsigned char *keyExchangeKey, const unsigned char *ukm, + const unsigned char *sessionKey, unsigned char *wrappedKey) +{ + unsigned char kek_ukm[32]; + keyDiversifyCryptoPro(ctx,keyExchangeKey,ukm,kek_ukm); + gost_key(ctx,kek_ukm); + memcpy(wrappedKey,ukm,8); + gost_enc(ctx,sessionKey,wrappedKey+8,4); + gost_mac_iv(ctx,32,ukm,sessionKey,32,wrappedKey+40); + return 1; +} +/* + * Unwraps key using RFC 4357 6.4 + * ctx - gost encryption context, initialized with some S-boxes + * keyExchangeKey 32-byte shared key + * wrappedKey 44 byte key to be unwrapped (concatenation of 8-byte UKM, + * 32 byte encrypted key and 4 byte MAC + * + * sessionKEy - 32byte buffer to store sessionKey in + * Returns 1 if key is decrypted successfully, and 0 if MAC doesn't match + */ + +int keyUnwrapCryptoPro(gost_ctx *ctx,const unsigned char *keyExchangeKey, + const unsigned char *wrappedKey, unsigned char *sessionKey) +{ + unsigned char kek_ukm[32],cek_mac[4]; + keyDiversifyCryptoPro(ctx,keyExchangeKey,wrappedKey + /* First 8 bytes of wrapped Key is ukm */ + ,kek_ukm); + gost_key(ctx,kek_ukm); + gost_dec(ctx,wrappedKey+8,sessionKey,4); + gost_mac_iv(ctx,32,wrappedKey,sessionKey,32,cek_mac); + if (memcmp(cek_mac,wrappedKey+40,4)) { + return 0; + } + return 1; +} + + diff --git a/engines/ccgost/keywrap.h b/engines/ccgost/keywrap.h new file mode 100644 index 0000000000..5553c92ff6 --- /dev/null +++ b/engines/ccgost/keywrap.h @@ -0,0 +1,56 @@ +/********************************************************************** + * keywrap.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of CryptoPro key wrap algorithm, as defined in * + * RFC 4357 p 6.3 and 6.4 * + * Doesn't need OpenSSL * + **********************************************************************/ +#ifndef GOST_KEYWRAP_H +#define GOST_KEYWRAP_H +#include +#include "gost89.h" +/* Diversifies key using random UserKey Material + * Implements RFC 4357 p 6.5 key diversification algorithm + * + * inputKey - 32byte key to be diversified + * ukm - 8byte user key material + * outputKey - 32byte buffer to store diversified key + * + */ +void keyDiversifyCryptoPro(gost_ctx *ctx, + const unsigned char *inputKey, + const unsigned char *ukm, + unsigned char *outputKey); +/* + * Wraps key using RFC 4357 6.3 + * ctx - gost encryption context, initialized with some S-boxes + * keyExchangeKey (KEK) 32-byte (256-bit) shared key + * ukm - 8 byte (64 bit) user key material, + * sessionKey - 32-byte (256-bit) key to be wrapped + * wrappedKey - 44-byte buffer to store wrapped key + */ + +int keyWrapCryptoPro(gost_ctx *ctx, + const unsigned char *keyExchangeKey, + const unsigned char *ukm, + const unsigned char *sessionKey, + unsigned char *wrappedKey) ; +/* + * Unwraps key using RFC 4357 6.4 + * ctx - gost encryption context, initialized with some S-boxes + * keyExchangeKey 32-byte shared key + * wrappedKey 44 byte key to be unwrapped (concatenation of 8-byte UKM, + * 32 byte encrypted key and 4 byte MAC + * + * sessionKEy - 32byte buffer to store sessionKey in + * Returns 1 if key is decrypted successfully, and 0 if MAC doesn't match + */ + + +int keyUnwrapCryptoPro(gost_ctx *ctx, + const unsigned char *keyExchangeKey, + const unsigned char *wrappedKey, + unsigned char *sessionKey) ; +#endif diff --git a/engines/ccgost/md.h b/engines/ccgost/md.h new file mode 100644 index 0000000000..7cf0af2a6b --- /dev/null +++ b/engines/ccgost/md.h @@ -0,0 +1,41 @@ +#ifndef GOST_MD_H +#define GOST_MD_H +/********************************************************************** + * md.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of GOST R 34.11 bindings to OpenSSL * + * * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include "gost89.h" +#include "gosthash.h" +#ifdef __cplusplus + extern "C" { +#endif + + /* Structure used as EVP_MD_CTX-md_data. + * It allows to avoid storing in the md-data pointers to + * dynamically allocated memory. + * + * I cannot invent better way to avoid memory leaks, because + * openssl insist on invoking Init on Final-ed digests, and there + * is no reliable way to find out whether pointer in the passed + * md_data is valid or not. + * */ +struct ossl_gost_digest_ctx { + gost_hash_ctx dctx; + gost_ctx cctx; +}; + +extern EVP_MD digest_gost; + + +#ifdef __cplusplus + }; +#endif +#endif diff --git a/engines/ccgost/md_gost.c b/engines/ccgost/md_gost.c new file mode 100644 index 0000000000..b0fede6d34 --- /dev/null +++ b/engines/ccgost/md_gost.c @@ -0,0 +1,69 @@ +/********************************************************************** + * md_gost.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * OpenSSL interface to GOST R 34.11-94 hash functions * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include "md.h" +#include "gosthash.h" +#include "e_gost_err.h" + +/* implementation of GOST 34.11 hash function See gost_md.c*/ +static int gost_digest_init(EVP_MD_CTX *ctx); +static int gost_digest_update(EVP_MD_CTX *ctx, const void *data, size_t count); +static int gost_digest_final(EVP_MD_CTX *ctx,unsigned char *md); +static int gost_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from); +static int gost_digest_cleanup(EVP_MD_CTX *ctx); + +EVP_MD digest_gost= +{ + NID_id_GostR3411_94, + NID_undef, + 32, + EVP_MD_FLAG_PKEY_METHOD_SIGNATURE, + gost_digest_init, + gost_digest_update, + gost_digest_final, + gost_digest_copy, + gost_digest_cleanup, + NULL, + NULL, + {NID_undef,NID_undef,0,0,0}, + 32, + sizeof(struct ossl_gost_digest_ctx ), + NULL +}; + +int gost_digest_init(EVP_MD_CTX *ctx) +{ + struct ossl_gost_digest_ctx *c = ctx->md_data; + memset(&(c->dctx),0,sizeof(gost_hash_ctx)); + gost_init(&(c->cctx),&GostR3411_94_CryptoProParamSet); + c->dctx.cipher_ctx= &(c->cctx); + return 1; +} + +int gost_digest_update(EVP_MD_CTX *ctx,const void *data,size_t count) +{ + return hash_block((gost_hash_ctx *)ctx->md_data,data,count); +} + +int gost_digest_final(EVP_MD_CTX *ctx,unsigned char *md) +{ + return finish_hash((gost_hash_ctx *)ctx->md_data,md); + +} + +int gost_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from) +{ + memcpy(to->md_data,from->md_data,sizeof(struct ossl_gost_digest_ctx)); + return 1; +} + +int gost_digest_cleanup(EVP_MD_CTX *ctx) { + memset(ctx->md_data,0,sizeof(struct ossl_gost_digest_ctx)); + return 1; +} diff --git a/engines/ccgost/meth.h b/engines/ccgost/meth.h new file mode 100644 index 0000000000..863046648c --- /dev/null +++ b/engines/ccgost/meth.h @@ -0,0 +1,22 @@ +#ifndef CCE_METH_H +#define CCE_METH_H +/********************************************************************** + * meth.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of method registration functions * + * * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + int register_ameth_gost (int nid, EVP_PKEY_ASN1_METHOD **ameth, const char* pemstr, const char* info); + int register_pmeth_gost (int id, EVP_PKEY_METHOD **pmeth, int flags); +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/engines/ccgost/params.c b/engines/ccgost/params.c new file mode 100644 index 0000000000..37aa23d653 --- /dev/null +++ b/engines/ccgost/params.c @@ -0,0 +1,198 @@ +/********************************************************************** + * params.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Definitions of GOST R 34.10 parameter sets, defined in RFC 4357 * + * OpenSSL 0.9.9 libraries required to compile and use * + * this code * + **********************************************************************/ +#include "paramset.h" +#include +/* Parameters of GOST 34.10 */ + +R3410_params R3410_paramset[]={ +/* Paramset A */ +{NID_id_GostR3410_94_CryptoPro_A_ParamSet, +"100997906755055304772081815535925224869" +"8410825720534578748235158755771479905292727772441528526992987964833" +"5669968284202797289605274717317548059048560713474685214192868091256" +"1502802222185647539190902656116367847270145019066794290930185446216" +"3997308722217328898303231940973554032134009725883228768509467406639" +"62", +"127021248288932417465907042777176443525" +"7876535089165358128175072657050312609850984974231883334834011809259" +"9999512098893413065920561499672425412104927434935707492031276956145" +"1689224110579311248812610229678534638401693520013288995000362260684" +"2227508135323070045173416336850045410625869714168836867788425378203" +"83", +"683631961449557007844441656118272528951" +"02170888761442055095051287550314083023"}, +{NID_id_GostR3410_94_CryptoPro_B_ParamSet, +"429418261486158041438734477379555023926" +"7234596860714306679811299408947123142002706038521669956384871995765" +"7284814898909770759462613437669456364882730370838934791080835932647" +"9767786019153434744009610342313166725786869204821949328786333602033" +"8479709268434224762105576023501613261478065276102850944540333865234" +"1", +"139454871199115825601409655107690713107" +"0417070599280317977580014543757653577229840941243685222882398330391" +"1468164807668823692122073732267216074074777170091113455043205380464" +"7694904686120113087816240740184800477047157336662926249423571248823" +"9685422217536601433914856808405203368594584948031873412885804895251" +"63", +"79885141663410976897627118935756323747307951916507639758300472692338873533959" +}, +{NID_id_GostR3410_94_CryptoPro_C_ParamSet, +"816552717970881016017893191415300348226" +"2544051353358162468249467681876621283478212884286545844013955142622" +"2087723485023722868022275009502224827866201744494021697716482008353" +"6398202298024892620480898699335508064332313529725332208819456895108" +"5155178100221003459370588291073071186553005962149936840737128710832" +"3", +"110624679233511963040518952417017040248" +"5862954819831383774196396298584395948970608956170224210628525560327" +"8638246716655439297654402921844747893079518669992827880792192992701" +"1428546551433875806377110443534293554066712653034996277099320715774" +"3542287621283671843703709141350171945045805050291770503634517804938" +"01", +"113468861199819350564868233378875198043" +"267947776488510997961231672532899549103" +}, +{NID_id_GostR3410_94_CryptoPro_D_ParamSet, +"756976611021707301782128757801610628085" +"5283803109571158829574281419208532589041660017017859858216341400371" +"4687551412794400562878935266630754392677014598582103365983119173924" +"4732511225464712252386803315902707727668715343476086350472025298282" +"7271461690125050616858238384366331089777463541013033926723743254833" +"7", +"905457649621929965904290958774625315611" +"3056083907389766971404812524422262512556054474620855996091570786713" +"5849550236741915584185990627801066465809510095784713989819413820871" +"5964648914493053407920737078890520482730623038837767710173664838239" +"8574828787891286471201460474326612697849693665518073864436497893214" +"9", +"108988435796353506912374591498972192620" +"190487557619582334771735390599299211593" +}, + +{NID_id_GostR3410_94_CryptoPro_XchA_ParamSet, +"1335318132727206734338595199483190012179423759678474868994823595993" +"6964252873471246159040332773182141032801252925387191478859899310331" +"0567744136196364803064721377826656898686468463277710150809401182608" +"7702016153249904683329312949209127762411378780302243557466062839716" +"59376426832674269780880061631528163475887", +"14201174159756348119636828602231808974327613839524373876287257344192" +"74593935127189736311660784676003608489466235676257952827747192122419" +"29071046134208380636394084512691828894000571524625445295769349356752" +"72895683154177544176313938445719175509684710784659566254794231229333" +"8483924514339614727760681880609734239", +"91771529896554605945588149018382750217296858393520724172743325725474" +"374979801" +}, +{NID_id_GostR3410_94_CryptoPro_XchB_ParamSet, +"8890864727828423151699995801875757891031463338652579140051973659" +"3048131440685857067369829407947744496306656291505503608252399443" +"7900272386749145996230867832228661977543992816745254823298629859" +"8753575466286051738837854736167685769017780335804511440773337196" +"2538423532919394477873664752824509986617878992443177", +"1028946126624994859676552074360530315217970499989304888248413244" +"8474923022758470167998871003604670704877377286176171227694098633" +"1539089568784129110109512690503345393869871295783467257264868341" +"7200196629860561193666752429682367397084815179752036423595736533" +"68957392061769855284593965042530895046088067160269433", +"9109671391802626916582318050603555673628769498182593088388796888" +"5281641595199" +}, +{NID_id_GostR3410_94_CryptoPro_XchC_ParamSet, +"4430618464297584182473135030809859326863990650118941756995270074" +"8609973181426950235239623239110557450826919295792878938752101867" +"7047181623251027516953100431855964837602657827828194249605561893" +"6965865325513137194483136247773653468410118796740709840825496997" +"9375560722345106704721086025979309968763193072908334", +"1246996366993477513607147265794064436203408861395055989217248455" +"7299870737698999651480662364723992859320868822848751165438350943" +"3276647222625940615560580450040947211826027729977563540237169063" +"0448079715771649447778447000597419032457722226253269698374446528" +"35352729304393746106576383349151001715930924115499549", +"6787876137336591234380295020065682527118129468050147943114675429" +"4748422492761" +}, + + +{NID_undef,NULL, NULL, NULL} +}; + +R3410_2001_params R3410_2001_paramset[]={ + /* default_cc_sign01_param 1.2.643.2.9.1.8.1 */ + {NID_id_GostR3410_2001_ParamSet_cc, + /* A */ + "C0000000000000000000000000000000000000000000000000000000000003c4", + /* B */ + "2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c", + /* P */ + "C0000000000000000000000000000000000000000000000000000000000003C7", + /* Q */ + "5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85", + /* X */ + "2", + /* Y */ + "a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c" + }, + /* 1.2.643.2.2.35.0 */ + {NID_id_GostR3410_2001_TestParamSet, + "7", + "5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E", + "8000000000000000000000000000000000000000000000000000000000000431", + "8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3", + "2", + "08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8" + }, + /*1.2.643.2.2.35.1*/ + {NID_id_GostR3410_2001_CryptoPro_A_ParamSet, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", + "a6", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", + "1", + "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14" + }, + /*1.2.643.2.2.35.2*/ + {NID_id_GostR3410_2001_CryptoPro_B_ParamSet, + "8000000000000000000000000000000000000000000000000000000000000C96", + "3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B", + "8000000000000000000000000000000000000000000000000000000000000C99", + "800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F", + "1", + "3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC" + }, + /*1.2.643.2.2.35.3*/ + {NID_id_GostR3410_2001_CryptoPro_C_ParamSet, + "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598", + "805a", + "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B", + "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9", + "0", + "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67" + }, + /*1.2.643.2.2.36.0*/ + {NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", + "a6", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", + "1", + "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14" + }, + /*1.2.643.2.2.36.1*/ + {NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet, + "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598", + "805a", + "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B", + "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9", + "0", + "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67" + }, + { 0,NULL,NULL,NULL,NULL,NULL,NULL + } +}; diff --git a/engines/ccgost/paramset.h b/engines/ccgost/paramset.h new file mode 100644 index 0000000000..002ac7857b --- /dev/null +++ b/engines/ccgost/paramset.h @@ -0,0 +1,34 @@ +/********************************************************************** + * paramset.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of structures used to represent GOST R 34.10 * + * parameter sets, defined in RFC 4357 * + * OpenSSL 0.9.9 libraries required to compile and use * + * this code * + **********************************************************************/ +#ifndef GOST_PARAMSET_H +#define GOST_PARAMSET_H +typedef struct R3410 { + int nid; + char *a; + char *p; + char *q; +} R3410_params; + +extern R3410_params R3410_paramset[]; + +typedef struct R3410_2001 { + int nid; + char *a; + char *b; + char *p; + char *q; + char *x; + char *y; +} R3410_2001_params; + +extern R3410_2001_params R3410_2001_paramset[]; + +#endif diff --git a/engines/ccgost/pmeth.c b/engines/ccgost/pmeth.c new file mode 100644 index 0000000000..2698e4f937 --- /dev/null +++ b/engines/ccgost/pmeth.c @@ -0,0 +1,514 @@ +/********************************************************************** + * pmeth.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of RFC 4357 (GOST R 34.10) Publick key method * + * for OpenSSL * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include +#include +#include +#include +#include +#include "meth.h" +#include "pmeth.h" +#include "sign.h" +#include "gostkeyx.h" +#include "paramset.h" +#include "tools.h" +#include "e_gost_err.h" +/*-------init, cleanup, copy - uniform for all algs ---------------*/ +/* Allocates new gost_pmeth_data structure and assigns it as data */ +static int pkey_gost_init(EVP_PKEY_CTX *ctx) { + struct gost_pmeth_data *data; + data = OPENSSL_malloc(sizeof(struct gost_pmeth_data)); + if (!data) return 0; + memset(data,0,sizeof(struct gost_pmeth_data)); + EVP_PKEY_CTX_set_data(ctx,data); + return 1; +} +/* Copies contents of gost_pmeth_data structure */ +static int pkey_gost_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) +{ + struct gost_pmeth_data *dst_data,*src_data; + if (!pkey_gost_init(dst)) { + return 0; + } + src_data = EVP_PKEY_CTX_get_data(src); + dst_data = EVP_PKEY_CTX_get_data(dst); + *dst_data = *src_data; + if (src_data -> eph_seckey) { + dst_data ->eph_seckey = NULL; + } + return 1; +} +/* Frees up gost_pmeth_data structure */ +static void pkey_gost_cleanup (EVP_PKEY_CTX *ctx) { + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + if (data->eph_seckey) EVP_PKEY_free(data->eph_seckey); + OPENSSL_free(data); +} +/* --------------------- control functions ------------------------------*/ +static int pkey_gost_ctrl (EVP_PKEY_CTX *ctx, int type, int p1, void *p2) +{ + struct gost_pmeth_data *pctx = (struct gost_pmeth_data*)EVP_PKEY_CTX_get_data(ctx); + switch (type) + { + case EVP_PKEY_CTRL_MD: + { + if (EVP_MD_type((const EVP_MD *)p2) != NID_id_GostR3411_94) { + GOSTerr(GOST_F_PKEY_GOST_CTRL, GOST_R_INVALID_DIGEST_TYPE); + return 0; + } + pctx->md = (EVP_MD *)p2; + return 1; + } + break; + + case EVP_PKEY_CTRL_PKCS7_ENCRYPT: + case EVP_PKEY_CTRL_PKCS7_DECRYPT: + case EVP_PKEY_CTRL_PKCS7_SIGN: + return 1; + + case EVP_PKEY_CTRL_GOST_PARAMSET: + pctx->sign_param_nid = (int)p1; + pctx->crypt_param_nid= (int)p2; + return 1; + + } + return -2; +} + +static int pkey_gost_ctrl94cc_str(EVP_PKEY_CTX *ctx, + const char *type, const char *value) +{ + if(!strcmp(type, param_ctrl_string)) { + return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, + NID_id_GostR3410_94_CryptoPro_A_ParamSet, + (void *)NID_id_Gost28147_89_cc); + } + return -2; +} + +static int pkey_gost_ctrl01cc_str(EVP_PKEY_CTX *ctx, + const char *type, const char *value) +{ + if(!strcmp(type, param_ctrl_string)) { + return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, + NID_id_GostR3410_2001_ParamSet_cc, + (void *) + NID_id_Gost28147_89_cc); + } + return -2; +} +static int pkey_gost_ctrl94_str(EVP_PKEY_CTX *ctx, + const char *type, const char *value) +{ + int param_nid=0; + if(!strcmp(type, param_ctrl_string)) { + if (!value) { + return 0; + } + if (strlen(value) == 1) { + switch(toupper(value[0])) { + case 'A': + param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet; + break; + case 'B': + param_nid = NID_id_GostR3410_94_CryptoPro_B_ParamSet; + break; + case 'C': + param_nid = NID_id_GostR3410_94_CryptoPro_C_ParamSet; + break; + case 'D': + param_nid = NID_id_GostR3410_94_CryptoPro_D_ParamSet; + break; + default: + return 0; + break; + } + } else if ((strlen(value) == 2) && (toupper(value[0]) == 'X')) { + switch (toupper(value[1])) { + case 'A': + param_nid = NID_id_GostR3410_94_CryptoPro_XchA_ParamSet; + break; + case 'B': + param_nid = NID_id_GostR3410_94_CryptoPro_XchB_ParamSet; + break; + case 'C': + param_nid = NID_id_GostR3410_94_CryptoPro_XchC_ParamSet; + break; + default: + return 0; + break; + } + } else { + R3410_params *p = R3410_paramset; + param_nid = OBJ_txt2nid(value); + if (param_nid == NID_undef) { + return 0; + } + for (;p->nid != NID_undef;p++) { + if (p->nid == param_nid) break; + } + if (p->nid == NID_undef) { + GOSTerr(GOST_F_PKEY_GOST_CTRL94_STR, + GOST_R_INVALID_PARAMSET); + return 0; + } + } + + return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, + param_nid, (void *)NID_id_Gost28147_89_CryptoPro_A_ParamSet); + } + return -2; +} + +static int pkey_gost_ctrl01_str(EVP_PKEY_CTX *ctx, + const char *type, const char *value) +{ + int param_nid=0; + if(!strcmp(type, param_ctrl_string)) { + if (!value) { + return 0; + } + if (strlen(value) == 1) { + switch(toupper(value[0])) { + case 'A': + param_nid = NID_id_GostR3410_2001_CryptoPro_A_ParamSet; + break; + case 'B': + param_nid = NID_id_GostR3410_2001_CryptoPro_B_ParamSet; + break; + case 'C': + param_nid = NID_id_GostR3410_2001_CryptoPro_C_ParamSet; + break; + case '0': + param_nid = NID_id_GostR3410_2001_TestParamSet; + break; + default: + return 0; + break; + } + } else if ((strlen(value) == 2) && (toupper(value[0]) == 'X')) { + switch (toupper(value[1])) { + case 'A': + param_nid = NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet; + break; + case 'B': + param_nid = NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet; + break; + default: + return 0; + break; + } + } else { + R3410_2001_params *p = R3410_2001_paramset; + param_nid = OBJ_txt2nid(value); + if (param_nid == NID_undef) { + return 0; + } + for (;p->nid != NID_undef;p++) { + if (p->nid == param_nid) break; + } + if (p->nid == NID_undef) { + GOSTerr(GOST_F_PKEY_GOST_CTRL01_STR, + GOST_R_INVALID_PARAMSET); + return 0; + } + } + + return pkey_gost_ctrl(ctx, EVP_PKEY_CTRL_GOST_PARAMSET, + param_nid, (void *)NID_id_Gost28147_89_CryptoPro_A_ParamSet); + } + return -2; +} +/* --------------------- key generation --------------------------------*/ +/* Generates GOST 94 key and assigns it setting specified type */ +static int pkey_gost94_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey,int type) +{ + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + DSA *dsa=NULL; + if (data->sign_param_nid == NID_undef) { + if (type== NID_id_GostR3410_94_cc) { + data->sign_param_nid = NID_id_GostR3410_94_CryptoPro_A_ParamSet; + } else { + GOSTerr(GOST_F_PKEY_GOST94_KEYGEN, + GOST_R_NO_PARAMETERS_SET); + return 0; + } + } + dsa = DSA_new(); + if (!fill_GOST94_params(dsa,data->sign_param_nid)) { + DSA_free(dsa); + return 0; + } + gost_sign_keygen(dsa); + EVP_PKEY_assign(pkey,type,dsa); + return 1; +} +/* Generates Gost_R3410_94_cc key */ +static int pkey_gost94cc_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + return pkey_gost94_keygen(ctx,pkey,NID_id_GostR3410_94_cc); +} + +/* Generates Gost_R3410_94_cp key */ +static int pkey_gost94cp_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + return pkey_gost94_keygen(ctx,pkey,NID_id_GostR3410_94); +} +/* Generates GOST_R3410 2001 key and assigns it using specified type */ +static int pkey_gost01_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey,int type) +{ + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + EC_KEY *ec=NULL; + if (data->sign_param_nid == NID_undef) { + if (type == NID_id_GostR3410_2001_cc) { + data->sign_param_nid = NID_id_GostR3410_2001_ParamSet_cc; + } else { + GOSTerr(GOST_F_PKEY_GOST01_KEYGEN, + GOST_R_NO_PARAMETERS_SET); + return 0; + } + } + ec = EC_KEY_new(); + if (!fill_GOST2001_params(ec,data->sign_param_nid)) { + EC_KEY_free(ec); + return 0; + } + gost2001_keygen(ec); + + EVP_PKEY_assign(pkey,type,ec); + return 1; +} +/* Generates GOST R3410 2001_cc key */ +static int pkey_gost01cc_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + return pkey_gost01_keygen(ctx,pkey,NID_id_GostR3410_2001_cc); +} + +/* Generates GOST R3410 2001_cp key */ +static int pkey_gost01cp_keygen (EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + return pkey_gost01_keygen(ctx,pkey,NID_id_GostR3410_2001); +} +/* ----------- sign callbacks --------------------------------------*/ +static int pkey_gost94_cc_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbs_len) +{ + DSA_SIG *unpacked_sig=NULL; + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); + if (!siglen) return 0; + if (!sig) + { + *siglen= 64; /* better to check size of pkey->pkey.dsa-q */ + return 1; + } + unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey)); + if (!unpacked_sig) { + return 0; + } + + return pack_sign_cc(unpacked_sig,32,sig,siglen); + + +} +static int pkey_gost94_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbs_len) +{ + DSA_SIG *unpacked_sig=NULL; + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); + if (!siglen) return 0; + if (!sig) + { + *siglen= 64; /* better to check size of pkey->pkey.dsa-q */ + return 1; + } + unpacked_sig = gost_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey)); + if (!unpacked_sig) { + return 0; + } + return pack_sign_cp(unpacked_sig,32,sig,siglen); + + +} +static int pkey_gost01_cc_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbs_len) +{ + DSA_SIG *unpacked_sig=NULL; + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); + if (!siglen) return 0; + if (!sig) + { + *siglen= 64; /* better to check size of curve order*/ + return 1; + } + unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey)); + if (!unpacked_sig) { + return 0; + } + return pack_sign_cc(unpacked_sig,32,sig,siglen); +} +static int pkey_gost01_cp_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbs_len) +{ + DSA_SIG *unpacked_sig=NULL; + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); + if (!siglen) return 0; + if (!sig) + { + *siglen= 64; /* better to check size of curve order*/ + return 1; + } + unpacked_sig = gost2001_do_sign(tbs,tbs_len,EVP_PKEY_get0(pkey)); + if (!unpacked_sig) { + return 0; + } + return pack_sign_cp(unpacked_sig,32,sig,siglen); +} +/* ------------------- verify callbacks ---------------------------*/ +static int pkey_gost94_cc_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, size_t tbs_len) +{ + int ok = 0; + EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx); + DSA_SIG *s=unpack_cc_signature(sig,siglen); + if (!s) return 0; + if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key)); + DSA_SIG_free(s); + return ok; +} + +static int pkey_gost94_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, size_t tbs_len) +{ + int ok = 0; + EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx); + DSA_SIG *s=unpack_cp_signature(sig,siglen); + if (!s) return 0; + if (pub_key) ok = gost_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key)); + DSA_SIG_free(s); + return ok; +} +static int pkey_gost01_cc_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, size_t tbs_len) +{ + int ok = 0; + EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx); + DSA_SIG *s=unpack_cc_signature(sig,siglen); + fprintf(stderr,"R="); + BN_print_fp(stderr,s->r); + fprintf(stderr,"\nS="); + BN_print_fp(stderr,s->s); + fprintf(stderr,"\n"); + if (!s) return 0; + if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key)); + DSA_SIG_free(s); + return ok; +} + +static int pkey_gost01_cp_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, size_t tbs_len) +{ + int ok = 0; + EVP_PKEY* pub_key = EVP_PKEY_CTX_get0_pkey(ctx); + DSA_SIG *s=unpack_cp_signature(sig,siglen); + if (!s) return 0; + fprintf(stderr,"R="); + BN_print_fp(stderr,s->r); + fprintf(stderr,"\nS="); + BN_print_fp(stderr,s->s); + fprintf(stderr,"\n"); + if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,EVP_PKEY_get0(pub_key)); + DSA_SIG_free(s); + return ok; +} +/* ------------- encrypt init -------------------------------------*/ +/* Generates ephermeral key */ +static int pkey_gost_encrypt_init(EVP_PKEY_CTX *ctx) +{ + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + EVP_PKEY *eph_key = EVP_PKEY_new(); + EVP_PKEY *old_key =EVP_PKEY_CTX_get0_pkey(ctx); + + if (data->eph_seckey) EVP_PKEY_free(data->eph_seckey); + EVP_PKEY_assign(eph_key,EVP_PKEY_base_id(old_key),NULL); + if (!EVP_PKEY_copy_parameters(eph_key,old_key)) return 0; + switch (EVP_PKEY_base_id(old_key)) { + case NID_id_GostR3410_2001: + case NID_id_GostR3410_2001_cc: + gost2001_keygen(EVP_PKEY_get0(eph_key)); + break; + case NID_id_GostR3410_94: + case NID_id_GostR3410_94_cc: + gost_sign_keygen(EVP_PKEY_get0(eph_key)); + break; + + + } + + + data->eph_seckey=eph_key; + return 1; +} +/* ----------------------------------------------------------------*/ +int register_pmeth_gost(int id, EVP_PKEY_METHOD **pmeth,int flags) { + *pmeth = EVP_PKEY_meth_new(id, flags); + if (!*pmeth) return 0; + + switch (id) { + case NID_id_GostR3410_94_cc: + EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94cc_str); + EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cc_keygen); + EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cc_sign); + EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cc_verify); + EVP_PKEY_meth_set_encrypt(*pmeth, + pkey_gost_encrypt_init, pkey_GOST94cc_encrypt); + EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cc_decrypt); + break; + case NID_id_GostR3410_94: + EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl94_str); + EVP_PKEY_meth_set_keygen(*pmeth,NULL,pkey_gost94cp_keygen); + EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost94_cp_sign); + EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost94_cp_verify); + EVP_PKEY_meth_set_encrypt(*pmeth, + pkey_gost_encrypt_init, pkey_GOST94cp_encrypt); + EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST94cp_decrypt); + + + break; + case NID_id_GostR3410_2001_cc: + EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01cc_str); + EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cc_sign); + EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cc_verify); + + EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cc_keygen); + + EVP_PKEY_meth_set_encrypt(*pmeth, + pkey_gost_encrypt_init, pkey_GOST01cc_encrypt); + EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cc_decrypt); + break; + /* There is intentionally no break here */ + case NID_id_GostR3410_2001: + EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_ctrl, pkey_gost_ctrl01_str); + EVP_PKEY_meth_set_sign(*pmeth, NULL, pkey_gost01_cp_sign); + EVP_PKEY_meth_set_verify(*pmeth, NULL, pkey_gost01_cp_verify); + + EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost01cp_keygen); + + EVP_PKEY_meth_set_encrypt(*pmeth, + pkey_gost_encrypt_init, pkey_GOST01cp_encrypt); + EVP_PKEY_meth_set_decrypt(*pmeth, NULL, pkey_GOST01cp_decrypt); + break; + default: //Unsupported method + return 0; + } + EVP_PKEY_meth_set_init(*pmeth, pkey_gost_init); + EVP_PKEY_meth_set_cleanup(*pmeth, pkey_gost_cleanup); + + EVP_PKEY_meth_set_copy(*pmeth, pkey_gost_copy); + //FIXME derive etc... + + return 1; +} + diff --git a/engines/ccgost/pmeth.h b/engines/ccgost/pmeth.h new file mode 100644 index 0000000000..a94f778f09 --- /dev/null +++ b/engines/ccgost/pmeth.h @@ -0,0 +1,26 @@ +#ifndef GOST_PMETH_H +#define GOST_PMETH_H +/********************************************************************** + * pmeth.h * + * Copyright (c) 2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of GOST PKEY context internal data * + * * + * Requires OpenSSL 0.9.9 for compilation * + **********************************************************************/ +#include +#include + +/* Gost-specific control-function parameters */ +#define param_ctrl_string "paramset" +#define EVP_PKEY_CTRL_GOST_PARAMSET (EVP_PKEY_ALG_CTRL+1) + + struct gost_pmeth_data { + int sign_param_nid; /* Should be set whenever parameters are filled */ + int crypt_param_nid; + EVP_PKEY *eph_seckey; + EVP_MD *md; + }; + +#endif diff --git a/engines/ccgost/sign.h b/engines/ccgost/sign.h new file mode 100644 index 0000000000..c697c4fedb --- /dev/null +++ b/engines/ccgost/sign.h @@ -0,0 +1,30 @@ +#ifndef GOST_SIGN_H +#define GOST_SIGN_H +/********************************************************************** + * sign.h * + * Copyright (c) 2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declaration of internal funtions implementing GOST R 34.10 * + * signature and key generation * + * OpenSSL 0.9.9 libraries required to compile and use * + * this code * + **********************************************************************/ +#include +#include +#include +int fill_GOST94_params(DSA *dsa,int nid); +int fill_GOST2001_params(EC_KEY *eckey, int nid); +int gost_sign_keygen(DSA *dsa) ; +int gost2001_keygen(EC_KEY *ec) ; + +DSA_SIG *gost_do_sign(const unsigned char *dgst,int dlen, DSA *dsa) ; +DSA_SIG *gost2001_do_sign(const unsigned char *dgst,int dlen, EC_KEY *eckey); + +int gost_do_verify(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa) ; +int gost2001_do_verify(const unsigned char *dgst,int dgst_len, + DSA_SIG *sig, EC_KEY *ec); +int gost2001_compute_public(EC_KEY *ec) ; +int gost94_compute_public(DSA *dsa) ; +#endif diff --git a/engines/ccgost/tools.h b/engines/ccgost/tools.h new file mode 100644 index 0000000000..db3d6089f3 --- /dev/null +++ b/engines/ccgost/tools.h @@ -0,0 +1,38 @@ +#ifndef GOST_TOOLS_H +#define GOST_TOOLS_H +/********************************************************************** + * sign.h * + * Copyright (c) 2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Miscellaneous functions used in GOST engine * + * OpenSSL 0.9.9 libraries required to compile and use * + * this code * + **********************************************************************/ +#include +#include + +/* from gost_sign.c */ +/* Convert GOST R 34.11 hash sum to bignum according to standard */ +BIGNUM *hashsum2bn(const unsigned char *dgst) ; +/* Store bignum in byte array of given length, prepending by zeros + * if nesseccary */ +int store_bignum(BIGNUM *bn, unsigned char *buf,int len); +/* Read bignum, which can have few MSB all-zeros from buffer*/ +BIGNUM *getbnfrombuf(const unsigned char *buf,size_t len); +/* Pack GOST R 34.10 signature according to CryptoCom rules */ +int pack_sign_cc(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen); +/* Pack GOST R 34.10 signature according to CryptoPro rules */ +int pack_sign_cp(DSA_SIG *s,int order,unsigned char *sig, unsigned int *siglen); +/* Unpack GOST R 34.10 signature according to CryptoCom rules */ +DSA_SIG *unpack_cc_signature(const unsigned char *sig,size_t siglen) ; +/* Unpack GOST R 34.10 signature according to CryptoPro rules */ +DSA_SIG *unpack_cp_signature(const unsigned char *sig,size_t siglen) ; +/* from ameth.c */ +/* Get private key as BIGNUM from both R 34.10-94 and R 34.10-2001 keys*/ +BIGNUM* gost_get_priv_key(const EVP_PKEY *pkey) ; +/* Find NID by GOST 94 parameters */ +int gost94_nid_by_params(DSA *p) ; + + +#endif -- 2.25.1