diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2006-09-17 13:00:18 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2006-09-17 13:00:18 +0000 |
commit | a04549cc755408ff2dcab209fd87d3e46f7d662a (patch) | |
tree | e4778866a61dddb7fb9ef4465490ad48de919645 /engines | |
parent | bc7535bc7fe30fbba222c316a3957da7d906603b (diff) | |
download | openssl-a04549cc755408ff2dcab209fd87d3e46f7d662a.tar.gz |
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.
Diffstat (limited to 'engines')
33 files changed, 5836 insertions, 0 deletions
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 <openssl/engine.h> +#include <openssl/evp.h> +#include <string.h> +#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;i<octet->length;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;i<octet->length;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;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_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 (da && db && da->pub_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 <unistd.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#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 <stdio.h> +#include <openssl/err.h> +#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 <string.h> +#include <openssl/evp.h> +#include <openssl/engine.h> +#include <openssl/obj_mac.h> +#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 <string.h> +#include <openssl/rand.h> +#include <openssl/ecdsa.h> +#include <openssl/err.h> +#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 <openssl/evp.h> +#include <openssl/rand.h> +#include <string.h> +#include <openssl/objects.h> +#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;i<inlen;i++) { + outbuf[inlen-1-i]=inbuf[i]; + } + *outlen = inlen; + return out; +} + +/* Create gost 2001 ephemeral key with same parameters as peer key */ +static EC_KEY *make_ec_ephemeral_key(EC_KEY *peer_key,BIGNUM *seckey) { + EC_KEY *out = EC_KEY_new(); + EC_KEY_copy(out,peer_key); + EC_KEY_set_private_key(out,seckey); + gost2001_compute_public(out); + return out; +} +/* Packs GOST elliptic curve key into EVP_PKEY setting same parameters + * as in passed pubkey + */ +static EVP_PKEY *ec_ephemeral_key_to_EVP(EVP_PKEY *pubk,int type,EC_KEY *ephemeral) +{ + EVP_PKEY *newkey; + newkey = EVP_PKEY_new(); + EVP_PKEY_assign(newkey,type,ephemeral); + return newkey; +} + +/* + * EVP_PKEY_METHOD callback encrypt + * Implementation of GOST2001 key transport, cryptocom variation + */ + +int pkey_GOST01cc_encrypt (EVP_PKEY_CTX *pctx,unsigned char *out, + size_t *out_len, const unsigned char *key,size_t key_len) +{ + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx); + GOST_KEY_TRANSPORT *gkt = NULL; + int ret=0; + gost_ctx ctx; + EC_KEY *ephemeral=NULL; + const EC_POINT *pub_key_point=NULL; + unsigned char shared_key[32],encrypted_key[32],hmac[4], + iv[8]={0,0,0,0,0,0,0,0}; + ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk), gost_get_priv_key(data->eph_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 <string.h> +#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;i<blocks;i++){ + gostcrypt(c,clear,cipher); + clear+=8; + cipher+=8; + } +} +/* Decrypts several blocks in ECB mode */ +void gost_dec(gost_ctx *c, const byte *cipher,byte *clear, int blocks) +{ + int i; + for(i=0;i<blocks;i++) { + gostdecrypt(c,cipher,clear); + clear+=8; + cipher+=8; + } + +} + +/* 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) { + byte cur_iv[8]; + byte gamma[8]; + int i,j; + const byte *in; + byte *out; + memcpy(cur_iv,iv,8); + for(i=0,in=clear,out=cipher;i<blocks;i++,in+=8,out+=8) { + gostcrypt(ctx,cur_iv,gamma); + for (j=0;j<8;j++) { + cur_iv[j]=out[j]=in[j]^gamma[j]; + } + } + +} +/* 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) { + byte cur_iv[8]; + byte gamma[8]; + int i,j; + const byte *in; + byte *out; + memcpy(cur_iv,iv,8); + for(i=0,in=cipher,out=clear;i<blocks;i++,in+=8,out+=8) { + gostcrypt(ctx,cur_iv,gamma); + for (j=0;j<8;j++) { + out[j]=(cur_iv[j]=in[j])^gamma[j]; + } + } +} + +/* Encrypts one block using specified key */ +void gost_enc_with_key(gost_ctx *c,byte *key,byte *inblock,byte *outblock) +{ + gost_key(c,key); + gostcrypt(c,inblock,outblock); + +} +/* Set 256 bit key into context */ +void gost_key(gost_ctx *c, const byte *k) +{ + int i,j; + for(i=0,j=0;i<8;i++,j+=4) { + c->k[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<rembits)-1):0; + int i; + for (i=0;i<nbytes;i++) out[i]=buffer[i]; + if (rembits) out[i]=buffer[i]&mask; +} + +/* Compute mac of specified length (in bits) from data. + * Context should be initialized with key and subst blocks */ +int gost_mac(gost_ctx *ctx,int mac_len,const unsigned char *data, + unsigned int data_len,unsigned char *mac) +{ + byte buffer[8]={0,0,0,0,0,0,0,0}; + byte buf2[8]; + int i; + for (i=0;i+8<=data_len;i+=8) + mac_block(ctx,buffer,data+i); + if (i<data_len) { + memset(buf2,0,8); + memcpy(buf2,data+i,data_len-i); + mac_block(ctx,buffer,buf2); + } + get_mac(buffer,mac_len,mac); + return 1; +} +/* Compute MAC with non-zero IV. Used in some RFC 4357 algorithms */ +int gost_mac_iv(gost_ctx *ctx,int mac_len,const unsigned char *iv,const unsigned char *data, + unsigned int data_len,unsigned char *mac) +{ + byte buffer[8]; + byte buf2[8]; + int i; + memcpy (buffer,iv,8); + for (i=0;i+8<=data_len;i+=8) + mac_block(ctx,buffer,data+i); + if (i<data_len) { + memset(buf2,0,8); + memcpy(buf2,data+i,data_len-i); + mac_block(ctx,buffer,buf2); + } + get_mac(buffer,mac_len,mac); + return 1; +} + +/* Implements key meshing algorithm by modifing ctx and IV in place */ +void cryptopro_key_meshing(gost_ctx *ctx, unsigned char *iv) { + unsigned char newkey[32],newiv[8]; + /* Set static keymeshing key */ + /* "Decrypt" key with keymeshing key */ + gost_dec(ctx,CryptoProKeyMeshingKey,newkey,4); + /* set new key */ + gost_key(ctx,newkey); + /* Encrypt iv with new key */ + gostcrypt(ctx,iv,newiv); + memcpy(iv,newiv,8); +} diff --git a/engines/ccgost/gost89.h b/engines/ccgost/gost89.h new file mode 100644 index 0000000000..2157852519 --- /dev/null +++ b/engines/ccgost/gost89.h @@ -0,0 +1,96 @@ +/********************************************************************** + * gost89.h * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Declarations for GOST 28147-89 encryption algorithm * + * No OpenSSL libraries required to compile and use * + * this code * + **********************************************************************/ +#ifndef GOST89_H +#define GOST89_H + +/* Typedef for unsigned 32-bit integer */ +#if __LONG_MAX__ > 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 <string.h> +#include <openssl/dh.h> +#include <openssl/rand.h> +#include <openssl/evp.h> +#include <openssl/objects.h> + +#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 <crypted_key_len) { + GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_NOT_ENOUGH_SPACE_FOR_KEY); + return 0; + } + if ((crypted_key_len & 7) !=0) + { + GOSTerr(GOST_F_DECRYPT_CRYPTOCOM_KEY,GOST_R_INVALID_ENCRYPTED_KEY_SIZE); + return 0; + } + for (i=blocks-1;i>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;i<key_len;i+=8) + { + gostcrypt(ctx,gamma,gamma); + for (j=0;j<8;j++) + gamma[j]=crypted_key[i+j]=sess_key[i+j]^gamma[j]; + } + return 1; +} +/* Implementation of the Diffi-Hellman key agreement scheme based on + * GOST-94 keys */ + +/* Computes Diffie-Hellman key and stores it into buffer in + * little-endian byte order as expected by both versions of GOST 94 + * algorigthm + */ +static int compute_pair_key_le(unsigned char *pair_key,BIGNUM *pub_key,DH *dh) +{ + unsigned char be_key[128]; + int i,key_size; + key_size=DH_compute_key(be_key,pub_key,dh); + if (!key_size) return 0; + memset(pair_key,0,128); + for (i=0;i<key_size;i++) { + pair_key[i]=be_key[key_size-1-i]; + } + return key_size; +} +/* + * Computes 256 bit key exchange key for CryptoCom variation of GOST 94 + * algorithm + */ +static int make_gost_shared_key(DH *dh,EVP_PKEY *pubk,unsigned char *shared_key) +{ + unsigned char dh_key [128]; + int i; + /* Compute key */ + memset(dh_key,0,128); + if (!compute_pair_key_le(dh_key,((DSA *)EVP_PKEY_get0(pubk))->pub_key,dh)) return 0; + /* Fold it down to 256 bit */ + /* According to GOST either 2^1020<p<2^1024 or + * 2^509<p<2^512, so DH_size can be exactly 128 or exactly 64 only + */ + + if (DH_size(dh)==128) + for (i=0;i<64;i++) { + dh_key[i]^=dh_key[64+i]; + } + for (i=0;i<32;i++) { + shared_key[i]=dh_key[i]^dh_key[32+i]; + } + return 1; +} + +static DH *make_ephemeral_key(EVP_PKEY *pubk,BIGNUM *ephemeral_key) +{ + DH *dh = DH_new(); + dh->g = 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 <stdio.h> +#include <openssl/asn1t.h> +#include <openssl/x509.h> +#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 <openssl/asn1t.h> +#include <openssl/x509.h> + + +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 <string.h> +#include "crypt.h" +#include "gost89.h" +#include <openssl/rand.h> +#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 && i<inl;j++,i++,in_ptr++,out_ptr++) + { + if (!ctx->encrypt) 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+8<inl;i+=8,in_ptr+=8,out_ptr+=8) { + /*block cipher current iv */ + gost_crypt_mesh(ctx->cipher_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 (i<inl) { + gost_crypt_mesh(ctx->cipher_data,ctx->iv,ctx->buf); + if (!ctx->encrypt) memcpy(ctx->buf+8,in_ptr,j); + for (j=0;i<inl;j++,i++) { + out_ptr[j]=ctx->buf[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 && i<inl;j++,i++,in_ptr++,out_ptr++) + { + *out_ptr=ctx->buf[j]^(*in_ptr); + } + if (j==8) { + ctx->num=0; + } else { + ctx->num=j; + return 1; + } +} + +for (;i+8<inl;i+=8,in_ptr+=8,out_ptr+=8) { + /*block cipher current iv */ + /* Encrypt */ + gost_cnt_next(ctx->cipher_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 (i<inl) { + gost_cnt_next(ctx->cipher_data,ctx->iv,ctx->buf); + for (j=0;i<inl;j++,i++) { + out_ptr[j]=ctx->buf[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 <string.h> +#include <openssl/rand.h> +#include <openssl/bn.h> +#include <openssl/dsa.h> +#include <openssl/evp.h> + +#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; i<len; i++) { + if (i% 16 ==0) fputc('\n',stderr); + fprintf (stderr," %02x",buffer[i]); + } + fprintf(stderr,"\nEnd of signature\n"); +} + +void dump_dsa_sig(const char *message, DSA_SIG *sig) { + fprintf(stderr,"%s\nR=",message); + BN_print_fp(stderr,sig->r); + fprintf(stderr,"\nS="); + BN_print_fp(stderr,sig->s); + fprintf(stderr,"\n"); +} + +#else + +#define dump_signature(a,b,c) +#define dump_dsa_sig(a,b) +#endif + +/* + * Computes signature and returns it as DSA_SIG structure + */ +DSA_SIG *gost_do_sign(const unsigned char *dgst,int dlen, DSA *dsa) +{ + BIGNUM *k=NULL,*tmp=NULL,*tmp2=NULL; + DSA_SIG *newsig = DSA_SIG_new(); + BIGNUM *md = hashsum2bn(dgst); + /* check if H(M) mod q is zero */ + BN_CTX *ctx=BN_CTX_new(); + BN_CTX_start(ctx); + if (!newsig) + { + GOSTerr(GOST_F_GOST_DO_SIGN,GOST_R_NO_MEMORY); + goto err; + } + tmp=BN_CTX_get(ctx); + k = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + BN_mod(tmp,md,dsa->q,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 <string.h> + +#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 <openssl/crypto.h> +# 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<n;i++) + { + sum=(int)left[i]+(int)right[i]+carry; + left[i]=sum & 0xff; + carry=sum>>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;i<len;i++) result[i]=a[i]^b[i]; +} + +/* + * Calculate H(i+1) = Hash(Hi,Mi) + * Where H and M are 32 bytes long + */ +static int hash_step(gost_ctx *c,byte *H,const byte *M) +{ + static byte U[32],W[32],V[32],S[32],Key[32]; + int i; + /* Compute first key */ + xor_blocks(W,H,M,32); + swap_bytes(W,Key); + /* Encrypt first 8 bytes of H with first key*/ + gost_enc_with_key(c,Key,H,S); + /* Compute second key*/ + circle_xor8(H,U); + circle_xor8(M,V); + circle_xor8(V,V); + xor_blocks(W,U,V,32); + swap_bytes(W,Key); + /* encrypt second 8 bytes of H with second key*/ + gost_enc_with_key(c,Key,H+8,S+8); + /* compute third key */ + circle_xor8(U,U); + U[31]=~U[31]; U[29]=~U[29]; U[28]=~U[28]; U[24]=~U[24]; + U[23]=~U[23]; U[20]=~U[20]; U[18]=~U[18]; U[17]=~U[17]; + U[14]=~U[14]; U[12]=~U[12]; U[10]=~U[10]; U[ 8]=~U[ 8]; + U[ 7]=~U[ 7]; U[ 5]=~U[ 5]; U[ 3]=~U[ 3]; U[ 1]=~U[ 1]; + circle_xor8(V,V); + circle_xor8(V,V); + xor_blocks(W,U,V,32); + swap_bytes(W,Key); + /* encrypt third 8 bytes of H with third key*/ + gost_enc_with_key(c,Key,H+16,S+16); + /* Compute fourth key */ + circle_xor8(U,U); + circle_xor8(V,V); + circle_xor8(V,V); + xor_blocks(W,U,V,32); + swap_bytes(W,Key); + /* Encrypt last 8 bytes with fourth key */ + gost_enc_with_key(c,Key,H+24,S+24); + for (i=0;i<12;i++) + transform_3(S); + xor_blocks(S,S,M,32); + transform_3(S); + xor_blocks(S,S,H,32); + for (i=0;i<61;i++) + transform_3(S); + memcpy(H,S,32); + return 1; +} + +/* Initialize gost_hash ctx - cleans up temporary structures and + * set up substitution blocks + */ +int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block) { + memset(ctx,0,sizeof(gost_hash_ctx)); + ctx->cipher_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 <stdlib.h> +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 <openssl/evp.h> +#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 <hashsum> <filename> + +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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <fcntl.h> +#include <string.h> +#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 && optind<argc) + { + check_file=fopen(argv[optind],"r"); + if (!check_file) + { + perror(argv[optind]); + exit(2); + } + } + while (get_line(check_file,inhash,filename)) + { + if (!hash_file(&ctx,filename,calcsum,open_mode)) { + exit (2); + } + count++; + if (!strncmp(calcsum,inhash,65)) + { + if (verbose) { + fprintf(stderr,"%s\tOK\n",filename); + } + } else { + if (verbose) { + fprintf(stderr,"%s\tFAILED\n",filename); + } else { + fprintf(stderr,"%s: GOST hash sum check failed for '%s'\n", + argv[0],filename); + } + failcount++; + } + } + if (verbose && failcount) { + fprintf(stderr,"%s: %d of %d file(f) failed GOST hash sum check\n", + argv[0],failcount,count); + } + exit (failcount?1:0); + } + if (optind==argc) { + char sum[65]; + if (!hash_stream(&ctx,fileno(stdin),sum)) { + perror("stdin"); + exit(1); + } + printf("%s -\n",sum); + exit(0); + } + for (i=optind;i<argc;i++) { + char sum[65]; + if (!hash_file(&ctx,argv[i],sum,open_mode)) { + errors++; + } else { + printf("%s %s\n",sum,argv[i]); + } + } + exit(errors?1:0); +} + +int hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode) +{ + int fd; + if ((fd=open(filename,mode))<0) { + perror(filename); + return 0; + } + if (!hash_stream(ctx,fd,sum)) { + perror(filename); + return 0; + } + close(fd); + return 1; +} + +int hash_stream(gost_hash_ctx *ctx,int fd, char *sum) +{ + unsigned char buffer[BUF_SIZE]; + ssize_t bytes; + int i; + start_hash(ctx); + while ((bytes=read(fd,buffer,BUF_SIZE))>0) { + 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 <string.h> +#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 <string.h> +#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 <unistd.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#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 <string.h> +#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 <openssl/objects.h> +/* 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 <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/ec.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#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 <openssl/bn.h> +#include <openssl/evp.h> + +/* 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 <openssl/evp.h> +#include <openssl/dsa.h> +#include <openssl/ec.h> +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 <openssl/evp.h> +#include <openssl/dsa.h> + +/* 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 |