diff options
Diffstat (limited to 'openssl/engines/ccgost')
28 files changed, 6544 insertions, 0 deletions
diff --git a/openssl/engines/ccgost/Makefile b/openssl/engines/ccgost/Makefile new file mode 100644 index 000000000..64be962f3 --- /dev/null +++ b/openssl/engines/ccgost/Makefile @@ -0,0 +1,275 @@ +DIR=ccgost +TOP=../.. +CC=cc +INCLUDES= -I../../include +CFLAG=-g +MAKEFILE= Makefile +AR= ar r +CFLAGS= $(INCLUDES) $(CFLAG) +LIB=$(TOP)/libcrypto.a + +LIBSRC= gost2001.c gost2001_keyx.c gost89.c gost94_keyx.c gost_ameth.c gost_asn1.c gost_crypt.c gost_ctl.c gost_eng.c gosthash.c gost_keywrap.c gost_md.c gost_params.c gost_pmeth.c gost_sign.c + +LIBOBJ= e_gost_err.o gost2001_keyx.o gost2001.o gost89.o gost94_keyx.o gost_ameth.o gost_asn1.o gost_crypt.o gost_ctl.o gost_eng.o gosthash.o gost_keywrap.o gost_md.o gost_params.o gost_pmeth.o gost_sign.o + +SRC=$(LIBSRC) + +LIBNAME=gost + +top: + (cd $(TOP); $(MAKE) DIRS=engines EDIRS=$(DIR) sub_all) + +all: lib + +tags: + ctags $(SRC) + +errors: + $(PERL) ../../util/mkerr.pl -conf gost.ec -nostatic -write $(SRC) + +lib: $(LIBOBJ) + if [ -n "$(SHARED_LIBS)" ]; then \ + $(MAKE) -f $(TOP)/Makefile.shared -e \ + LIBNAME=$(LIBNAME) \ + LIBEXTRAS='$(LIBOBJ)' \ + LIBDEPS='-L$(TOP) -lcrypto' \ + link_o.$(SHLIB_TARGET); \ + else \ + $(AR) $(LIB) $(LIBOBJ); \ + fi + @touch lib + +install: + [ -n "$(INSTALLTOP)" ] # should be set by top Makefile... + if [ -n "$(SHARED_LIBS)" ]; then \ + set -e; \ + echo installing $(LIBNAME); \ + pfx=lib; \ + if [ "$(PLATFORM)" != "Cygwin" ]; then \ + case "$(CFLAGS)" in \ + *DSO_BEOS*) sfx=".so";; \ + *DSO_DLFCN*) sfx=".so";; \ + *DSO_DL*) sfx=".sl";; \ + *DSO_WIN32*) sfx="eay32.dll"; pfx=;; \ + *) sfx=".bad";; \ + esac; \ + cp $${pfx}$(LIBNAME)$$sfx $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new; \ + else \ + sfx=".so"; \ + cp cyg$(LIBNAME).dll $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new; \ + fi; \ + chmod 555 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new; \ + mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx; \ + fi + +links: + +tests: + +depend: + @if [ -z "$(THIS)" ]; then \ + $(MAKE) -f $(TOP)/Makefile reflect THIS=$@; \ + else \ + $(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC); \ + fi + +files: + + + +lint: + lint -DLINT $(INCLUDES) $(SRC)>fluff + +dclean: + $(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new + mv -f Makefile.new $(MAKEFILE) + +clean: + rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff *.so *.sl *.dll + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +gost2001.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost2001.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost2001.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost2001.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost2001.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost2001.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost2001.o: ../../include/openssl/err.h ../../include/openssl/evp.h +gost2001.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +gost2001.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +gost2001.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost2001.o: ../../include/openssl/pkcs7.h ../../include/openssl/rand.h +gost2001.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +gost2001.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +gost2001.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +gost2001.o: e_gost_err.h gost2001.c gost89.h gost_lcl.h gost_params.h +gost2001.o: gosthash.h +gost2001_keyx.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost2001_keyx.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost2001_keyx.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost2001_keyx.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost2001_keyx.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost2001_keyx.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost2001_keyx.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +gost2001_keyx.o: ../../include/openssl/obj_mac.h +gost2001_keyx.o: ../../include/openssl/objects.h +gost2001_keyx.o: ../../include/openssl/opensslconf.h +gost2001_keyx.o: ../../include/openssl/opensslv.h +gost2001_keyx.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pkcs7.h +gost2001_keyx.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h +gost2001_keyx.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost2001_keyx.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost2001_keyx.o: ../../include/openssl/x509_vfy.h e_gost_err.h gost2001_keyx.c +gost2001_keyx.o: gost2001_keyx.h gost89.h gost_keywrap.h gost_lcl.h gosthash.h +gost89.o: gost89.c gost89.h +gost94_keyx.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost94_keyx.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost94_keyx.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost94_keyx.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h +gost94_keyx.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +gost94_keyx.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +gost94_keyx.o: ../../include/openssl/engine.h ../../include/openssl/evp.h +gost94_keyx.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +gost94_keyx.o: ../../include/openssl/objects.h +gost94_keyx.o: ../../include/openssl/opensslconf.h +gost94_keyx.o: ../../include/openssl/opensslv.h +gost94_keyx.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pkcs7.h +gost94_keyx.o: ../../include/openssl/rand.h ../../include/openssl/safestack.h +gost94_keyx.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost94_keyx.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost94_keyx.o: ../../include/openssl/x509_vfy.h e_gost_err.h gost89.h +gost94_keyx.o: gost94_keyx.c gost_keywrap.h gost_lcl.h gosthash.h +gost_ameth.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_ameth.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_ameth.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_ameth.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_ameth.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_ameth.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_ameth.o: ../../include/openssl/err.h ../../include/openssl/evp.h +gost_ameth.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +gost_ameth.o: ../../include/openssl/objects.h +gost_ameth.o: ../../include/openssl/opensslconf.h +gost_ameth.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_ameth.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +gost_ameth.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost_ameth.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost_ameth.o: ../../include/openssl/x509_vfy.h e_gost_err.h gost89.h +gost_ameth.o: gost_ameth.c gost_lcl.h gost_params.h gosthash.h +gost_asn1.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_asn1.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_asn1.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_asn1.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_asn1.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_asn1.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_asn1.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +gost_asn1.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +gost_asn1.o: ../../include/openssl/opensslconf.h +gost_asn1.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_asn1.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +gost_asn1.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost_asn1.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost_asn1.o: ../../include/openssl/x509_vfy.h gost89.h gost_asn1.c gost_lcl.h +gost_asn1.o: gosthash.h +gost_crypt.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_crypt.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_crypt.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_crypt.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_crypt.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_crypt.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_crypt.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +gost_crypt.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +gost_crypt.o: ../../include/openssl/opensslconf.h +gost_crypt.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_crypt.o: ../../include/openssl/pkcs7.h ../../include/openssl/rand.h +gost_crypt.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +gost_crypt.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +gost_crypt.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +gost_crypt.o: e_gost_err.h gost89.h gost_crypt.c gost_lcl.h gosthash.h +gost_ctl.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_ctl.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_ctl.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_ctl.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_ctl.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_ctl.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_ctl.o: ../../include/openssl/err.h ../../include/openssl/evp.h +gost_ctl.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +gost_ctl.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +gost_ctl.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_ctl.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +gost_ctl.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost_ctl.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost_ctl.o: ../../include/openssl/x509_vfy.h gost89.h gost_ctl.c gost_lcl.h +gost_ctl.o: gosthash.h +gost_eng.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_eng.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_eng.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_eng.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_eng.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_eng.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_eng.o: ../../include/openssl/err.h ../../include/openssl/evp.h +gost_eng.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +gost_eng.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h +gost_eng.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_eng.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +gost_eng.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost_eng.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost_eng.o: ../../include/openssl/x509_vfy.h e_gost_err.h gost89.h gost_eng.c +gost_eng.o: gost_lcl.h gosthash.h +gost_keywrap.o: gost89.h gost_keywrap.c gost_keywrap.h +gost_md.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_md.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_md.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_md.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_md.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_md.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_md.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +gost_md.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +gost_md.o: ../../include/openssl/opensslconf.h ../../include/openssl/opensslv.h +gost_md.o: ../../include/openssl/ossl_typ.h ../../include/openssl/pkcs7.h +gost_md.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +gost_md.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +gost_md.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +gost_md.o: e_gost_err.h gost89.h gost_lcl.h gost_md.c gosthash.h +gost_params.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h +gost_params.o: ../../include/openssl/crypto.h ../../include/openssl/e_os2.h +gost_params.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +gost_params.o: ../../include/openssl/opensslconf.h +gost_params.o: ../../include/openssl/opensslv.h +gost_params.o: ../../include/openssl/ossl_typ.h +gost_params.o: ../../include/openssl/safestack.h ../../include/openssl/stack.h +gost_params.o: ../../include/openssl/symhacks.h gost_params.c gost_params.h +gost_pmeth.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_pmeth.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_pmeth.o: ../../include/openssl/buffer.h ../../include/openssl/conf.h +gost_pmeth.o: ../../include/openssl/crypto.h ../../include/openssl/dsa.h +gost_pmeth.o: ../../include/openssl/e_os2.h ../../include/openssl/ec.h +gost_pmeth.o: ../../include/openssl/ecdh.h ../../include/openssl/ecdsa.h +gost_pmeth.o: ../../include/openssl/engine.h ../../include/openssl/evp.h +gost_pmeth.o: ../../include/openssl/lhash.h ../../include/openssl/obj_mac.h +gost_pmeth.o: ../../include/openssl/objects.h +gost_pmeth.o: ../../include/openssl/opensslconf.h +gost_pmeth.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_pmeth.o: ../../include/openssl/pkcs7.h ../../include/openssl/safestack.h +gost_pmeth.o: ../../include/openssl/sha.h ../../include/openssl/stack.h +gost_pmeth.o: ../../include/openssl/symhacks.h ../../include/openssl/x509.h +gost_pmeth.o: ../../include/openssl/x509_vfy.h ../../include/openssl/x509v3.h +gost_pmeth.o: e_gost_err.h gost89.h gost_lcl.h gost_params.h gost_pmeth.c +gost_pmeth.o: gosthash.h +gost_sign.o: ../../include/openssl/asn1.h ../../include/openssl/asn1t.h +gost_sign.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +gost_sign.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +gost_sign.o: ../../include/openssl/dsa.h ../../include/openssl/e_os2.h +gost_sign.o: ../../include/openssl/ec.h ../../include/openssl/ecdh.h +gost_sign.o: ../../include/openssl/ecdsa.h ../../include/openssl/engine.h +gost_sign.o: ../../include/openssl/evp.h ../../include/openssl/lhash.h +gost_sign.o: ../../include/openssl/obj_mac.h ../../include/openssl/objects.h +gost_sign.o: ../../include/openssl/opensslconf.h +gost_sign.o: ../../include/openssl/opensslv.h ../../include/openssl/ossl_typ.h +gost_sign.o: ../../include/openssl/pkcs7.h ../../include/openssl/rand.h +gost_sign.o: ../../include/openssl/safestack.h ../../include/openssl/sha.h +gost_sign.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +gost_sign.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h +gost_sign.o: e_gost_err.h gost89.h gost_lcl.h gost_params.h gost_sign.c +gost_sign.o: gosthash.h +gosthash.o: gost89.h gosthash.c gosthash.h diff --git a/openssl/engines/ccgost/README.gost b/openssl/engines/ccgost/README.gost new file mode 100644 index 000000000..c96cccc7b --- /dev/null +++ b/openssl/engines/ccgost/README.gost @@ -0,0 +1,300 @@ +GOST ENGINE + +This engine provides implementation of Russian cryptography standard. +This is also an example of adding new cryptoalgorithms into OpenSSL +without changing its core. If OpenSSL is compiled with dynamic engine +support, new algorithms can be added even without recompilation of +OpenSSL and applications which use it. + +ALGORITHMS SUPPORTED + +GOST R 34.10-94 and GOST R 34.10-2001 - digital signature algorithms. + Also support key exchange based on public keys. See RFC 4357 for + details of VKO key exchange algorithm. These algorithms use + 256 bit private keys. Public keys are 1024 bit for 94 and 512 bit for + 2001 (which is elliptic-curve based). Key exchange algorithms + (VKO R 34.10) are supported on these keys too. + +GOST R 34.11-94 Message digest algorithm. 256-bit hash value + +GOST 28147-89 - Symmetric cipher with 256-bit key. Various modes are + defined in the standard, but only CFB and CNT modes are implemented + in the engine. To make statistical analysis more difficult, key + meshing is supported (see RFC 4357). + +GOST 28147-89 MAC mode. Message authentication code. While most MAC + algorithms out there are based on hash functions using HMAC + algorithm, this algoritm is based on symmetric cipher. + It has 256-bit symmetric key and only 32 bits of MAC value + (while HMAC has same key size and value size). + + It is implemented as combination of EVP_PKEY type and EVP_MD type. + +USAGE OF THESE ALGORITHMS + +This engine is designed to allow usage of this algorithms in the +high-level openssl functions, such as PKI, S/MIME and TLS. + +See RFC 4490 for S/MIME with GOST algorithms and RFC 4491 for PKI. +TLS support is implemented according IETF +draft-chudov-cryptopro-cptls-03.txt and is compatible with +CryptoPro CSP 3.0 and 3.6 as well as with MagPro CSP. +GOST ciphersuites implemented in CryptoPro CSP 2.0 are not supported +because they use ciphersuite numbers used now by AES ciphersuites. + +To use the engine you have to load it via openssl configuration +file. Applications should read openssl configuration file or provide +their own means to load engines. Also, applications which operate with +private keys, should use generic EVP_PKEY API instead of using RSA or +other algorithm-specific API. + +CONFIGURATION FILE + +Configuration file should include following statement in the global +section, i.e. before first bracketed section header (see config(5) for details) + + openssl_conf = openssl_def + +where openssl_def is name of the section in configuration file which +describes global defaults. + +This section should contain following statement: + + [openssl_def] + engines = engine_section + +which points to the section which describes list of the engines to be +loaded. This section should contain: + + [engine_section] + gost = gost_section + +And section which describes configuration of the engine should contain + + [gost_section] + engine_id = gost + dynamic_path = /usr/lib/ssl/engines/libgost.so + default_algorithms = ALL + CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet + +Where engine_id parameter specifies name of engine (should be "gost"). +dynamic_path is a location of the loadable shared library implementing the +engine. If the engine is compiled statically or is located in the OpenSSL +engines directory, this line can be omitted. +default_algorithms parameter specifies that all algorithms, provided by +engine, should be used. + +The CRYPT_PARAMS parameter is engine-specific. It allows the user to choose +between different parameter sets of symmetric cipher algorithm. RFC 4357 +specifies several parameters for the GOST 28147-89 algorithm, but OpenSSL +doesn't provide user interface to choose one when encrypting. So use engine +configuration parameter instead. + +Value of this parameter can be either short name, defined in OpenSSL +obj_dat.h header file or numeric representation of OID, defined in RFC +4357. + +USAGE WITH COMMAND LINE openssl UTILITY + +1. Generation of private key + + openssl genpkey -algorithm gost2001 -pkeyopt paramset:A -out seckey.pem + + Use -algorithm option to specify algorithm. + Use -pkeyopt option to pass paramset to algorithm. The following paramsets + are supported by + gost94: 0,A,B,C,D,XA,XB,XC + gost2001: 0,A,B,C,XA,XB + You can also use numeric representation of OID as to destinate + paramset. + + Paramsets starting with X are intended to use for key exchange keys. + Paramsets without X are for digital signature keys. + + Paramset for both algorithms 0 is the test paramset which should be used + only for test purposes. + +There are no algorithm-specific things with generation of certificate +request once you have a private key. + +2. Generation of certificate request along with private/public keypar + + openssl req -newkey gost2001 -pkeyopt paramset:A + + Syntax of -pkeyopt parameter is identical with genpkey command. + + You can also use oldstyle syntax -newkey gost2001:paramfile, but in + this case you should create parameter file first. + + It can be created with + + openssl genpkey -genparam -algorithm gost2001 -pkeyopt paramset:A\ + -out paramfile. + +3. S/MIME operations + +If you want to send encrypted mail using GOST algorithms, don't forget +to specify -gost89 as encryption algorithm for OpenSSL smime command. +While OpenSSL is clever enough to find out that GOST R 34.11-94 digest +must be used for digital signing with GOST private key, it have no way +to derive symmetric encryption algorithm from key exchange keys. + +4. TLS operations + +OpenSSL supports all four ciphersuites defined in the IETF draft. +Once you've loaded GOST key and certificate into your TLS server, +ciphersuites which use GOST 28147-89 encryption are enabled. + +Ciphersuites with NULL encryption should be enabled explicitely if +needed. + +GOST2001-GOST89-GOST89 Uses GOST R 34.10-2001 for auth and key exchange + GOST 28147-89 for encryption and GOST 28147-89 MAC +GOST94-GOST89-GOST89 Uses GOST R 34.10-94 for auth and key exchange + GOST 28147-89 for encryption and GOST 28147-89 MAC +GOST2001-NULL-GOST94 Uses GOST R 34.10-2001 for auth and key exchange, + no encryption and HMAC, based on GOST R 34.11-94 +GOST94-NULL-GOST94 Uses GOST R 34.10-94 for auth and key exchange, + no encryption and HMAC, based on GOST R 34.11-94 + +Gost 94 and gost 2001 keys can be used simultaneously in the TLS server. +RSA, DSA and EC keys can be used simultaneously with GOST keys, if +server implementation supports loading more than two private +key/certificate pairs. In this case ciphersuites which use any of loaded +keys would be supported and clients can negotiate ones they wish. + +This allows creation of TLS servers which use GOST ciphersuites for +Russian clients and RSA/DSA ciphersuites for foreign clients. + +5. Calculation of digests and symmetric encryption + OpenSSL provides specific commands (like sha1, aes etc) for calculation + of digests and symmetric encryption. Since such commands cannot be + added dynamically, no such commands are provided for GOST algorithms. + Use generic commands 'dgst' and 'enc'. + + Calculation of GOST R 34.11-94 message digest + + openssl dgst -md_gost94 datafile + + Note that GOST R 34.11-94 specifies that digest value should be + interpreted as little-endian number, but OpenSSL outputs just hex dump + of digest value. + + So, to obtain correct digest value, such as produced by gostsum utility + included in the engine distribution, bytes of output should be + reversed. + + Calculation of HMAC based on GOST R 34.11-94 + + openssl dgst -md_gost94 -mac hmac -macopt key:<32 bytes of key> datafile + + (or use hexkey if key contain NUL bytes) + Calculation of GOST 28147 MAC + + openssl dgst -mac gost-mac -macopt key:<32 bytes of key> datafile + + Note absense of an option that specifies digest algorithm. gost-mac + algorithm supports only one digest (which is actually part of + implementation of this mac) and OpenSSL is clever enough to find out + this. + + Encryption with GOST 28147 CFB mode + openssl enc -gost89 -out encrypted-file -in plain-text-file -k <passphrase> + Encryption with GOST 28147 CNT mode + openssl enc -gost89-cnt -out encrypted-file -in plain-text-file -k <passphrase> + + +6. Encrypting private keys and PKCS12 + +To produce PKCS12 files compatible with MagPro CSP, you need to use +GOST algorithm for encryption of PKCS12 file and also GOST R 34.11-94 +hash to derive key from password. + +openssl pksc12 -export -inkey gost.pem -in gost_cert.pem -keypbe gost89\ + -certpbe gost89 -macalg md_gost94 + +7. Testing speed of symmetric ciphers. + +To test performance of GOST symmetric ciphers you should use -evp switch +of the openssl speed command. Engine-provided ciphers couldn't be +accessed by cipher-specific functions, only via generic evp interface + + openssl speed -evp gost89 + openssl speed -evp gost89-cnt + + +PROGRAMMING INTERFACES DETAILS + +Applications never should access engine directly. They only use provided +EVP_PKEY API. But there are some details, which should be taken into +account. + +EVP provides two kinds of API for key exchange: + +1. EVP_PKEY_encrypt/EVP_PKEY_decrypt functions, intended to use with + RSA-like public key encryption algorithms + +2. EVP_PKEY_derive, intended to use with Diffie-Hellman-like shared key +computing algorithms. + +Although VKO R 34.10 algorithms, described in the RFC 4357 are +definitely second case, engine provides BOTH API for GOST R 34.10 keys. + +EVP_PKEY_derive just invokes appropriate VKO algorithm and computes +256 bit shared key. VKO R 34.10-2001 requires 64 bits of random user key +material (UKM). This UKM should be transmitted to other party, so it is +not generated inside derive function. + +It should be set by EVP_PKEY_CTX_ctrl function using +EVP_PKEY_CTRL_SET_IV command after call of EVP_PKEY_derive_init, but +before EVP_PKEY_derive. + unsigned char ukm[8]; + RAND_bytes(ukm,8); + EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_DERIVE, 8, ukm) + +EVP_PKEY_encrypt encrypts provided session key with VKO shared key and +packs it into GOST key transport structure, described in the RFC 4490. + +It typically uses ephemeral key pair to compute shared key and packs its +public part along with encrypted key. So, for most cases use of +EVP_PKEY_encrypt/EVP_PKEY_decrypt with GOST keys is almost same as with +RSA. + +However, if peerkey field in the EVP_PKEY_CTX structure is set (using +EVP_PKEY_derive_set_peerkey function) to EVP_PKEY structure which has private +key and uses same parameters as the public key from which this EVP_PKEY_CTX is +created, EVP_PKEY_encrypt will use this private key to compute shared key and +set ephemeral key in the GOST_key_transport structure to NULL. In this case +pkey and peerkey fields in the EVP_PKEY_CTX are used upside-down. + +If EVP_PKEY_decrypt encounters GOST_key_transport structure with NULL +public key field, it tries to use peerkey field from the context to +compute shared key. In this case peerkey field should really contain +peer public key. + +Encrypt operation supports EVP_PKEY_CTRL_SET_IV operation as well. +It can be used when some specific restriction on UKM are imposed by +higher level protocol. For instance, description of GOST ciphersuites +requires UKM to be derived from shared secret. + +If UKM is not set by this control command, encrypt operation would +generate random UKM. + + +This sources include implementation of GOST 28147-89 and GOST R 34.11-94 +which are completely indepentent from OpenSSL and can be used separately +(files gost89.c, gost89.h, gosthash.c, gosthash.h) Utility gostsum (file +gostsum.c) is provided as example of such separate usage. This is +program, simular to md5sum and sha1sum utilities, but calculates GOST R +34.11-94 hash. + +Makefile doesn't include rule for compiling gostsum. +Use command + +$(CC) -o gostsum gostsum.c gost89.c gosthash.c +where $(CC) is name of your C compiler. + +Implementations of GOST R 34.10-xx, including VKO algorithms heavily +depends on OpenSSL BIGNUM and Elliptic Curve libraries. + + diff --git a/openssl/engines/ccgost/e_gost_err.c b/openssl/engines/ccgost/e_gost_err.c new file mode 100644 index 000000000..9a79a374e --- /dev/null +++ b/openssl/engines/ccgost/e_gost_err.c @@ -0,0 +1,212 @@ +/* e_gost_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2009 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_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_GOST2001_KEYGEN), "GOST2001_KEYGEN"}, +{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_COMPUTE_PUBLIC), "GOST94_COMPUTE_PUBLIC"}, +{ERR_FUNC(GOST_F_GOST_CIPHER_CTL), "GOST_CIPHER_CTL"}, +{ERR_FUNC(GOST_F_GOST_DO_SIGN), "GOST_DO_SIGN"}, +{ERR_FUNC(GOST_F_GOST_DO_VERIFY), "GOST_DO_VERIFY"}, +{ERR_FUNC(GOST_F_GOST_IMIT_CTRL), "GOST_IMIT_CTRL"}, +{ERR_FUNC(GOST_F_GOST_IMIT_FINAL), "GOST_IMIT_FINAL"}, +{ERR_FUNC(GOST_F_GOST_IMIT_UPDATE), "GOST_IMIT_UPDATE"}, +{ERR_FUNC(GOST_F_PARAM_COPY_GOST01), "PARAM_COPY_GOST01"}, +{ERR_FUNC(GOST_F_PARAM_COPY_GOST94), "PARAM_COPY_GOST94"}, +{ERR_FUNC(GOST_F_PKEY_GOST01CP_DECRYPT), "PKEY_GOST01CP_DECRYPT"}, +{ERR_FUNC(GOST_F_PKEY_GOST01CP_ENCRYPT), "PKEY_GOST01CP_ENCRYPT"}, +{ERR_FUNC(GOST_F_PKEY_GOST01CP_KEYGEN), "PKEY_GOST01CP_KEYGEN"}, +{ERR_FUNC(GOST_F_PKEY_GOST01_PARAMGEN), "PKEY_GOST01_PARAMGEN"}, +{ERR_FUNC(GOST_F_PKEY_GOST2001_DERIVE), "PKEY_GOST2001_DERIVE"}, +{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_GOST94CP_KEYGEN), "PKEY_GOST94CP_KEYGEN"}, +{ERR_FUNC(GOST_F_PKEY_GOST94_PARAMGEN), "PKEY_GOST94_PARAMGEN"}, +{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_PKEY_GOST_MAC_CTRL), "PKEY_GOST_MAC_CTRL"}, +{ERR_FUNC(GOST_F_PKEY_GOST_MAC_CTRL_STR), "PKEY_GOST_MAC_CTRL_STR"}, +{ERR_FUNC(GOST_F_PKEY_GOST_MAC_KEYGEN), "PKEY_GOST_MAC_KEYGEN"}, +{ERR_FUNC(GOST_F_PRINT_GOST_01), "PRINT_GOST_01"}, +{ERR_FUNC(GOST_F_PRIV_DECODE_GOST), "PRIV_DECODE_GOST"}, +{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_CTRL_CALL_FAILED) ,"ctrl call failed"}, +{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_INCOMPATIBLE_ALGORITHMS),"incompatible algorithms"}, +{ERR_REASON(GOST_R_INCOMPATIBLE_PEER_KEY),"incompatible peer key"}, +{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_GOST94_PARMSET),"invalid gost94 parmset"}, +{ERR_REASON(GOST_R_INVALID_IV_LENGTH) ,"invalid iv length"}, +{ERR_REASON(GOST_R_INVALID_MAC_KEY_LENGTH),"invalid mac key 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_MAC_KEY_NOT_SET) ,"mac key not set"}, +{ERR_REASON(GOST_R_MALLOC_FAILURE) ,"malloc failure"}, +{ERR_REASON(GOST_R_NO_MEMORY) ,"no memory"}, +{ERR_REASON(GOST_R_NO_PARAMETERS_SET) ,"no parameters set"}, +{ERR_REASON(GOST_R_NO_PEER_KEY) ,"no peer key"}, +{ERR_REASON(GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR),"no private part of non ephemeral keypair"}, +{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_SIGNATURE_MISMATCH) ,"signature mismatch"}, +{ERR_REASON(GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q),"signature parts greater than q"}, +{ERR_REASON(GOST_R_UKM_NOT_SET) ,"ukm not set"}, +{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/openssl/engines/ccgost/e_gost_err.h b/openssl/engines/ccgost/e_gost_err.h new file mode 100644 index 000000000..6dc500079 --- /dev/null +++ b/openssl/engines/ccgost/e_gost_err.h @@ -0,0 +1,156 @@ +/* ==================================================================== + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +/* 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 99 +#define GOST_F_ENCODE_GOST_ALGOR_PARAMS 100 +#define GOST_F_FILL_GOST2001_PARAMS 101 +#define GOST_F_FILL_GOST94_PARAMS 102 +#define GOST_F_GET_ENCRYPTION_PARAMS 103 +#define GOST_F_GOST2001_COMPUTE_PUBLIC 104 +#define GOST_F_GOST2001_DO_SIGN 105 +#define GOST_F_GOST2001_DO_VERIFY 106 +#define GOST_F_GOST2001_KEYGEN 107 +#define GOST_F_GOST89_GET_ASN1_PARAMETERS 108 +#define GOST_F_GOST89_SET_ASN1_PARAMETERS 109 +#define GOST_F_GOST94_COMPUTE_PUBLIC 110 +#define GOST_F_GOST_CIPHER_CTL 111 +#define GOST_F_GOST_DO_SIGN 112 +#define GOST_F_GOST_DO_VERIFY 113 +#define GOST_F_GOST_IMIT_CTRL 114 +#define GOST_F_GOST_IMIT_FINAL 140 +#define GOST_F_GOST_IMIT_UPDATE 115 +#define GOST_F_PARAM_COPY_GOST01 116 +#define GOST_F_PARAM_COPY_GOST94 117 +#define GOST_F_PKEY_GOST01CP_DECRYPT 118 +#define GOST_F_PKEY_GOST01CP_ENCRYPT 119 +#define GOST_F_PKEY_GOST01CP_KEYGEN 120 +#define GOST_F_PKEY_GOST01_PARAMGEN 138 +#define GOST_F_PKEY_GOST2001_DERIVE 121 +#define GOST_F_PKEY_GOST94CP_DECRYPT 122 +#define GOST_F_PKEY_GOST94CP_ENCRYPT 123 +#define GOST_F_PKEY_GOST94CP_KEYGEN 124 +#define GOST_F_PKEY_GOST94_PARAMGEN 139 +#define GOST_F_PKEY_GOST_CTRL 125 +#define GOST_F_PKEY_GOST_CTRL01_STR 126 +#define GOST_F_PKEY_GOST_CTRL94_STR 127 +#define GOST_F_PKEY_GOST_MAC_CTRL 128 +#define GOST_F_PKEY_GOST_MAC_CTRL_STR 129 +#define GOST_F_PKEY_GOST_MAC_KEYGEN 130 +#define GOST_F_PRINT_GOST_01 131 +#define GOST_F_PRIV_DECODE_GOST 132 +#define GOST_F_PUB_DECODE_GOST01 133 +#define GOST_F_PUB_DECODE_GOST94 134 +#define GOST_F_PUB_ENCODE_GOST01 135 +#define GOST_F_UNPACK_CC_SIGNATURE 136 +#define GOST_F_UNPACK_CP_SIGNATURE 137 + +/* Reason codes. */ +#define GOST_R_BAD_KEY_PARAMETERS_FORMAT 99 +#define GOST_R_BAD_PKEY_PARAMETERS_FORMAT 100 +#define GOST_R_CANNOT_PACK_EPHEMERAL_KEY 101 +#define GOST_R_CTRL_CALL_FAILED 132 +#define GOST_R_ERROR_COMPUTING_SHARED_KEY 102 +#define GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO 103 +#define GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO 104 +#define GOST_R_INCOMPATIBLE_ALGORITHMS 105 +#define GOST_R_INCOMPATIBLE_PEER_KEY 131 +#define GOST_R_INVALID_CIPHER_PARAMS 106 +#define GOST_R_INVALID_CIPHER_PARAM_OID 107 +#define GOST_R_INVALID_DIGEST_TYPE 108 +#define GOST_R_INVALID_GOST94_PARMSET 109 +#define GOST_R_INVALID_IV_LENGTH 110 +#define GOST_R_INVALID_MAC_KEY_LENGTH 111 +#define GOST_R_INVALID_PARAMSET 112 +#define GOST_R_KEY_IS_NOT_INITALIZED 113 +#define GOST_R_KEY_IS_NOT_INITIALIZED 114 +#define GOST_R_KEY_PARAMETERS_MISSING 115 +#define GOST_R_MAC_KEY_NOT_SET 116 +#define GOST_R_MALLOC_FAILURE 117 +#define GOST_R_NO_MEMORY 118 +#define GOST_R_NO_PARAMETERS_SET 119 +#define GOST_R_NO_PEER_KEY 120 +#define GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR 121 +#define GOST_R_PUBLIC_KEY_UNDEFINED 122 +#define GOST_R_RANDOM_GENERATOR_ERROR 123 +#define GOST_R_RANDOM_GENERATOR_FAILURE 124 +#define GOST_R_RANDOM_NUMBER_GENERATOR_FAILED 125 +#define GOST_R_SIGNATURE_MISMATCH 126 +#define GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q 127 +#define GOST_R_UKM_NOT_SET 128 +#define GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND 129 +#define GOST_R_UNSUPPORTED_PARAMETER_SET 130 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/openssl/engines/ccgost/e_gost_err.proto b/openssl/engines/ccgost/e_gost_err.proto new file mode 100644 index 000000000..c57bd1bd8 --- /dev/null +++ b/openssl/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/openssl/engines/ccgost/gost.ec b/openssl/engines/ccgost/gost.ec new file mode 100644 index 000000000..6c2c85e57 --- /dev/null +++ b/openssl/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/openssl/engines/ccgost/gost2001.c b/openssl/engines/ccgost/gost2001.c new file mode 100644 index 000000000..dacd82d2b --- /dev/null +++ b/openssl/engines/ccgost/gost2001.c @@ -0,0 +1,343 @@ +/********************************************************************** + * 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 "gost_lcl.h" +#include "gost_params.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=NULL; + 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); + newsig = NULL; + 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); + newsig = NULL; + 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); + newsig = NULL; + 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_GOST2001_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_KEYGEN,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/openssl/engines/ccgost/gost2001_keyx.c b/openssl/engines/ccgost/gost2001_keyx.c new file mode 100644 index 000000000..00759bcab --- /dev/null +++ b/openssl/engines/ccgost/gost2001_keyx.c @@ -0,0 +1,304 @@ +/********************************************************************** + * 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 "e_gost_err.h" +#include "gost_keywrap.h" +#include "gost_lcl.h" +#include "gost2001_keyx.h" + + + +/* 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; + } + + +/* + * EVP_PKEY_METHOD callback derive. Implements VKO R 34.10-2001 + * algorithm + */ +int pkey_gost2001_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) +{ + /* Public key of peer in the ctx field peerkey + * Our private key in the ctx pkey + * ukm is in the algorithm specific context data + */ + EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx); + EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx); + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + + if (!data->shared_ukm) { + GOSTerr(GOST_F_PKEY_GOST2001_DERIVE, GOST_R_UKM_NOT_SET); + return 0; + } + + if (key == NULL) { + *keylen = 32; + return 32; + } + + *keylen=VKO_compute_key(key, 32, EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)), + (EC_KEY *)EVP_PKEY_get0(my_key),data->shared_ukm); + return 1; +} + + + + +/* + * EVP_PKEY_METHOD callback encrypt + * Implementation of GOST2001 key transport, cryptocom variation + */ +/* Generates ephemeral key based on pubk algorithm + * computes shared key using VKO and returns filled up + * GOST_KEY_TRANSPORT structure + */ + +/* + * 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); + const struct gost_cipher_info *param=get_encryption_params(NULL); + unsigned char ukm[8], shared_key[32], crypted_key[44]; + int ret=0; + int key_is_ephemeral=1; + gost_ctx cctx; + EVP_PKEY *sec_key=EVP_PKEY_CTX_get0_peerkey(pctx); + if (data->shared_ukm) + { + memcpy(ukm, data->shared_ukm,8); + } + else if (out) + { + + if (RAND_bytes(ukm,8)<=0) + { + GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, + GOST_R_RANDOM_GENERATOR_FAILURE); + return 0; + } + } + /* Check for private key in the peer_key of context */ + if (sec_key) + { + key_is_ephemeral=0; + if (!gost_get0_priv_key(sec_key)) + { + GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, + GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR); + goto err; + } + } + else + { + key_is_ephemeral=1; + if (out) + { + sec_key = EVP_PKEY_new(); + EVP_PKEY_assign(sec_key,EVP_PKEY_base_id(pubk),EC_KEY_new()); + EVP_PKEY_copy_parameters(sec_key,pubk); + if (!gost2001_keygen(EVP_PKEY_get0(sec_key))) + { + goto err; + } + } + } + if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS) && param == gost_cipher_list) + { + param= gost_cipher_list+1; + } + if (out) + { + VKO_compute_key(shared_key,32,EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)),EVP_PKEY_get0(sec_key),ukm); + gost_init(&cctx,param->sblock); + keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key); + } + gkt = GOST_KEY_TRANSPORT_new(); + if (!gkt) + { + goto err; + } + if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv, + ukm,8)) + { + goto err; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4)) + { + goto err; + } + if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32)) + { + goto err; + } + if (key_is_ephemeral) { + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,out?sec_key:pubk)) + { + GOSTerr(GOST_F_PKEY_GOST01CP_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); + if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key); + if (!key_is_ephemeral) + { + /* Set control "public key from client certificate used" */ + if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0) + { + GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT, + GOST_R_CTRL_CALL_FAILED); + goto err; + } + } + if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL))>0) ret =1; + GOST_KEY_TRANSPORT_free(gkt); + return ret; + err: + if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key); + GOST_KEY_TRANSPORT_free(gkt); + 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; + unsigned char wrappedKey[44]; + unsigned char sharedKey[32]; + gost_ctx ctx; + const struct gost_cipher_info *param=NULL; + EVP_PKEY *eph_key=NULL, *peerkey=NULL; + + if (!key) + { + *key_len = 32; + return 1; + } + gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p, + in_len); + if (!gkt) + { + GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO); + return -1; + } + + /* If key transport structure contains public key, use it */ + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + if (eph_key) + { + if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0) + { + GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT, + GOST_R_INCOMPATIBLE_PEER_KEY); + goto err; + } + } + else + { + /* Set control "public key from client certificate used" */ + if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0) + { + GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT, + GOST_R_CTRL_CALL_FAILED); + goto err; + } + } + peerkey = EVP_PKEY_CTX_get0_peerkey(pctx); + if (!peerkey) + { + GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT, + GOST_R_NO_PEER_KEY); + goto err; + } + + 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(peerkey)), + EVP_PKEY_get0(priv),wrappedKey); + if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key)) + { + GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT, + GOST_R_ERROR_COMPUTING_SHARED_KEY); + goto err; + } + + ret=1; +err: + if (eph_key) EVP_PKEY_free(eph_key); + if (gkt) GOST_KEY_TRANSPORT_free(gkt); + return ret; + } diff --git a/openssl/engines/ccgost/gost2001_keyx.h b/openssl/engines/ccgost/gost2001_keyx.h new file mode 100644 index 000000000..a014d9c1e --- /dev/null +++ b/openssl/engines/ccgost/gost2001_keyx.h @@ -0,0 +1,10 @@ +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); + +int decrypt_rfc4490_shared_key_2001(EVP_PKEY *priv, + GOST_KEY_TRANSPORT *gkt, + unsigned char *key_buf, + int key_buf_len) ; + diff --git a/openssl/engines/ccgost/gost89.c b/openssl/engines/ccgost/gost89.c new file mode 100644 index 000000000..7ebae0f71 --- /dev/null +++ b/openssl/engines/ccgost/gost89.c @@ -0,0 +1,409 @@ +/********************************************************************** + * 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*/ +static 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] = (byte)(n2&0xff); out[1] = (byte)((n2>>8)&0xff); + out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24); + out[4] = (byte)(n1&0xff); out[5] = (byte)((n1>>8)&0xff); + out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(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] = (byte)(n2&0xff); out[1] = (byte)((n2>>8)&0xff); + out[2] = (byte)((n2>>16)&0xff); out[3]=(byte)(n2>>24); + out[4] = (byte)(n1&0xff); out[5] = (byte)((n1>>8)&0xff); + out[6] = (byte)((n1>>16)&0xff); out[7] = (byte)(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]=(byte)(c->k[i]& 0xFF); + k[j+1]=(byte)((c->k[i]>>8 )&0xFF); + k[j+2]=(byte)((c->k[i]>>16) &0xFF); + k[j+3]=(byte)((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] = (byte)(n1&0xff); buffer[1] = (byte)((n1>>8)&0xff); + buffer[2] = (byte)((n1>>16)&0xff); buffer[3] = (byte)(n1>>24); + buffer[4] = (byte)(n2&0xff); buffer[5] = (byte)((n2>>8)&0xff); + buffer[6] = (byte)((n2>>16)&0xff); buffer[7] = (byte)(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]; + unsigned 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]; + unsigned 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/openssl/engines/ccgost/gost89.h b/openssl/engines/ccgost/gost89.h new file mode 100644 index 000000000..215785251 --- /dev/null +++ b/openssl/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/openssl/engines/ccgost/gost94_keyx.c b/openssl/engines/ccgost/gost94_keyx.c new file mode 100644 index 000000000..a183edbe8 --- /dev/null +++ b/openssl/engines/ccgost/gost94_keyx.c @@ -0,0 +1,287 @@ +/********************************************************************** + * 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 "gost89.h" +#include "gosthash.h" +#include "e_gost_err.h" +#include "gost_keywrap.h" +#include "gost_lcl.h" +/* Common functions for both 94 and 2001 key exchange schemes */ +/* 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 + * algorithm + */ +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 as specified in RFC 4357 + */ +static int make_cp_exchange_key(BIGNUM *priv_key,EVP_PKEY *pubk, unsigned char *shared_key) + { + unsigned char dh_key [128]; + int ret; + gost_hash_ctx hash_ctx; + DH *dh = DH_new(); + + if (!dh) + return 0; + memset(dh_key,0,128); + dh->g = BN_dup(pubk->pkey.dsa->g); + dh->p = BN_dup(pubk->pkey.dsa->p); + dh->priv_key = BN_dup(priv_key); + ret=compute_pair_key_le(dh_key,((DSA *)(EVP_PKEY_get0(pubk)))->pub_key,dh) ; + DH_free(dh); + if (!ret) 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 derive. Implements VKO R 34.10-94 */ + +int pkey_gost94_derive(EVP_PKEY_CTX *ctx,unsigned char *key,size_t *keylen) + { + EVP_PKEY *pubk = EVP_PKEY_CTX_get0_peerkey(ctx); + EVP_PKEY *mykey = EVP_PKEY_CTX_get0_pkey(ctx); + *keylen = 32; + if (key == NULL) return 1; + + return make_cp_exchange_key(gost_get0_priv_key(mykey), pubk, key); + } + +/* 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; + 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); + gost_ctx cctx; + int key_is_ephemeral=1; + EVP_PKEY *mykey = EVP_PKEY_CTX_get0_peerkey(ctx); + + /* Do not use vizir cipher parameters with cryptopro */ + if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS) && param == gost_cipher_list) + { + param= gost_cipher_list+1; + } + + if (mykey) + { + /* If key already set, it is not ephemeral */ + key_is_ephemeral=0; + if (!gost_get0_priv_key(mykey)) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR); + goto err; + } + } + else + { + /* Otherwise generate ephemeral key */ + key_is_ephemeral = 1; + if (out) + { + mykey = EVP_PKEY_new(); + EVP_PKEY_assign(mykey, EVP_PKEY_base_id(pubk),DSA_new()); + EVP_PKEY_copy_parameters(mykey,pubk); + if (!gost_sign_keygen(EVP_PKEY_get0(mykey))) + { + goto err; + } + } + } + if (out) + make_cp_exchange_key(gost_get0_priv_key(mykey),pubk,shared_key); + if (data->shared_ukm) + { + memcpy(ukm,data->shared_ukm,8); + } + else if (out) + { + if (RAND_bytes(ukm,8)<=0) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_RANDOM_GENERATOR_FAILURE); + goto err; + } + } + + if (out) { + gost_init(&cctx,param->sblock); + 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 (key_is_ephemeral) { + if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,out?mykey:pubk)) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY); + goto err; + } + if (out) EVP_PKEY_free(mykey); + } + ASN1_OBJECT_free(gkt->key_agreement_info->cipher); + gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid); + *outlen = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL); + if (*outlen == 0) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT,GOST_R_ERROR_PACKING_KEY_TRANSPORT_INFO); + goto err; + } + if (!key_is_ephemeral) + { + /* Set control "public key from client certificate used" */ + if (EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0) + { + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_CTRL_CALL_FAILED); + goto err; + } + } + GOST_KEY_TRANSPORT_free(gkt); + return 1; + memerr: + if (key_is_ephemeral) { + EVP_PKEY_free(mykey); + } + GOSTerr(GOST_F_PKEY_GOST94CP_ENCRYPT, + GOST_R_MALLOC_FAILURE); + err: + GOST_KEY_TRANSPORT_free(gkt); + 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) { + 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, *peerkey=NULL; + EVP_PKEY *priv= EVP_PKEY_CTX_get0_pkey(ctx); + + if (!key) + { + *key_len = 32; + return 1; + } + + 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); + return 0; + } + eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key); + if (eph_key) + { + if (EVP_PKEY_derive_set_peer(ctx, eph_key) <= 0) + { + GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, + GOST_R_INCOMPATIBLE_PEER_KEY); + goto err; + } + } + else + { + /* Set control "public key from client certificate used" */ + if (EVP_PKEY_CTX_ctrl(ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0) + { + GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, + GOST_R_CTRL_CALL_FAILED); + goto err; + } + } + peerkey = EVP_PKEY_CTX_get0_peerkey(ctx); + if (!peerkey) + { + GOSTerr(GOST_F_PKEY_GOST94CP_DECRYPT, + GOST_R_NO_PEER_KEY); + goto err; + } + + 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(gost_get0_priv_key(priv),peerkey,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); + return 1; +err: + EVP_PKEY_free(eph_key); + GOST_KEY_TRANSPORT_free(gkt); + return -1; + } + diff --git a/openssl/engines/ccgost/gost_ameth.c b/openssl/engines/ccgost/gost_ameth.c new file mode 100644 index 000000000..16a99ac2b --- /dev/null +++ b/openssl/engines/ccgost/gost_ameth.c @@ -0,0 +1,910 @@ +/********************************************************************** + * gost_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 <string.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/engine.h> +#include <openssl/evp.h> +#include <openssl/asn1.h> +#include "gost_params.h" +#include "gost_lcl.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: + 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; + void *_pval; + ASN1_STRING *pval = NULL; + const unsigned char *p; + GOST_KEY_PARAMS *gkp = NULL; + + X509_ALGOR_get0(&palg_obj, &ptype, &_pval, palg); + pval = _pval; + 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); + return 0; + } + 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: + { + 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: + { + 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: + { + 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: + { + 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_get0_priv_key(const EVP_PKEY *pkey) + { + switch (EVP_PKEY_base_id(pkey)) + { + case NID_id_GostR3410_94: + { + DSA *dsa = EVP_PKEY_get0((EVP_PKEY *)pkey); + if (!dsa) + { + return NULL; + } + if (!dsa->priv_key) return NULL; + return dsa->priv_key; + break; + } + case NID_id_GostR3410_2001: + { + 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 (BIGNUM *)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; + } + if (V_ASN1_OCTET_STRING == *p) + { + /* New format - Little endian octet string */ + unsigned char rev_buf[32]; + int i; + ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL,&p,priv_len); + if (!s||s->length !=32) + { + GOSTerr(GOST_F_PRIV_DECODE_GOST, + EVP_R_DECODE_ERROR); + return 0; + } + for (i=0;i<32;i++) + { + rev_buf[31-i]=s->data[i]; + } + ASN1_STRING_free(s); + pk_num = getbnfrombuf(rev_buf,32); + } + else + { + priv_key=d2i_ASN1_INTEGER(NULL,&p,priv_len); + if (!priv_key) return 0; + ret= ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL))!=NULL) ; + ASN1_INTEGER_free(priv_key); + if (!ret) + { + GOSTerr(GOST_F_PRIV_DECODE_GOST, + EVP_R_DECODE_ERROR); + return 0; + } + } + + 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; + + ASN1_INTEGER *asn1key=NULL; + if (!params) + { + return 0; + } + asn1key = BN_to_ASN1_INTEGER(gost_get0_priv_key(pk),NULL); + 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); + } +/* --------- printing keys --------------------------------*/ +static int print_gost_94(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx, int type) + { + int param_nid = NID_undef; + + if (type == 2) + { + BIGNUM *key; + + if (!BIO_indent(out,indent,128)) return 0; + BIO_printf(out,"Private key: "); + key = gost_get0_priv_key(pkey); + if (!key) + BIO_printf(out,"<undefined>"); + else + BN_print(out,key); + BIO_printf(out,"\n"); + } + if (type >= 1) + { + BIGNUM *pubkey; + + pubkey = ((DSA *)EVP_PKEY_get0((EVP_PKEY *)pkey))->pub_key; + BIO_indent(out,indent,128); + BIO_printf(out,"Public key: "); + BN_print(out,pubkey); + BIO_printf(out,"\n"); + } + + param_nid = gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)pkey)); + BIO_indent(out,indent,128); + BIO_printf(out, "Parameter set: %s\n",OBJ_nid2ln(param_nid)); + return 1; +} + +static int param_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) + { + return print_gost_94(out, pkey, indent, pctx,0); + } + +static int pub_print_gost94(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) + { + return print_gost_94(out,pkey, indent, pctx,1); + } +static int priv_print_gost94(BIO *out,const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) + { + return print_gost_94(out,pkey,indent,pctx,2); + } + +static int print_gost_01(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx, int type) + { + int param_nid = NID_undef; + if (type == 2) + { + BIGNUM *key; + + if (!BIO_indent(out,indent,128)) return 0; + BIO_printf(out,"Private key: "); + key = gost_get0_priv_key(pkey); + if (!key) + BIO_printf(out,"<undefined)"); + else + BN_print(out,key); + BIO_printf(out,"\n"); + } + if (type >= 1) + { + BN_CTX *ctx = BN_CTX_new(); + BIGNUM *X,*Y; + const EC_POINT *pubkey; + const EC_GROUP *group; + + if (!ctx) + { + GOSTerr(GOST_F_PRINT_GOST_01,ERR_R_MALLOC_FAILURE); + return 0; + } + BN_CTX_start(ctx); + X = BN_CTX_get(ctx); + Y = BN_CTX_get(ctx); + pubkey = EC_KEY_get0_public_key((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey)); + group = EC_KEY_get0_group((EC_KEY *)EVP_PKEY_get0((EVP_PKEY *)pkey)); + if (!EC_POINT_get_affine_coordinates_GFp(group,pubkey,X,Y,ctx)) + { + GOSTerr(GOST_F_PRINT_GOST_01,ERR_R_EC_LIB); + BN_CTX_free(ctx); + return 0; + } + if (!BIO_indent(out,indent,128)) return 0; + BIO_printf(out,"Public key:\n"); + if (!BIO_indent(out,indent+3,128)) return 0; + BIO_printf(out,"X:"); + BN_print(out,X); + BIO_printf(out,"\n"); + BIO_indent(out,indent+3,128); + BIO_printf(out,"Y:"); + BN_print(out,Y); + BIO_printf(out,"\n"); + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)pkey))); + if (!BIO_indent(out,indent,128)) return 0; + BIO_printf(out,"Parameter set: %s\n",OBJ_nid2ln(param_nid)); + return 1; +} +static int param_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) + { + return print_gost_01(out,pkey,indent,pctx,0); + } +static int pub_print_gost01(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) + { + return print_gost_01(out,pkey, indent, pctx,1); + } +static int priv_print_gost01(BIO *out,const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) + { + return print_gost_01(out,pkey,indent,pctx,2); + } +/* ---------------------------------------------------------------------*/ +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_GOST01, + 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_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 = V_ASN1_UNDEF; + 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; + int len; + 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_GOST01,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]; + } + len=octet->length/2; + ASN1_OCTET_STRING_free(octet); + + Y= getbnfrombuf(databuf,len); + X= getbnfrombuf(databuf+len,len); + 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); + EC_POINT_free(pub_key); + BN_free(X); + BN_free(Y); + 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); + EC_POINT_free(pub_key); + 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 = V_ASN1_UNDEF; + + 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); + + 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 pkey_size_gost(const EVP_PKEY *pk) + { + return 64; + } + +static int pkey_bits_gost(const EVP_PKEY *pk) + { + return 256; + } +/*------------------------ ASN1 METHOD for GOST MAC -------------------*/ +static void mackey_free_gost(EVP_PKEY *pk) + { + if (pk->pkey.ptr) { + OPENSSL_free(pk->pkey.ptr); + } + } +static int mac_ctrl_gost(EVP_PKEY *pkey, int op, long arg1, void *arg2) +{ + switch (op) + { + case ASN1_PKEY_CTRL_DEFAULT_MD_NID: + *(int *)arg2 = NID_undef; + return 2; + } + return -2; +} + +static int gost94_param_encode(const EVP_PKEY *pkey, unsigned char **pder) +{ + int nid=gost94_nid_by_params(EVP_PKEY_get0((EVP_PKEY *)pkey)); + return i2d_ASN1_OBJECT(OBJ_nid2obj(nid),pder); +} +static int gost2001_param_encode(const EVP_PKEY *pkey, unsigned char **pder) +{ + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)pkey))); + return i2d_ASN1_OBJECT(OBJ_nid2obj(nid),pder); +} + +static int gost94_param_decode(EVP_PKEY *pkey, const unsigned char **pder, int derlen) +{ + ASN1_OBJECT *obj=NULL; + DSA *dsa = EVP_PKEY_get0(pkey); + int nid; + if (d2i_ASN1_OBJECT(&obj,pder,derlen)==NULL) { + return 0; + } + nid = OBJ_obj2nid(obj); + ASN1_OBJECT_free(obj); + if (!dsa) + { + dsa=DSA_new(); + if (!EVP_PKEY_assign(pkey,NID_id_GostR3410_94,dsa)) return 0; + } + if (!fill_GOST94_params(dsa,nid)) return 0; + return 1; +} + +static int gost2001_param_decode(EVP_PKEY *pkey, const unsigned char **pder, int derlen) { + ASN1_OBJECT *obj=NULL; + int nid; + EC_KEY *ec = EVP_PKEY_get0(pkey); + if (d2i_ASN1_OBJECT(&obj,pder,derlen)==NULL) { + return 0; + } + nid = OBJ_obj2nid(obj); + ASN1_OBJECT_free(obj); + if (!ec) + { + ec = EC_KEY_new(); + if (!EVP_PKEY_assign(pkey,NID_id_GostR3410_2001,ec)) return 0; + } + if (!fill_GOST2001_params(ec, nid)) return 0; + return 1; +} + + + + + +/* ----------------------------------------------------------------------*/ +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: + EVP_PKEY_asn1_set_free (*ameth, pkey_free_gost94); + EVP_PKEY_asn1_set_private (*ameth, + priv_decode_gost, priv_encode_gost, + priv_print_gost94); + + EVP_PKEY_asn1_set_param (*ameth, + gost94_param_decode, gost94_param_encode, + param_missing_gost94, param_copy_gost94, + param_cmp_gost94,param_print_gost94 ); + 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: + EVP_PKEY_asn1_set_free (*ameth, pkey_free_gost01); + EVP_PKEY_asn1_set_private (*ameth, + priv_decode_gost, priv_encode_gost, + priv_print_gost01); + + EVP_PKEY_asn1_set_param (*ameth, + gost2001_param_decode, gost2001_param_encode, + param_missing_gost01, param_copy_gost01, + param_cmp_gost01, param_print_gost01); + 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; + case NID_id_Gost28147_89_MAC: + EVP_PKEY_asn1_set_free(*ameth, mackey_free_gost); + EVP_PKEY_asn1_set_ctrl(*ameth,mac_ctrl_gost); + break; + } + return 1; + } diff --git a/openssl/engines/ccgost/gost_asn1.c b/openssl/engines/ccgost/gost_asn1.c new file mode 100644 index 000000000..318ecfce5 --- /dev/null +++ b/openssl/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_lcl.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_OPT(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/openssl/engines/ccgost/gost_crypt.c b/openssl/engines/ccgost/gost_crypt.c new file mode 100644 index 000000000..eb11f0e32 --- /dev/null +++ b/openssl/engines/ccgost/gost_crypt.c @@ -0,0 +1,614 @@ +/********************************************************************** + * 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 "gost89.h" +#include <openssl/rand.h> +#include "e_gost_err.h" +#include "gost_lcl.h" +static int gost_cipher_init(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); +/* Handles block of data in CFB mode */ +static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t 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, size_t 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, + }; + +EVP_CIPHER cipher_gost_cpacnt = + { + NID_gost89_cnt, + 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_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_cpa = + { + NID_id_Gost28147_89_MAC, + NID_undef, + 4, + 0, + gost_imit_init_cpa, + gost_imit_update, + gost_imit_final, + gost_imit_copy, + gost_imit_cleanup, + NULL, + NULL, + {0,0,0,0,0}, + 8, + sizeof(struct ossl_gost_imit_ctx), + gost_imit_ctrl + }; + +/* + * 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_id_Gost28147_89_TestParamSet,&Gost28147_TestParamSet,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 = get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS); + if (!params || !strlen(params)) + return &gost_cipher_list[1]; + + 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. */ +static 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 (ctx->app_data == NULL) + { + if (!gost_cipher_set_param(c,paramNID)) return 0; + ctx->app_data = ctx->cipher_data; + } + 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; + } + +static 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; + 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 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]=(unsigned char)(g&0xff); + buf1[1]=(unsigned char)((g>>8)&0xff); + buf1[2]=(unsigned char)((g>>16)&0xff); + buf1[3]=(unsigned char)((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]=(unsigned char)(g&0xff); + buf1[5]=(unsigned char)((g>>8)&0xff); + buf1[6]=(unsigned char)((g>>16)&0xff); + buf1[7]=(unsigned char)((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, size_t inl) + { + const unsigned char *in_ptr=in; + unsigned char *out_ptr=out; + size_t i=0; + size_t j=0; +/* 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; + } + +static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { + const unsigned char *in_ptr=in; + unsigned char *out_ptr=out; + size_t i=0; + size_t 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(&((struct ossl_gost_cipher_ctx *)ctx->cipher_data)->cctx); + ctx->app_data = NULL; + 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; + } + case EVP_CTRL_PBE_PRF_NID: + if (ptr) { + *((int *)ptr)= NID_id_HMACGostR3411_94; + return 1; + } else { + return 0; + } + + 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; + } + + +int gost_imit_init_cpa(EVP_MD_CTX *ctx) + { + struct ossl_gost_imit_ctx *c = ctx->md_data; + memset(c->buffer,0,16); + c->count = 0; + c->bytes_left=0; + c->key_meshing=1; + gost_init(&(c->cctx),&Gost28147_CryptoProParamSetA); + return 1; + } + +static void mac_block_mesh(struct ossl_gost_imit_ctx *c,const unsigned char *data) + { + unsigned 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)) { + GOSTerr(GOST_F_GOST_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_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->key_set) { + GOSTerr(GOST_F_GOST_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET); + return 0; + } + 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_KEY_LEN: + *((unsigned int*)(ptr)) = 32; + return 1; + case EVP_MD_CTRL_SET_KEY: + { + if (arg!=32) { + GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_LENGTH); + return 0; + } + + gost_key(&(((struct ossl_gost_imit_ctx*)(ctx->md_data))->cctx),ptr) ; + ((struct ossl_gost_imit_ctx*)(ctx->md_data))->key_set = 1; + return 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; + } + diff --git a/openssl/engines/ccgost/gost_ctl.c b/openssl/engines/ccgost/gost_ctl.c new file mode 100644 index 000000000..d3cd17181 --- /dev/null +++ b/openssl/engines/ccgost/gost_ctl.c @@ -0,0 +1,89 @@ +/********************************************************************** + * gost_ctl.c * + * Copyright (c) 2005-2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Implementation of control commands for GOST engine * + * OpenSSL 0.9.9 libraries required * + **********************************************************************/ +#include <stdlib.h> +#include <string.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/engine.h> +#include <openssl/buffer.h> +#include "gost_lcl.h" + +static char *gost_params[GOST_PARAM_MAX+1]={NULL}; +static const char *gost_envnames[]={"CRYPT_PARAMS"}; +const ENGINE_CMD_DEFN gost_cmds[]= + { +/* { GOST_CTRL_RNG, + "RNG", + "Type of random number generator to use", + ENGINE_CMD_FLAG_STRING + }, + { GOST_CTRL_RNG_PARAMS, + "RNG_PARAMS", + "Parameter for random number generator", + ENGINE_CMD_FLAG_STRING + }, +*/ { GOST_CTRL_CRYPT_PARAMS, + "CRYPT_PARAMS", + "OID of default GOST 28147-89 parameters", + ENGINE_CMD_FLAG_STRING + }, +{0,NULL,NULL,0} + }; + +void gost_param_free() +{ + int i; + for (i=0;i<=GOST_PARAM_MAX;i++) + if (gost_params[i]!=NULL) + { + OPENSSL_free(gost_params[i]); + gost_params[i]=NULL; + } + +} + +int gost_control_func(ENGINE *e,int cmd,long i, void *p, void (*f)(void)) + { + int param = cmd-ENGINE_CMD_BASE; + int ret=0; + if (param <0 || param >GOST_PARAM_MAX) return -1; + ret=gost_set_default_param(param,p); + return ret; + } + +const char *get_gost_engine_param(int param) + { + char *tmp; + if (param <0 || param >GOST_PARAM_MAX) return NULL; + if (gost_params[param]!=NULL) + { + return gost_params[param]; + } + tmp = getenv(gost_envnames[param]); + if (tmp) + { + if (gost_params[param]) OPENSSL_free(gost_params[param]); + gost_params[param] = BUF_strdup(tmp); + return gost_params[param]; + } + return NULL; + } + +int gost_set_default_param(int param, const char *value) + { + const char *tmp; + if (param <0 || param >GOST_PARAM_MAX) return 0; + tmp = getenv(gost_envnames[param]); + /* if there is value in the environment, use it, else -passed string * */ + if (!tmp) tmp=value; + if (gost_params[param]) OPENSSL_free(gost_params[param]); + gost_params[param] = BUF_strdup(tmp); + + return 1; + } diff --git a/openssl/engines/ccgost/gost_eng.c b/openssl/engines/ccgost/gost_eng.c new file mode 100644 index 000000000..d2cbe3b83 --- /dev/null +++ b/openssl/engines/ccgost/gost_eng.c @@ -0,0 +1,273 @@ +/********************************************************************** + * gost_eng.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/crypto.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/engine.h> +#include <openssl/obj_mac.h> +#include "e_gost_err.h" +#include "gost_lcl.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, NID_gost89_cnt,0}; + +static int gost_digest_nids[] = + {NID_id_GostR3411_94,NID_id_Gost28147_89_MAC, 0}; + +static int gost_pkey_meth_nids[] = + {NID_id_GostR3410_94, + NID_id_GostR3410_2001, NID_id_Gost28147_89_MAC, 0}; + +static EVP_PKEY_METHOD *pmeth_GostR3410_94 = NULL, + *pmeth_GostR3410_2001 = NULL, + *pmeth_Gost28147_MAC = NULL; + +static EVP_PKEY_ASN1_METHOD *ameth_GostR3410_94 = NULL, + *ameth_GostR3410_2001 = NULL, + *ameth_Gost28147_MAC = 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) + { + gost_param_free(); + 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; + } + /* Control function and commands */ + if (!ENGINE_set_cmd_defns(e,gost_cmds)) + { + fprintf(stderr,"ENGINE_set_cmd_defns failed\n"); + goto end; + } + if (!ENGINE_set_ctrl_function(e,gost_control_func)) + { + fprintf(stderr,"ENGINE_set_ctrl_func 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, &ameth_GostR3410_94, "GOST94", "GOST R 34.10-94")) goto end; + if (!register_ameth_gost(NID_id_GostR3410_2001, &ameth_GostR3410_2001, "GOST2001", "GOST R 34.10-2001")) goto end; + if (!register_ameth_gost(NID_id_Gost28147_89_MAC, &ameth_Gost28147_MAC, + "GOST-MAC", "GOST 28147-89 MAC")) goto end; + + if (!register_pmeth_gost(NID_id_GostR3410_94, &pmeth_GostR3410_94, 0)) goto end; + if (!register_pmeth_gost(NID_id_GostR3410_2001, &pmeth_GostR3410_2001, 0)) goto end; + if (!register_pmeth_gost(NID_id_Gost28147_89_MAC, &pmeth_Gost28147_MAC, 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_cipher(&cipher_gost_cpacnt) + || ! EVP_add_digest(&digest_gost) + || ! EVP_add_digest(&imit_gost_cpa) + ) + { + goto end; + } + + ERR_load_GOST_strings(); + ret = 1; + end: + return ret; + } + +#ifndef OPENSSL_NO_DYNAMIC_ENGINE +IMPLEMENT_DYNAMIC_BIND_FN(bind_gost) +IMPLEMENT_DYNAMIC_CHECK_FN() +#endif /* ndef 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 2; + } + /*printf("Digest no %d requested\n",nid);*/ + if(nid == NID_id_GostR3411_94) + { + *digest = &digest_gost; + } + else if (nid == NID_id_Gost28147_89_MAC) + { + *digest = &imit_gost_cpa; + } + 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 2; /* two ciphers are supported */ + } + + if(nid == NID_id_Gost28147_89) + { + *cipher = &cipher_gost; + } + else if (nid == NID_gost89_cnt) + { + *cipher = &cipher_gost_cpacnt; + } + 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 3; + } + + switch (nid) + { + case NID_id_GostR3410_94: *pmeth = pmeth_GostR3410_94; return 1; + case NID_id_GostR3410_2001: *pmeth = pmeth_GostR3410_2001; return 1; + case NID_id_Gost28147_89_MAC: *pmeth = pmeth_Gost28147_MAC; 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 3; + } + switch (nid) + { + case NID_id_GostR3410_94: *ameth = ameth_GostR3410_94; return 1; + case NID_id_GostR3410_2001: *ameth = ameth_GostR3410_2001; return 1; + case NID_id_Gost28147_89_MAC: *ameth = ameth_Gost28147_MAC; return 1; + + default:; + } + + *ameth = NULL; + return 0; + } + +#ifdef OPENSSL_NO_DYNAMIC_ENGINE +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) + { + ENGINE *toadd =engine_gost(); + if (!toadd) return; + ENGINE_add(toadd); + ENGINE_free(toadd); + ERR_clear_error(); + } +#endif + diff --git a/openssl/engines/ccgost/gost_keywrap.c b/openssl/engines/ccgost/gost_keywrap.c new file mode 100644 index 000000000..c618f6da2 --- /dev/null +++ b/openssl/engines/ccgost/gost_keywrap.c @@ -0,0 +1,109 @@ +/********************************************************************** + * 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 "gost_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]=(unsigned char)(s1&0xff); + S[1]=(unsigned char)((s1>>8)&0xff); + S[2]=(unsigned char)((s1>>16)&0xff); + S[3]=(unsigned char)((s1>>24)&0xff); + S[4]=(unsigned char)(s2&0xff); + S[5]=(unsigned char)((s2>>8)&0xff); + S[6]=(unsigned char)((s2>>16)&0xff); + S[7]=(unsigned char)((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/openssl/engines/ccgost/gost_keywrap.h b/openssl/engines/ccgost/gost_keywrap.h new file mode 100644 index 000000000..37c2a0f73 --- /dev/null +++ b/openssl/engines/ccgost/gost_keywrap.h @@ -0,0 +1,56 @@ +/********************************************************************** + * gost_keywrap.h * + * 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/openssl/engines/ccgost/gost_lcl.h b/openssl/engines/ccgost/gost_lcl.h new file mode 100644 index 000000000..437a48cc8 --- /dev/null +++ b/openssl/engines/ccgost/gost_lcl.h @@ -0,0 +1,218 @@ +#ifndef GOST_TOOLS_H +#define GOST_TOOLS_H +/********************************************************************** + * gost_lcl.h * + * Copyright (c) 2006 Cryptocom LTD * + * This file is distributed under the same license as OpenSSL * + * * + * Internal declarations used in GOST engine * + * OpenSSL 0.9.9 libraries required to compile and use * + * this code * + **********************************************************************/ +#include <openssl/bn.h> +#include <openssl/evp.h> +#include <openssl/dsa.h> +#include <openssl/asn1t.h> +#include <openssl/x509.h> +#include <openssl/engine.h> +#include <openssl/ec.h> +#include "gost89.h" +#include "gosthash.h" +/* Control commands */ +#define GOST_PARAM_CRYPT_PARAMS 0 +#define GOST_PARAM_MAX 0 +#define GOST_CTRL_CRYPT_PARAMS (ENGINE_CMD_BASE+GOST_PARAM_CRYPT_PARAMS) + + extern const ENGINE_CMD_DEFN gost_cmds[]; + int gost_control_func(ENGINE *e,int cmd, long i, void *p, void (*f)(void)); + const char *get_gost_engine_param(int param); + int gost_set_default_param(int param, const char *value); + void gost_param_free(void); + +/* method registration */ + + 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); + +/* Gost-specific pmeth control-function parameters */ +/* For GOST R34.10 parameters */ +#define param_ctrl_string "paramset" +#define EVP_PKEY_CTRL_GOST_PARAMSET (EVP_PKEY_ALG_CTRL+1) +/* For GOST 28147 MAC */ +#define key_ctrl_string "key" +#define hexkey_ctrl_string "hexkey" +#define EVP_PKEY_CTRL_GOST_MAC_HEXKEY (EVP_PKEY_ALG_CTRL+3) +/* Pmeth internal representation */ + struct gost_pmeth_data { + int sign_param_nid; /* Should be set whenever parameters are filled */ + EVP_MD *md; + unsigned char *shared_ukm; + int peer_key_used; + }; + + struct gost_mac_pmeth_data { + int key_set; + EVP_MD *md; + unsigned char key[32]; + } ; +/* GOST-specific ASN1 structures */ + + +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; + +/* Hacks to shorten symbols to 31 characters or less, or OpenVMS. + This mimics what's done in symhacks.h, but since this is a very + local header file, I prefered to put this hack directly here. + -- Richard Levitte */ +#ifdef OPENSSL_SYS_VMS +#undef GOST_CLIENT_KEY_EXCHANGE_PARAMS_it +#define GOST_CLIENT_KEY_EXCHANGE_PARAMS_it GOST_CLIENT_KEY_EXC_PARAMS_it +#undef GOST_CLIENT_KEY_EXCHANGE_PARAMS_new +#define GOST_CLIENT_KEY_EXCHANGE_PARAMS_new GOST_CLIENT_KEY_EXC_PARAMS_new +#undef GOST_CLIENT_KEY_EXCHANGE_PARAMS_free +#define GOST_CLIENT_KEY_EXCHANGE_PARAMS_free GOST_CLIENT_KEY_EXC_PARAMS_free +#undef d2i_GOST_CLIENT_KEY_EXCHANGE_PARAMS +#define d2i_GOST_CLIENT_KEY_EXCHANGE_PARAMS d2i_GOST_CLIENT_KEY_EXC_PARAMS +#undef i2d_GOST_CLIENT_KEY_EXCHANGE_PARAMS +#define i2d_GOST_CLIENT_KEY_EXCHANGE_PARAMS i2d_GOST_CLIENT_KEY_EXC_PARAMS +#endif /* End of hack */ +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) +/*============== Message digest and cipher related structures ==========*/ + /* 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; +}; +/* EVP_MD structure for GOST R 34.11 */ +extern EVP_MD digest_gost; +/* EVP_MD structure for GOST 28147 in MAC mode */ +extern EVP_MD imit_gost_cpa; +/* 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; +}; +/* 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; +}; +/* 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; +extern EVP_CIPHER cipher_gost_cpacnt; +#define EVP_MD_CTRL_KEY_LEN (EVP_MD_CTRL_ALG_CTRL+3) +#define EVP_MD_CTRL_SET_KEY (EVP_MD_CTRL_ALG_CTRL+4) +/* EVP_PKEY_METHOD key encryption 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_GOST94cp_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_GOST01cp_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char* in, size_t in_len ); +/* derive functions */ +/* From gost2001_keyx.c */ +int pkey_gost2001_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen); +/* From gost94_keyx.c */ +int pkey_gost94_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen); +/* Internal functions for signature algorithms */ +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) ; +/*============== miscellaneous functions============================= */ +/* 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 CryptoPro rules */ +int pack_sign_cp(DSA_SIG *s,int order,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*/ +/* Returns pointer into EVP_PKEY structure */ +BIGNUM* gost_get0_priv_key(const EVP_PKEY *pkey) ; +/* Find NID by GOST 94 parameters */ +int gost94_nid_by_params(DSA *p) ; + + +#endif diff --git a/openssl/engines/ccgost/gost_md.c b/openssl/engines/ccgost/gost_md.c new file mode 100644 index 000000000..417e10887 --- /dev/null +++ b/openssl/engines/ccgost/gost_md.c @@ -0,0 +1,75 @@ +/********************************************************************** + * 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 "gost_lcl.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) + { + struct ossl_gost_digest_ctx *md_ctx=to->md_data; + if (to->md_data && from->md_data) { + memcpy(to->md_data,from->md_data,sizeof(struct ossl_gost_digest_ctx)); + md_ctx->dctx.cipher_ctx=&(md_ctx->cctx); + } + return 1; + } + +int gost_digest_cleanup(EVP_MD_CTX *ctx) + { + if (ctx->md_data) + memset(ctx->md_data,0,sizeof(struct ossl_gost_digest_ctx)); + return 1; + } diff --git a/openssl/engines/ccgost/gost_params.c b/openssl/engines/ccgost/gost_params.c new file mode 100644 index 000000000..40fc343af --- /dev/null +++ b/openssl/engines/ccgost/gost_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 "gost_params.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/openssl/engines/ccgost/gost_params.h b/openssl/engines/ccgost/gost_params.h new file mode 100644 index 000000000..4c3f5567d --- /dev/null +++ b/openssl/engines/ccgost/gost_params.h @@ -0,0 +1,34 @@ +/********************************************************************** + * gost_params.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/openssl/engines/ccgost/gost_pmeth.c b/openssl/engines/ccgost/gost_pmeth.c new file mode 100644 index 000000000..caaea99d3 --- /dev/null +++ b/openssl/engines/ccgost/gost_pmeth.c @@ -0,0 +1,621 @@ +/********************************************************************** + * gost_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 <openssl/x509v3.h> /*For string_to_hex */ +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "gost_params.h" +#include "gost_lcl.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; + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); + data = OPENSSL_malloc(sizeof(struct gost_pmeth_data)); + if (!data) return 0; + memset(data,0,sizeof(struct gost_pmeth_data)); + if (pkey && EVP_PKEY_get0(pkey)) + { + switch (EVP_PKEY_base_id(pkey)) { + case NID_id_GostR3410_94: + data->sign_param_nid = gost94_nid_by_params(EVP_PKEY_get0(pkey)); + break; + case NID_id_GostR3410_2001: + data->sign_param_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0((EVP_PKEY *)pkey))); + break; + default: + return 0; + } + } + 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 -> shared_ukm) { + dst_data->shared_ukm=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->shared_ukm) OPENSSL_free(data->shared_ukm); + 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; + return 1; + case EVP_PKEY_CTRL_SET_IV: + pctx->shared_ukm=OPENSSL_malloc((int)p1); + memcpy(pctx->shared_ukm,p2,(int) p1); + return 1; + case EVP_PKEY_CTRL_PEER_KEY: + if (p1 == 0 || p1 == 1) /* call from EVP_PKEY_derive_set_peer */ + return 1; + if (p1 == 2) /* TLS: peer key used? */ + return pctx->peer_key_used; + if (p1 == 3) /* TLS: peer key used! */ + return (pctx->peer_key_used = 1); + return -2; + } + 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, NULL); + } + 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, NULL); + } + return -2; + } + +/* --------------------- key generation --------------------------------*/ + +static int pkey_gost_paramgen_init(EVP_PKEY_CTX *ctx) { + return 1; +} +static int pkey_gost94_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) + { + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + DSA *dsa=NULL; + if (data->sign_param_nid == NID_undef) + { + GOSTerr(GOST_F_PKEY_GOST94_PARAMGEN, + GOST_R_NO_PARAMETERS_SET); + return 0; + } + dsa = DSA_new(); + if (!fill_GOST94_params(dsa,data->sign_param_nid)) + { + DSA_free(dsa); + return 0; + } + EVP_PKEY_assign(pkey,NID_id_GostR3410_94,dsa); + return 1; + } +static int pkey_gost01_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) + { + struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + EC_KEY *ec=NULL; + + if (data->sign_param_nid == NID_undef) + { + GOSTerr(GOST_F_PKEY_GOST01_PARAMGEN, + GOST_R_NO_PARAMETERS_SET); + return 0; + } + if (!ec) + ec = EC_KEY_new(); + if (!fill_GOST2001_params(ec,data->sign_param_nid)) + { + EC_KEY_free(ec); + return 0; + } + EVP_PKEY_assign(pkey,NID_id_GostR3410_2001,ec); + return 1; + } + +/* Generates Gost_R3410_94_cp key */ +static int pkey_gost94cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) + { + DSA *dsa; + if (!pkey_gost94_paramgen(ctx,pkey)) return 0; + dsa = EVP_PKEY_get0(pkey); + gost_sign_keygen(dsa); + return 1; + } + +/* Generates GOST_R3410 2001 key and assigns it using specified type */ +static int pkey_gost01cp_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) + { + EC_KEY *ec; + if (!pkey_gost01_paramgen(ctx,pkey)) return 0; + ec = EVP_PKEY_get0(pkey); + gost2001_keygen(ec); + return 1; + } + + + +/* ----------- sign callbacks --------------------------------------*/ + +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_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_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_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; +#ifdef DEBUG_SIGN + fprintf(stderr,"R="); + BN_print_fp(stderr,s->r); + fprintf(stderr,"\nS="); + BN_print_fp(stderr,s->s); + fprintf(stderr,"\n"); +#endif + 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) + { + return 1; + } +/* --------------- Derive init ------------------------------------*/ +static int pkey_gost_derive_init(EVP_PKEY_CTX *ctx) +{ + return 1; +} +/* -------- PKEY_METHOD for GOST MAC algorithm --------------------*/ +static int pkey_gost_mac_init(EVP_PKEY_CTX *ctx) + { + struct gost_mac_pmeth_data *data; + data = OPENSSL_malloc(sizeof(struct gost_mac_pmeth_data)); + if (!data) return 0; + memset(data,0,sizeof(struct gost_mac_pmeth_data)); + EVP_PKEY_CTX_set_data(ctx,data); + return 1; + } +static void pkey_gost_mac_cleanup (EVP_PKEY_CTX *ctx) + { + struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + OPENSSL_free(data); + } +static int pkey_gost_mac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) + { + struct gost_mac_pmeth_data *dst_data,*src_data; + if (!pkey_gost_mac_init(dst)) + { + return 0; + } + src_data = EVP_PKEY_CTX_get_data(src); + dst_data = EVP_PKEY_CTX_get_data(dst); + *dst_data = *src_data; + return 1; + } + +static int pkey_gost_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) + { + struct gost_mac_pmeth_data *data = +(struct gost_mac_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_Gost28147_89_MAC) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL, GOST_R_INVALID_DIGEST_TYPE); + return 0; + } + data->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_SET_MAC_KEY: + if (p1 != 32) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL, + GOST_R_INVALID_MAC_KEY_LENGTH); + return 0; + } + + memcpy(data->key,p2,32); + data->key_set = 1; + return 1; + case EVP_PKEY_CTRL_DIGESTINIT: + { + EVP_MD_CTX *mctx = p2; + void *key; + if (!data->key_set) + { + EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); + if (!pkey) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,GOST_R_MAC_KEY_NOT_SET); + return 0; + } + key = EVP_PKEY_get0(pkey); + if (!key) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL,GOST_R_MAC_KEY_NOT_SET); + return 0; + } + } else { + key = &(data->key); + } + return mctx->digest->md_ctrl(mctx,EVP_MD_CTRL_SET_KEY,32,key); + } + } + return -2; + } +static int pkey_gost_mac_ctrl_str(EVP_PKEY_CTX *ctx, + const char *type, const char *value) + { + if (!strcmp(type, key_ctrl_string)) + { + if (strlen(value)!=32) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR, + GOST_R_INVALID_MAC_KEY_LENGTH); + return 0; + } + return pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, + 32,(char *)value); + } + if (!strcmp(type, hexkey_ctrl_string)) + { + long keylen; int ret; + unsigned char *keybuf=string_to_hex(value,&keylen); + if (keylen != 32) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_CTRL_STR, + GOST_R_INVALID_MAC_KEY_LENGTH); + return 0; + } + ret= pkey_gost_mac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, + 32,keybuf); + OPENSSL_free(keybuf); + return ret; + + } + return -2; + } + +static int pkey_gost_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) + { + struct gost_mac_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx); + unsigned char *keydata; + if (!data->key_set) + { + GOSTerr(GOST_F_PKEY_GOST_MAC_KEYGEN,GOST_R_MAC_KEY_NOT_SET); + return 0; + } + keydata = OPENSSL_malloc(32); + memcpy(keydata,data->key,32); + EVP_PKEY_assign(pkey, NID_id_Gost28147_89_MAC, keydata); + return 1; + } + +static int pkey_gost_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) + { + return 1; +} + +static int pkey_gost_mac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx) + { + unsigned int tmpsiglen=*siglen; /* for platforms where sizeof(int)!=sizeof(size_t)*/ + int ret; + if (!sig) + { + *siglen = 4; + return 1; + } + ret=EVP_DigestFinal_ex(mctx,sig,&tmpsiglen); + *siglen = tmpsiglen; + return ret; + } +/* ----------------------------------------------------------------*/ +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: + 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); + EVP_PKEY_meth_set_derive(*pmeth, + pkey_gost_derive_init, pkey_gost94_derive); + EVP_PKEY_meth_set_paramgen(*pmeth, pkey_gost_paramgen_init,pkey_gost94_paramgen); + break; + 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); + EVP_PKEY_meth_set_derive(*pmeth, + pkey_gost_derive_init, pkey_gost2001_derive); + EVP_PKEY_meth_set_paramgen(*pmeth, pkey_gost_paramgen_init,pkey_gost01_paramgen); + break; + case NID_id_Gost28147_89_MAC: + EVP_PKEY_meth_set_ctrl(*pmeth,pkey_gost_mac_ctrl, pkey_gost_mac_ctrl_str); + EVP_PKEY_meth_set_signctx(*pmeth,pkey_gost_mac_signctx_init, pkey_gost_mac_signctx); + EVP_PKEY_meth_set_keygen(*pmeth,NULL, pkey_gost_mac_keygen); + EVP_PKEY_meth_set_init(*pmeth,pkey_gost_mac_init); + EVP_PKEY_meth_set_cleanup(*pmeth,pkey_gost_mac_cleanup); + EVP_PKEY_meth_set_copy(*pmeth,pkey_gost_mac_copy); + return 1; + 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/openssl/engines/ccgost/gost_sign.c b/openssl/engines/ccgost/gost_sign.c new file mode 100644 index 000000000..409565435 --- /dev/null +++ b/openssl/engines/ccgost/gost_sign.c @@ -0,0 +1,321 @@ +/********************************************************************** + * 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 algorithm * + * 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 "gost_params.h" +#include "gost_lcl.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, size_t *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, size_t *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_GOST94_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/openssl/engines/ccgost/gosthash.c b/openssl/engines/ccgost/gosthash.c new file mode 100644 index 000000000..a5c0662ff --- /dev/null +++ b/openssl/engines/ccgost/gosthash.c @@ -0,0 +1,255 @@ +/********************************************************************** + * 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) + { + 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*/ + if (ctx->left) + { + /*There are some bytes from previous step*/ + unsigned 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; + } + curptr=block+add_bytes; + hash_step(ctx->cipher_ctx,ctx->H,ctx->remainder); + add_blocks(32,ctx->S,ctx->remainder); + ctx->len+=32; + ctx->left=0; + } + while (curptr<=barrier) + { + hash_step(ctx->cipher_ctx,ctx->H,curptr); + + add_blocks(32,ctx->S,curptr); + ctx->len+=32; + curptr+=32; + } + if (curptr!=block+length) + { + ctx->left=block+length-curptr; + 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]; + ghosthash_len 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++)=(byte)(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/openssl/engines/ccgost/gosthash.h b/openssl/engines/ccgost/gosthash.h new file mode 100644 index 000000000..4a2e441ec --- /dev/null +++ b/openssl/engines/ccgost/gosthash.h @@ -0,0 +1,48 @@ +/********************************************************************** + * gosthash.h * + * 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> + +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +typedef __int64 ghosthash_len; +#elif defined(__arch64__) +typedef long ghosthash_len; +#else +typedef long long ghosthash_len; +#endif + +typedef struct gost_hash_ctx { + ghosthash_len 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/openssl/engines/ccgost/gostsum.c b/openssl/engines/ccgost/gostsum.c new file mode 100644 index 000000000..d57112eb5 --- /dev/null +++ b/openssl/engines/ccgost/gostsum.c @@ -0,0 +1,210 @@ +/********************************************************************** + * 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; + } |