diff --git a/config.c b/config.c index 35db823..c57d945 100644 --- a/config.c +++ b/config.c @@ -93,9 +93,9 @@ int main() printf("enter the native wordlength of your computer\n\n"); printf("For your information:-\n"); printf("The size of a char is %d bits\n",bitsinchar); - printf("The size of a short is %ld bits\n",bitsinchar*sizeof(short)); - printf("The size of an int is %ld bits\n",bitsinchar*sizeof(int)); - printf("The size of a long is %ld bits\n",bitsinchar*sizeof(long)); + printf("The size of a short is %d bits\n",bitsinchar*sizeof(short)); + printf("The size of an int is %d bits\n",bitsinchar*sizeof(int)); + printf("The size of a long is %d bits\n",bitsinchar*sizeof(long)); eps=1.0; for (dmant=0;;dmant++) @@ -106,7 +106,7 @@ int main() eps/=2.0; } - printf("The size of a double is %ld bits, its mantissa is %d bits\n",bitsinchar*sizeof(double),dmant); + printf("The size of a double is %d bits, its mantissa is %d bits\n",bitsinchar*sizeof(double),dmant); leps=1.0; for (lmant=0;;lmant++) @@ -116,7 +116,7 @@ int main() if (lx==ly) break; leps/=2.0; } - printf("The size of a long double is %ld bits, its mantissa is %d bits\n",bitsinchar*sizeof(long double),lmant); + printf("The size of a long double is %d bits, its mantissa is %d bits\n",bitsinchar*sizeof(long double),lmant); fp=fopen("mirdef.tst","wt"); @@ -147,7 +147,7 @@ int main() no64=0; if (double_type) { - fprintf(fp,"#define MIRACL %ld\n",bitsinchar*sizeof(double)); + fprintf(fp,"#define MIRACL %d\n",bitsinchar*sizeof(double)); fprintf(fp,"#define mr_utype double\n"); fprintf(fp,"#define mr_dltype long double\n"); fprintf(fp,"#define MR_NOFULLWIDTH\n"); @@ -235,8 +235,8 @@ int main() } } - fprintf(fp,"#define MR_IBITS %ld\n",bitsinchar*sizeof(int)); - fprintf(fp,"#define MR_LBITS %ld\n",bitsinchar*sizeof(long)); + fprintf(fp,"#define MR_IBITS %d\n",bitsinchar*sizeof(int)); + fprintf(fp,"#define MR_LBITS %d\n",bitsinchar*sizeof(long)); /* Now try to find 32-bit unsigned types */ @@ -488,6 +488,7 @@ int main() fprintf(fpl,"mrshs256.c\n"); fprintf(fpl,"mraes.c\n"); fprintf(fpl,"mrgcm.c\n"); + fprintf(fpl,"mrfpe.c\n"); fprintf(fpl,"mrstrong.c\n"); fprintf(fpl,"mrcurve.c\n"); fprintf(fpl,"mrbrick.c\n"); @@ -502,8 +503,11 @@ int main() fprintf(fpl,"mrfast.c\n"); fprintf(fpl,"mralloc.c\n"); } - if (chosen64) fprintf(fpl,"mrshs512.c\n"); - + if (chosen64) + { + fprintf(fpl,"mrshs512.c\n"); + fprintf(fpl,"mrsha3.c\n"); + } port=0; if (chosen && double_length_type) { diff --git a/readme.txt b/readme.txt index 203251a..3755e0e 100644 --- a/readme.txt +++ b/readme.txt @@ -15,6 +15,7 @@ The distribution media contains the following files FASTGF2M.TXT - How to speed up methods based on the field GF(2^m) WIN64.TXT - 64-bit Windows advice DEVCPP.TXT - DEV-CPP quick-start instructions + TEXASDSP.TXT - Texas C6713 DSP advice AMD64.TXT - AMD64 processor advice SSE2.TXT - SSE2 extensions advice PIC32.TXT - PIC32 processor advice @@ -242,6 +243,11 @@ In the subdirectory SOURCE P1363.C - P1363 implementation file TEST1363.c - test driver for P1363 implementation RSA.C - quick start RSA application + OCTET.C - OCTET string handler + OCTET.H - OCTET header + ECDH.C - Elliptic Curve Code + ECDH.H - Elliptic Curve Header + TESTECC.C - Typical MIRACL Elliptic Curve API Implementation - thread-safe - no heap In the subdirectory SOURCE\CURVE\PAIRING diff --git a/source/mrcomba.tpl b/source/mrcomba.tpl index 43d4c47..d7e5aec 100644 --- a/source/mrcomba.tpl +++ b/source/mrcomba.tpl @@ -596,7 +596,7 @@ void comba_redc(_MIPD_ big t,big z) } if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) { - if (compare(z,modulus)>=0) + if (mr_compare(z,modulus)>=0) { /*** DECREMENT ***/ } @@ -957,7 +957,7 @@ comba_sub(z,w,z); } if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) { - if (compare(z,modulus)>=0) + if (mr_compare(z,modulus)>=0) { /*** DECREMENT ***/ } diff --git a/source/mrsha3.c b/source/mrsha3.c index ec7755a..b36fa3b 100644 --- a/source/mrsha3.c +++ b/source/mrsha3.c @@ -48,12 +48,12 @@ the CertiVox MIRACL Crypto SDK with a closed source product. * /* round constants */ static const mr_unsign64 RC[24]={ -0x0000000000000001,0x0000000000008082,0x800000000000808A,0x8000000080008000, -0x000000000000808B,0x0000000080000001,0x8000000080008081,0x8000000000008009, -0x000000000000008A,0x0000000000000088,0x0000000080008009,0x000000008000000A, -0x000000008000808B,0x800000000000008B,0x8000000000008089,0x8000000000008003, -0x8000000000008002,0x8000000000000080,0x000000000000800A,0x800000008000000A, -0x8000000080008081,0x8000000000008080,0x0000000080000001,0x8000000080008008}; +0x0000000000000001LL,0x0000000000008082LL,0x800000000000808ALL,0x8000000080008000LL, +0x000000000000808BLL,0x0000000080000001LL,0x8000000080008081LL,0x8000000000008009LL, +0x000000000000008ALL,0x0000000000000088LL,0x0000000080008009LL,0x000000008000000ALL, +0x000000008000808BLL,0x800000000000008BLL,0x8000000000008089LL,0x8000000000008003LL, +0x8000000000008002LL,0x8000000000000080LL,0x000000000000800ALL,0x800000008000000ALL, +0x8000000080008081LL,0x8000000000008080LL,0x0000000080000001LL,0x8000000080008008LL}; /* functions */ diff --git a/source/mrshs512.c b/source/mrshs512.c index b7830a3..b11c511 100644 --- a/source/mrshs512.c +++ b/source/mrshs512.c @@ -48,8 +48,6 @@ the CertiVox MIRACL Crypto SDK with a closed source product. * #ifdef mr_unsign64 - -#ifdef __GNUC__ #define H0 0x6a09e667f3bcc908LL #define H1 0xbb67ae8584caa73bLL #define H2 0x3c6ef372fe94f82bLL @@ -67,28 +65,9 @@ the CertiVox MIRACL Crypto SDK with a closed source product. * #define HD 0x8eb44a8768581511LL #define HE 0xdb0c2e0d64f98fa7LL #define HF 0x47b5481dbefa4fa4LL -#else -#define H0 0x6a09e667f3bcc908 -#define H1 0xbb67ae8584caa73b -#define H2 0x3c6ef372fe94f82b -#define H3 0xa54ff53a5f1d36f1 -#define H4 0x510e527fade682d1 -#define H5 0x9b05688c2b3e6c1f -#define H6 0x1f83d9abfb41bd6b -#define H7 0x5be0cd19137e2179 - -#define H8 0xcbbb9d5dc1059ed8 -#define H9 0x629a292a367cd507 -#define HA 0x9159015a3070dd17 -#define HB 0x152fecd8f70e5939 -#define HC 0x67332667ffc00b31 -#define HD 0x8eb44a8768581511 -#define HE 0xdb0c2e0d64f98fa7 -#define HF 0x47b5481dbefa4fa4 -#endif + /* */ -#ifdef __GNUC__ static const mr_unsign64 K[80]= {0x428a2f98d728ae22LL,0x7137449123ef65cdLL,0xb5c0fbcfec4d3b2fLL,0xe9b5dba58189dbbcLL, 0x3956c25bf348b538LL,0x59f111f1b605d019LL,0x923f82a4af194f9bLL,0xab1c5ed5da6d8118LL, @@ -110,29 +89,6 @@ static const mr_unsign64 K[80]= 0x06f067aa72176fbaLL,0x0a637dc5a2c898a6LL,0x113f9804bef90daeLL,0x1b710b35131c471bLL, 0x28db77f523047d84LL,0x32caab7b40c72493LL,0x3c9ebe0a15c9bebcLL,0x431d67c49c100d4cLL, 0x4cc5d4becb3e42b6LL,0x597f299cfc657e2aLL,0x5fcb6fab3ad6faecLL,0x6c44198c4a475817LL}; -#else -static const mr_unsign64 K[80]= -{0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc, -0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118, -0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2, -0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694, -0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65, -0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5, -0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4, -0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70, -0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df, -0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b, -0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30, -0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8, -0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8, -0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3, -0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec, -0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b, -0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178, -0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b, -0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c, -0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817}; -#endif #define PAD 0x80 #define ZERO 0 diff --git a/source/p1363/ecdh.c b/source/p1363/ecdh.c new file mode 100644 index 0000000..c6c1410 --- /dev/null +++ b/source/p1363/ecdh.c @@ -0,0 +1,1013 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox SkyKey XT Crypto SDK. * + * +The CertiVox SkyKey XT Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox SkyKey XT Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox SkyKey XT Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox SkyKey XT Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox SkyKey XT Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* ECDH/ECIES/ECDSA Functions - see main program below */ + +/* Note that in production code miracl COMBA mechanism should be invoked for 2-3 times speed up */ +/* Use this mirdef.h for 32-bit processor - note no assembly required + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_ALWAYS_BINARY +#define MR_STATIC 8 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_NOSUPPORT_COMPRESSION +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_NOASM +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +*/ + +/* Use this mirdef.h for 64-bit processor + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_ALWAYS_BINARY +#define MR_STATIC 4 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_NOSUPPORT_COMPRESSION +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + +*/ + +/* Link to these files + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrio1.c +mrgcd.c +mrxgcd.c +mrarth3.c +mrbits.c +mrmonty.c +mrcurve.c +mraes.c +mrshs256.c +mrstrong.c + +For 64-bit build using Microsoft compiler mrmuldv.w64 must be included as well +For 64-bit build using Linux and Intel chips, mrmuldv.g64 must be included as well + + +To use COMBA speed-up, for 32-bit build add + +#define MR_COMBA 8 +#define MR_GENERALISED_MERSENNE +#define MR_SPECIAL + +For 64-bit build add + +#define MR_COMBA 4 +#define MR_GENERALISED_MERSENNE +#define MR_SPECIAL + + +to mirdef.h + +Also create mrcomba.c using MEX utility, and add mrcomba.c in build + +*/ + +#include +#include +#include +#include + +#include "ecdh.h" + +/* Elliptic Curve parameters - NIST P256 Curve */ + +#if MIRACL==64 + +const mr_small ecrom[]={ +0xffffffffffffffff,0xffffffff,0x0,0xffffffff00000001, +0x3bce3c3e27d2604b,0x651d06b0cc53b0f6,0xb3ebbd55769886bc,0x5ac635d8aa3a93e7, +0xf3b9cac2fc632551,0xbce6faada7179e84,0xffffffffffffffff,0xffffffff00000000, +0xf4a13945d898c296,0x77037d812deb33a0,0xf8bce6e563a440f2,0x6b17d1f2e12c4247, +0xcbb6406837bf51f5,0x2bce33576b315ece,0x8ee7eb4a7c0f9e16,0x4fe342e2fe1a7f9b}; + +#endif + +#if MIRACL==32 + +const mr_small ecrom[]={ +0xffffffff,0xffffffff,0xffffffff,0x0,0x0,0x0,0x1,0xffffffff, +0x27d2604b,0x3bce3c3e,0xcc53b0f6,0x651d06b0,0x769886bc,0xb3ebbd55,0xaa3a93e7,0x5ac635d8, +0xfc632551,0xf3b9cac2,0xa7179e84,0xbce6faad,0xffffffff,0xffffffff,0x0,0xffffffff, +0xd898c296,0xf4a13945,0x2deb33a0,0x77037d81,0x63a440f2,0xf8bce6e5,0xe12c4247,0x6b17d1f2, +0x37bf51f5,0xcbb64068,0x6b315ece,0x2bce3357,0x7c0f9e16,0x8ee7eb4a,0xfe1a7f9b,0x4fe342e2}; + +#endif + + +static void hash(octet *p,int n,octet *x,octet *y,octet *w) +{ + int i,hlen,c[4]; + HASHFUNC sha; + char hh[HASH_BYTES]; + + hlen=HASH_BYTES; + + SHS_INIT(&sha); + if (p!=NULL) + for (i=0;ilen;i++) SHS_PROCESS(&sha,p->val[i]); + if (n>0) + { + c[0]=(n>>24)&0xff; + c[1]=(n>>16)&0xff; + c[2]=(n>>8)&0xff; + c[3]=(n)&0xff; + for (i=0;i<4;i++) SHS_PROCESS(&sha,c[i]); + } + if (x!=NULL) + for (i=0;ilen;i++) SHS_PROCESS(&sha,x->val[i]); + if (y!=NULL) + for (i=0;ilen;i++) SHS_PROCESS(&sha,y->val[i]); + + + SHS_HASH(&sha,hh); + + OCTET_EMPTY(w); + OCTET_JOIN_BYTES(hh,hlen,w); + for (i=0;ilen,RAW->val,0L); +} + +void KILL_CSPRNG(csprng *RNG) +{ + strong_kill(RNG); +} + +BOOL HMAC(octet *m,octet *k,int olen,octet *tag) +{ +/* Input is from an octet m * + * olen is requested output length in bytes. k is the key * + * The output is the calculated tag */ + int i,hlen,b; + char h[HASH_BYTES],k0[HASH_BLOCK]; + octet H={0,sizeof(h),h}; + octet K0={0,sizeof(k0),k0}; + + hlen=HASH_BYTES; b=HASH_BLOCK; + if (olen<4 || olen>hlen) return FALSE; + + if (k->len > b) hash(k,-1,NULL,NULL,&K0); + else OCTET_COPY(k,&K0); + + OCTET_JOIN_BYTE(0,b-K0.len,&K0); + + OCTET_XOR_BYTE(0x36,&K0); + + hash(&K0,-1,m,NULL,&H); + + OCTET_XOR_BYTE(0x6a,&K0); /* 0x6a = 0x36 ^ 0x5c */ + hash(&K0,-1,&H,NULL,&H); + + OCTET_EMPTY(tag); + OCTET_JOIN_BYTES(H.val,olen,tag); + + return TRUE; +} + +/* Key Derivation Functions */ +/* Input octet z */ +/* Output key of length olen */ + +void KDF1(octet *z,int olen,octet *key) +{ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; + int counter,cthreshold; + int hlen=HASH_BYTES; + + OCTET_EMPTY(key); + + cthreshold=MR_ROUNDUP(olen,hlen); + + for (counter=0;counterlen+hlen>olen) OCTET_JOIN_BYTES(H.val,olen%hlen,key); + else OCTET_JOIN_OCTET(&H,key); + } +} + +void KDF2(octet *z,octet *p,int olen,octet *key) +{ +/* NOTE: the parameter olen is the length of the output k in bytes */ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; + int counter,cthreshold; + int hlen=HASH_BYTES; + + OCTET_EMPTY(key); + + cthreshold=MR_ROUNDUP(olen,hlen); + + for (counter=1;counter<=cthreshold;counter++) + { + hash(z,counter,p,NULL,&H); + if (key->len+hlen>olen) OCTET_JOIN_BYTES(H.val,olen%hlen,key); + else OCTET_JOIN_OCTET(&H,key); + } +} + +/* Password based Key Derivation Function */ +/* Input password p, salt s, and repeat count */ +/* Output key of length olen */ + +void PBKDF2(octet *p,octet *s,int rep,int olen,octet *key) +{ + int i,j,len,d=MR_ROUNDUP(olen,HASH_BYTES); + char f[EFS],u[EFS]; + octet F={0,sizeof(f),f}; + octet U={0,sizeof(u),u}; + OCTET_EMPTY(key); + + for (i=1;i<=d;i++) + { + len=s->len; + OCTET_JOIN_LONG(i,4,s); + HMAC(s,p,EFS,&F); + s->len=len; + OCTET_COPY(&F,&U); + for (j=2;j<=rep;j++) + { + HMAC(&U,p,EFS,&U); + OCTET_XOR(&U,&F); + } + + OCTET_JOIN_OCTET(&F,key); + } + OCTET_CHOP(key,olen,NULL); +} + +/* AES encryption/decryption */ + +void AES_CBC_IV0_ENCRYPT(octet *k,octet *m,octet *c) +{ /* AES CBC encryption, with Null IV and key k */ + /* Input is from an octet string m, output is to an octet string c */ + /* Input is padded as necessary to make up a full final block */ + aes a; + BOOL fin; + int i,j,ipt,opt,ch; + char buff[16]; + int padlen; + + OCTET_CLEAR(c); + if (m->len==0) return; + if (!aes_init(&a,MR_CBC,k->len,k->val,NULL)) return; + + ipt=opt=0; + fin=FALSE; + forever + { + for (i=0;i<16;i++) + { + if (iptlen) buff[i]=m->val[ipt++]; + else {fin=TRUE; break;} + } + if (fin) break; + aes_encrypt(&a,buff); + for (i=0;i<16;i++) + if (optmax) c->val[opt++]=buff[i]; + } + +/* last block, filled up to i-th index */ + + padlen=16-i; + for (j=i;j<16;j++) buff[j]=padlen; + aes_encrypt(&a,buff); + for (i=0;i<16;i++) + if (optmax) c->val[opt++]=buff[i]; + aes_end(&a); + c->len=opt; +} + +/* returns TRUE if all consistent, else returns FALSE */ + +BOOL AES_CBC_IV0_DECRYPT(octet *k,octet *c,octet *m) +{ /* padding is removed */ + aes a; + int i,ipt,opt,ch; + char buff[16]; + BOOL fin,bad; + int padlen; + ipt=opt=0; + + OCTET_CLEAR(m); + if (c->len==0) return TRUE; + ch=c->val[ipt++]; + + if (!aes_init(&a,MR_CBC,k->len,k->val,NULL)) return FALSE; + fin=FALSE; + + forever + { + for (i=0;i<16;i++) + { + buff[i]=ch; + if (ipt>=c->len) {fin=TRUE; break;} + else ch=c->val[ipt++]; + } + aes_decrypt(&a,buff); + if (fin) break; + for (i=0;i<16;i++) + if (optmax) m->val[opt++]=buff[i]; + } + aes_end(&a); + bad=FALSE; + padlen=buff[15]; + if (i!=15 || padlen<1 || padlen>16) bad=TRUE; + if (padlen>=2 && padlen<=16) + for (i=16-padlen;i<16;i++) if (buff[i]!=padlen) bad=TRUE; + + if (!bad) for (i=0;i<16-padlen;i++) + if (optmax) m->val[opt++]=buff[i]; + + m->len=opt; + if (bad) return FALSE; + return TRUE; +} + + +/*** EC GF(p) primitives - support functions ***/ +/* destroy the EC GF(p) domain structure */ + +void ECP_DOMAIN_KILL(ecp_domain *DOM) +{ + int i; + for (i=0;iQ[i]=0; + DOM->A[i]=0; + DOM->B[i]=0; + DOM->Gx[i]=0; + DOM->Gy[i]=0; + } + for (i=0;iR[i]=0; +} + +/* Initialise the EC GF(p) domain structure + * It is assumed that the EC domain details are obtained from ROM + */ + +int ECP_DOMAIN_INIT(ecp_domain *DOM,const void *rom) +{ /* get domain details from ROM */ + + FILE *fp; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,2*EFS,16); +#else + miracl *mr_mip=mirsys(2*EFS,16); +#endif + BOOL fileinput=TRUE; + big q,r,gx,gy,a,b; + int words,promptr,err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 6); +#else + char mem[MR_BIG_RESERVE(6)]; + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + + DOM->nibbles=2*EFS; + words=MR_ROUNDUP(EFS*8,MIRACL); + + if (mr_mip==NULL || mem==NULL) res= ECDH_OUT_OF_MEMORY; + + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + + promptr=0; + init_big_from_rom(q,words,(const mr_small *)rom,words*5,&promptr); /* Read in prime modulus q from ROM */ + init_big_from_rom(b,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter b from ROM */ + init_big_from_rom(r,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter r from ROM */ + init_big_from_rom(gx,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter gx from ROM */ + init_big_from_rom(gy,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter gy from ROM */ + convert(_MIPP_ -3,a); + add(_MIPP_ q,a,a); + + big_to_bytes(_MIPP_ EFS,q,DOM->Q,TRUE); + big_to_bytes(_MIPP_ EFS,a,DOM->A,TRUE); + big_to_bytes(_MIPP_ EFS,b,DOM->B,TRUE); + big_to_bytes(_MIPP_ EGS,r,DOM->R,TRUE); + big_to_bytes(_MIPP_ EFS,gx,DOM->Gx,TRUE); + big_to_bytes(_MIPP_ EFS,gy,DOM->Gy,TRUE); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); +#else + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Calculate a public/private EC GF(p) key pair. W=S.g mod EC(p), + * where S is the secret key and W is the public key + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally */ + +int ECP_KEY_PAIR_GENERATE(ecp_domain *DOM,csprng *RNG,octet* S,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,r,gx,gy,s,wx,wy; + epoint *G,*WP; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 9); + char *mem1=(char *)ecp_memalloc(_MIPP_ 2); +#else + char mem[MR_BIG_RESERVE(9)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(9)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + wx=mirvar_mem(_MIPP_ mem, 7); + wy=mirvar_mem(_MIPP_ mem, 8); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + bytes_to_big(_MIPP_ EFS,DOM->Gx,gx); + bytes_to_big(_MIPP_ EFS,DOM->Gy,gy); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + if (RNG!=NULL) + strong_bigrand(_MIPP_ RNG,r,s); + else + { + bytes_to_big(_MIPP_ S->len,S->val,s); + divide(_MIPP_ s,r,r); + } + + ecurve_mult(_MIPP_ s,G,WP); + epoint_get(_MIPP_ WP,wx,wy); + + if (RNG!=NULL) S->len=big_to_bytes(_MIPP_ 0,s,S->val,FALSE); + + W->len=2*EFS+1; W->val[0]=4; + big_to_bytes(_MIPP_ EFS,wx,&(W->val[1]),TRUE); + big_to_bytes(_MIPP_ EFS,wy,&(W->val[EFS+1]),TRUE); + } + +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(9)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* validate an EC GF(p) public key. Set full=TRUE for fuller, + * but more time-consuming test */ + +int ECP_PUBLIC_KEY_VALIDATE(ecp_domain *DOM,BOOL full,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,r,wx,wy; + epoint *WP; + BOOL valid; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 6); + char *mem1=(char *)ecp_memalloc(_MIPP_ 1); +#else + char mem[MR_BIG_RESERVE(6)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem, 4); + wy=mirvar_mem(_MIPP_ mem, 5); + + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + + bytes_to_big(_MIPP_ EFS,&(W->val[1]),wx); + bytes_to_big(_MIPP_ EFS,&(W->val[EFS+1]),wy); + + if (mr_compare(wx,q)>=0 || mr_compare (wy,q)>=0) res=ECDH_INVALID_PUBLIC_KEY; + } + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + WP=epoint_init_mem(_MIPP_ mem1,0); + + valid=epoint_set(_MIPP_ wx,wy,0,WP); + + if (!valid || WP->marker==MR_EPOINT_INFINITY) res=ECDH_INVALID_PUBLIC_KEY; + if (res==0 && full) + { + ecurve_mult(_MIPP_ r,WP,WP); + if (WP->marker!=MR_EPOINT_INFINITY) res=ECDH_INVALID_PUBLIC_KEY; + } + + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** P1363 EC GF(p) primitives ***/ +/* See P1363 documentation for specification */ + +int ECPSVDP_DH(ecp_domain *DOM,octet *S,octet *WD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,s,wx,wy,z; + BOOL valid; + epoint *W; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 7); + char *mem1=(char *)ecp_memalloc(_MIPP_ 1); +#else + char mem[MR_BIG_RESERVE(7)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem, 4); + wy=mirvar_mem(_MIPP_ mem, 5); + z=mirvar_mem(_MIPP_ mem, 6); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + + bytes_to_big(_MIPP_ S->len,S->val,s); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + W=epoint_init_mem(_MIPP_ mem1,0); + + bytes_to_big(_MIPP_ EFS,&(WD->val[1]),wx); + bytes_to_big(_MIPP_ EFS,&(WD->val[EFS+1]),wy); + + valid=epoint_set(_MIPP_ wx,wy,0,W); + + if (!valid) res=ECDH_ERROR; + } + if (res==0) + { + ecurve_mult(_MIPP_ s,W,W); + if (W->marker==MR_EPOINT_INFINITY) res=ECDH_ERROR; + else + { + epoint_get(_MIPP_ W,z,z); + Z->len=big_to_bytes(_MIPP_ EFS,z,Z->val,TRUE); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Sign octet F using private key S. Signature in C and D. Must supply RNG */ + +int ECPSP_DSA(ecp_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,gx,gy,r,s,f,c,d,u,vx; + epoint *G,*V; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 12); + char *mem1=(char *)ecp_memalloc(_MIPP_ 2); +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + hash(F,-1,NULL,NULL,&H); /* hash message */ + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + u=mirvar_mem(_MIPP_ mem, 10); + vx=mirvar_mem(_MIPP_ mem,11); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + bytes_to_big(_MIPP_ EFS,DOM->Gx,gx); + bytes_to_big(_MIPP_ EFS,DOM->Gy,gy); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ S->len,S->val,s); + bytes_to_big(_MIPP_ H.len,H.val,f); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + V=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + do { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,r,u); + + ecurve_mult(_MIPP_ u,G,V); + epoint_get(_MIPP_ V,vx,vx); + + copy(vx,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) continue; + xgcd(_MIPP_ u,r,u,u,u); + mad(_MIPP_ s,c,f,r,r,d); + mad(_MIPP_ u,d,u,r,r,d); + + } while (size(d)==0); + + if (res==0) + { + C->len=big_to_bytes(_MIPP_ EGS,c,C->val,TRUE); + D->len=big_to_bytes(_MIPP_ EGS,d,D->val,TRUE); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Verify Signature (C, D) on F using public key W */ + +int ECPVP_DSA(ecp_domain *DOM,octet *W,octet *F, octet *C,octet *D) +{ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,r,a,b,gx,gy,wx,wy,f,c,d,h2; + int bit,err,res=0; + epoint *G,*WP,*P; + BOOL compressed,valid; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 12); + char *mem1=(char *)ecp_memalloc(_MIPP_ 3); +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + hash(F,-1,NULL,NULL,&H); /* hash message */ + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + f=mirvar_mem(_MIPP_ mem, 8); + c=mirvar_mem(_MIPP_ mem, 9); + d=mirvar_mem(_MIPP_ mem, 10); + h2=mirvar_mem(_MIPP_ mem,11); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + bytes_to_big(_MIPP_ EFS,DOM->Gx,gx); + bytes_to_big(_MIPP_ EFS,DOM->Gy,gy); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ C->len,C->val,c); + bytes_to_big(_MIPP_ D->len,D->val,d); + bytes_to_big(_MIPP_ H.len,H.val,f); + + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<1 || mr_compare(d,r)>=0) + res=ECDH_INVALID; + } + + if (res==0) + { + xgcd(_MIPP_ d,r,d,d,d); + mad(_MIPP_ f,d,f,r,r,f); + mad(_MIPP_ c,d,c,r,r,h2); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint_set(_MIPP_ gx,gy,0,G); + + bytes_to_big(_MIPP_ EFS,&(W->val[1]),wx); + bytes_to_big(_MIPP_ EFS,&(W->val[EFS+1]),wy); + + valid=epoint_set(_MIPP_ wx,wy,0,WP); + + if (!valid) res=ECDH_ERROR; + else + { + ecurve_mult2(_MIPP_ f,G,h2,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=ECDH_INVALID; + else + { + epoint_get(_MIPP_ P,d,d); + divide(_MIPP_ d,r,r); + if (mr_compare(d,c)!=0) res=ECDH_INVALID; + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + + +void ECP_ECIES_ENCRYPT(ecp_domain *DOM,octet *P1,octet *P2,csprng *RNG,octet *W,octet *M,int tlen,octet *V,octet *C,octet *T) +{ /* Inputs: Input params, random number generator, his public key, the message to be encrypted and the MAC length */ + /* Outputs: my one-time public key, the ciphertext and the MAC tag */ + + int i,len; + char z[EFS],vz[3*EFS+2],k[32],k1[16],k2[16],l2[8],u[EFS]; + octet Z={0,sizeof(z),z}; + octet VZ={0,sizeof(vz),vz}; + octet K={0,sizeof(k),k}; + octet K1={0,sizeof(k1),k1}; + octet K2={0,sizeof(k2),k2}; + octet L2={0,sizeof(l2),l2}; + octet U={0,sizeof(u),u}; + + if (ECP_KEY_PAIR_GENERATE(DOM,RNG,&U,V)!=0) return; /* one time key pair */ + if (ECPSVDP_DH(DOM,&U,W,&Z)!=0) return; + + OCTET_COPY(V,&VZ); + OCTET_JOIN_OCTET(&Z,&VZ); + + KDF2(&VZ,P1,EFS,&K); + +/* split key into AES encryption key and MAC key */ + + K1.len=K2.len=16; + for (i=0;i<16;i++) {K1.val[i]=K.val[i]; K2.val[i]=K.val[16+i];} + + AES_CBC_IV0_ENCRYPT(&K1,M,C); + + OCTET_JOIN_LONG((long)P2->len,8,&L2); + + len=C->len; + OCTET_JOIN_OCTET(P2,C); + OCTET_JOIN_OCTET(&L2,C); + HMAC(C,&K2,tlen,T); + C->len=len; +} + +/* ECIES Decryption */ + +BOOL ECP_ECIES_DECRYPT(ecp_domain *DOM,octet *P1,octet *P2,octet *V,octet *C,octet *T,octet *U,octet *M) +{ /* Inputs: Input params, ciphertext triple V,C,T and recipients private key */ + /* Output: recovered plaintext M */ + + int i,len; + char z[EFS],vz[3*EFS+2],k[32],k1[16],k2[16],l2[8],tag[32]; + octet Z={0,sizeof(z),z}; + octet VZ={0,sizeof(vz),vz}; + octet K={0,sizeof(k),k}; + octet K1={0,sizeof(k1),k1}; + octet K2={0,sizeof(k2),k2}; + octet L2={0,sizeof(l2),l2}; + octet TAG={0,sizeof(tag),tag}; + + if (ECPSVDP_DH(DOM,U,V,&Z)!=0) return FALSE; + + OCTET_COPY(V,&VZ); + OCTET_JOIN_OCTET(&Z,&VZ); + + KDF2(&VZ,P1,EFS,&K); + +/* split key into AES decryption key and MAC key */ + + K1.len=K2.len=16; + for (i=0;i<16;i++) {K1.val[i]=K.val[i]; K2.val[i]=K.val[16+i];} + + if (!AES_CBC_IV0_DECRYPT(&K1,C,M)) return FALSE; + + OCTET_JOIN_LONG((long)P2->len,8,&L2); + + len=C->len; + OCTET_JOIN_OCTET(P2,C); + OCTET_JOIN_OCTET(&L2,C); + HMAC(C,&K2,T->len,&TAG); + C->len=len; + + if (!OCTET_COMPARE(T,&TAG)) return FALSE; + + return TRUE; + +} + diff --git a/source/p1363/ecdh.h b/source/p1363/ecdh.h new file mode 100644 index 0000000..96b8041 --- /dev/null +++ b/source/p1363/ecdh.h @@ -0,0 +1,141 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox SkyKey XT Crypto SDK. * + * +The CertiVox SkyKey XT Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox SkyKey XT Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox SkyKey XT Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox SkyKey XT Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox SkyKey XT Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* + * MIRACL ECDH header file + * Author: M. Scott 2013 + */ + +#ifndef ECDH_H +#define ECDH_H + +#include "miracl.h" +#include "octet.h" + +#define EAS 16 /* Symmetric Key size - 128 bits */ +#define EGS 32 /* ECCSI Group Size - 256 bits */ +#define EFS 32 /* ECCSI Field Size - 256 bits */ + +#define ECDH_OK 0 +#define ECDH_DOMAIN_ERROR -1 +#define ECDH_INVALID_PUBLIC_KEY -2 +#define ECDH_ERROR -3 +#define ECDH_INVALID -4 +#define ECDH_DOMAIN_NOT_FOUND -5 +#define ECDH_OUT_OF_MEMORY -6 +#define ECDH_DIV_BY_ZERO -7 +#define ECDH_BAD_ASSUMPTION -8 + +extern const mr_small ecrom[]; + +/* ECp domain parameters */ + +typedef struct +{ + int nibbles; + char Q[EFS]; + char A[EFS]; + char B[EFS]; + char R[EGS]; + char Gx[EFS]; + char Gy[EFS]; +} ecp_domain; + +#define HASH_BYTES 32 + +#if HASH_BYTES==20 + #define HASHFUNC sha + #define SHS_INIT shs_init + #define SHS_PROCESS shs_process + #define SHS_HASH shs_hash + #define HASH_BLOCK 64 +#endif + +#if HASH_BYTES==32 + #define HASHFUNC sha256 + #define SHS_INIT shs256_init + #define SHS_PROCESS shs256_process + #define SHS_HASH shs256_hash + #define HASH_BLOCK 64 +#endif + +#if HASH_BYTES==48 + #define HASHFUNC sha384 + #define SHS_INIT shs384_init + #define SHS_PROCESS shs384_process + #define SHS_HASH shs384_hash + #define HASH_BLOCK 128 +#endif + +#if HASH_BYTES==64 + #define HASHFUNC sha512 + #define SHS_INIT shs512_init + #define SHS_PROCESS shs512_process + #define SHS_HASH shs512_hash + #define HASH_BLOCK 128 +#endif + +/* ECDH Auxiliary Functions */ + +extern void CREATE_CSPRNG(csprng *,octet *); +extern void KILL_CSPRNG(csprng *); +extern void HASH(octet *,octet *); +extern BOOL HMAC(octet *,octet *,int,octet *); +extern void KDF1(octet *,int,octet *); +extern void KDF2(octet *,octet *,int,octet *); +extern void PBKDF2(octet *,octet *,int,int,octet *); +extern void AES_CBC_IV0_ENCRYPT(octet *,octet *,octet *); +extern BOOL AES_CBC_IV0_DECRYPT(octet *,octet *,octet *); + +/* ECDH primitives - support functions */ + +extern void ECP_DOMAIN_KILL(ecp_domain *); +extern int ECP_DOMAIN_INIT(ecp_domain *,const void *); +extern int ECP_KEY_PAIR_GENERATE(ecp_domain *,csprng *,octet *,octet *); +extern int ECP_PUBLIC_KEY_VALIDATE(ecp_domain *,BOOL,octet *); + +/* ECDH primitives */ + +extern int ECPSVDP_DH(ecp_domain *,octet *,octet *,octet *); +extern int ECPSVDP_DHC(ecp_domain *,octet *,octet *,BOOL,octet *); + +/* ECIES functions */ +extern void ECP_ECIES_ENCRYPT(ecp_domain *,octet *,octet *,csprng *,octet *,octet *,int,octet *,octet *,octet *); +extern BOOL ECP_ECIES_DECRYPT(ecp_domain *,octet *,octet *,octet *,octet *,octet *,octet *,octet *); + +/* ECDSA functions */ +extern int ECPSP_DSA(ecp_domain *,csprng *,octet *,octet *,octet *,octet *); +extern int ECPVP_DSA(ecp_domain *,octet *,octet *,octet *,octet *); +#endif + diff --git a/source/p1363/octet.c b/source/p1363/octet.c new file mode 100644 index 0000000..3b99fa7 --- /dev/null +++ b/source/p1363/octet.c @@ -0,0 +1,313 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox Crypto SDK. * + * +The CertiVox Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox Crypto SDK with a closed source product. * + * +***************************************************************************/ + + +/*** Basic Octet string maintainance routines ***/ + +#include "octet.h" + +/* Output an octet string (Debug Only) */ + +void OCTET_OUTPUT(octet *w) +{ + int i; + unsigned char ch; + for (i=0;ilen;i++) + { + ch=w->val[i]; + printf("%02x",ch); + } + printf("\n"); +} + +void OCTET_OUTPUT_STRING(octet *w) +{ + int i; + unsigned char ch; + for (i=0;ilen;i++) + { + ch=w->val[i]; + printf("%c",ch); + } + /* printf("\n"); */ +} + +/* Convert C string to octet format - truncates if no room */ + +void OCTET_JOIN_STRING(char *s,octet *y) +{ + int i,j; + i=y->len; + j=0; + while (s[j]!=0 && imax) + { + y->val[i]=s[j]; + y->len++; + i++; j++; + } +} + +/* compare 2 octet strings. + * If x==y return TRUE, else return FALSE */ + +int OCTET_COMPARE(octet *x,octet *y) +{ + int i; + if (x->len>y->len) return 0; + if (x->lenlen) return 0; + for (i=0;ilen;i++) + { + if (x->val[i]!=y->val[i]) return 0; + } + return 1; +} + +/* Append binary string to octet - truncates if no room */ + +void OCTET_JOIN_BYTES(char *b,int len,octet *y) +{ + int i,j; + i=y->len; + for (j=0;jmax;j++) + { + y->val[i]=b[j]; + y->len++; + i++; + } +} + +/* Concatenates two octet strings */ + +void OCTET_JOIN_OCTET(octet *x,octet *y) +{ /* y=y || x */ + int i,j; + if (x==NULL) return; + + for (i=0;ilen;i++) + { + j=y->len+i; + if (j>=y->max) + { + y->len=y->max; + return; + } + y->val[j]=x->val[i]; + } + y->len+=x->len; +} + +/* Append byte to octet rep times */ + +void OCTET_JOIN_BYTE(int ch,int rep,octet *y) +{ + int i,j; + i=y->len; + for (j=0;jmax;j++) + { + y->val[i]=ch; + y->len++; + i++; + } +} + +/* XOR common bytes of x with y */ + +void OCTET_XOR(octet *x,octet *y) +{ /* xor first x->len bytes of y */ + + int i; + for (i=0;ilen && ilen;i++) + { + y->val[i]^=x->val[i]; + } +} + +/* clear an octet */ + +void OCTET_EMPTY(octet *w) +{ + w->len=0; +} + +/* Kill an octet string - Zeroise it for security */ + +void OCTET_CLEAR(octet *w) +{ + int i; + for (i=0;imax;i++) w->val[i]=0; + w->len=0; +} + +/* OCTET_JOIN_LONG primitive */ +/* appends long x of length len bytes to OCTET string */ + +void OCTET_JOIN_LONG(long x,int len,octet *y) +{ + int i,j,n; + n=y->len+len; + if (n>y->max || len<=0) return; + for (i=y->len;ival[i]=0; + y->len=n; + + i=y->len; + while (x>0 && i>0) + { + i--; + y->val[i]=x%256; + x/=256; + } +} + +/* Pad an octet to a given length */ + +void OCTET_PAD(int n,octet *w) +{ + int i,d; + if (w->len>=n || n>w->max) return; + d=n-w->len; + for (i=n-1;i>=d;i--) + w->val[i]=w->val[i-d]; + for (i=d-1;i>=0;i--) + w->val[i]=0; + w->len=n; +} + +/* Convert an octet string to base64 string */ + +void OCTET_TO_BASE64(octet *w,char *b) +{ + int i,j,k,rem,last; + int c,ch[4]; + unsigned char ptr[3]; + rem=w->len%3; j=k=0; last=4; + while (jlen) + { + for (i=0;i<3;i++) + { + if (jlen) ptr[i]=w->val[j++]; + else {ptr[i]=0; last--;} + } + ch[0]=(ptr[0]>>2)&0x3f; + ch[1]=((ptr[0]<<4)|(ptr[1]>>4))&0x3f; + ch[2]=((ptr[1]<<2)|(ptr[2]>>6))&0x3f; + ch[3]=ptr[2]&0x3f; + for (i=0;i=26 && c<52) c+=71; + if (c>=52 && c<62) c-=4; + if (c==62) c='+'; + if (c==63) c='/'; + b[k++]=c; + } + } + if (rem>0) for (i=rem;i<3;i++) b[k++]='='; + b[k]='\0'; // dangerous! +} + +void OCTET_FROM_BASE64(char *b,octet *w) +{ + int i,j,k,pads,len=strlen(b); + int c,ch[4],ptr[3]; + int lead=1; + j=k=0; + while (jmax) + { + pads=0; + for (i=0;i<4;i++) + { + c=80+b[j++]; + if (c<=112) continue; /* ignore white space */ + if (c>144 && c<171) c-=145; + if (c>176 && c<203) c-=151; + if (c>127 && c<138) c-=76; + if (c==123) c=62; + if (c==127) c=63; + if (c==141) {pads++; continue;} /* ignore pads '=' */ + ch[i]=c; + } + ptr[0]=(ch[0]<<2)|(ch[1]>>4); + ptr[1]=(ch[1]<<4)|(ch[2]>>2); + ptr[2]=(ch[2]<<6)|ch[3]; + for (i=0;i<3-pads && kmax;i++) + { /* don't put in leading zeros */ + /* if (lead && ptr[i]==0) continue; */ + w->val[k++]=ptr[i]; + lead=0; + } + + } + w->len=k; +} + +/* copy an octet string - truncates if no room */ + +void OCTET_COPY(octet *x,octet *y) +{ + int i; + OCTET_CLEAR(y); + y->len=x->len; + if (y->len>y->max) y->len=y->max; + + for (i=0;ilen;i++) + y->val[i]=x->val[i]; +} + +/* XOR m with all of x */ + +void OCTET_XOR_BYTE(int m,octet *x) +{ + int i; + for (i=0;ilen;i++) x->val[i]^=m; +} + +/* truncates x to n bytes and places the rest in y (if y is not NULL) */ + +void OCTET_CHOP(octet *x,int n,octet *y) +{ + int i; + if (n>=x->len) + { + if (y!=NULL) y->len=0; + return; + } + if (y!=NULL) y->len=x->len-n; + x->len=n; + + if (y!=NULL) + { + for (i=0;ilen && imax;i++) y->val[i]=x->val[i+n]; + } +} diff --git a/source/p1363/octet.h b/source/p1363/octet.h new file mode 100644 index 0000000..f950f98 --- /dev/null +++ b/source/p1363/octet.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox Crypto SDK. * + * +The CertiVox Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox Crypto SDK with a closed source product. * + * +***************************************************************************/ + + +#ifndef OCTET_H +#define OCTET_H + +#include +#include +#include + +/* portable representation of a big positive number */ + +typedef struct +{ + int len; + int max; + char *val; +} octet; + +/* Octet string handlers */ + +extern void OCTET_OUTPUT(octet *); +extern void OCTET_OUTPUT_STRING(octet *); +extern void OCTET_CLEAR(octet *); +extern int OCTET_COMPARE(octet *,octet *); +extern void OCTET_JOIN_STRING(char *,octet *); +extern void OCTET_JOIN_BYTES(char *,int,octet *); +extern void OCTET_JOIN_BYTE(int,int,octet *); +extern void OCTET_JOIN_OCTET(octet *,octet *); +extern void OCTET_XOR(octet *,octet *); +extern void OCTET_EMPTY(octet *); +extern void OCTET_PAD(int,octet *); +extern void OCTET_TO_BASE64(octet *,char *); +extern void OCTET_FROM_BASE64(char *,octet *); +extern void OCTET_COPY(octet *,octet *); +extern void OCTET_XOR_BYTE(int,octet *); +extern void OCTET_CHOP(octet *,int,octet *); +extern void OCTET_JOIN_LONG(long,int,octet *); + +#endif diff --git a/source/p1363/testecc.c b/source/p1363/testecc.c new file mode 100644 index 0000000..2953659 --- /dev/null +++ b/source/p1363/testecc.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox Crypto SDK. * + * +The CertiVox Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* This file implements a typical thread-safe API for MIRACL */ +/* Static build - requires no heap */ +/* See comments in ecdh.c for more details on the build */ +/* Derived from p1363.c code */ + +/* test driver and function exerciser for ECDH/ECIES/ECDSA Functions */ +/* cl /O2 testecc.c ecdh.c octet.c miracl.lib */ + +#include +#include +#include +#include +#include "ecdh.h" + +int main(int argc,char **argv) +{ + int i,res; + BOOL result; + char *pp="M0ng00se"; +/* These octets are automatically protected against buffer overflow attacks */ +/* Note salt must be big enough to include an appended word */ +/* Note ECIES ciphertext C must be big enough to include at least 1 appended block */ +/* Recall EFS is field size in bytes. So EFS=32 for 256-bit curve */ + char s0[EGS],s1[EGS],w0[2*EFS+1],w1[2*EFS+1],z0[EFS],z1[EFS],raw[100],key[EAS],salt[32],pw[20],b64[4+((8*EFS+4)/3)],p1[30],p2[30],v[2*EFS+1],m[32],c[64],t[32],cs[EGS],ds[EGS]; + octet S0={0,sizeof(s0),s0}; + octet S1={0,sizeof(s1),s1}; + octet W0={0,sizeof(w0),w0}; + octet W1={0,sizeof(w1),w1}; + octet Z0={0,sizeof(z0),z0}; + octet Z1={0,sizeof(z1),z1}; + octet RAW={0,sizeof(raw),raw}; + octet KEY={0,sizeof(key),key}; + octet SALT={0,sizeof(salt),salt}; + octet PW={0,sizeof(pw),pw}; + octet P1={0,sizeof(p1),p1}; + octet P2={0,sizeof(p2),p2}; + octet V={0,sizeof(v),v}; + octet M={0,sizeof(m),m}; + octet C={0,sizeof(c),c}; + octet T={0,sizeof(t),t}; + octet CS={0,sizeof(cs),cs}; + octet DS={0,sizeof(ds),ds}; + + ecp_domain epdom; + csprng RNG; /* Crypto Strong RNG */ + + RAW.len=100; /* fake random seed source */ + for (i=0;i<100;i++) RAW.val[i]=i+1; + + CREATE_CSPRNG(&RNG,&RAW); /* initialise strong RNG */ + + SALT.len=8; + for (i=0;i<8;i++) SALT.val[i]=i+1; // set Salt + + printf("Alice's Passphrase= %s\n",pp); + + OCTET_JOIN_STRING(pp,&PW); // set Password from string + +/* First set up Elliptic Curve from ROM data */ + + ECP_DOMAIN_INIT(&epdom,ecrom); + +/* private key S0 of size EGS bytes derived from Password and Salt */ + + PBKDF2(&PW,&SALT,1000,EGS,&S0); + OCTET_TO_BASE64(&S0,b64); + printf("Alices private key= %s\n",b64); + +/* Generate Key pair S/W */ + + ECP_KEY_PAIR_GENERATE(&epdom,NULL,&S0,&W0); + res=ECP_PUBLIC_KEY_VALIDATE(&epdom,TRUE,&W0); + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + OCTET_TO_BASE64(&W0,b64); + printf("Alice's public key= %s\n",b64); + OCTET_FROM_BASE64(b64,&W0); + +/* Random private key for other party */ + + S1.len=3; S1.val[0]=0x01; S1.val[1]=0x23; S1.val[2]=0x45; + + ECP_KEY_PAIR_GENERATE(&epdom,NULL,&S1,&W1); + res=ECP_PUBLIC_KEY_VALIDATE(&epdom,TRUE,&W1); + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + OCTET_TO_BASE64(&W1,b64); + printf("Servers public key= %s\n",b64); + OCTET_FROM_BASE64(b64,&W1); + +/* Calculate common key using DH - IEEE 1363 method */ + + ECPSVDP_DH(&epdom,&S0,&W1,&Z0); + ECPSVDP_DH(&epdom,&S1,&W0,&Z1); + + if (!OCTET_COMPARE(&Z0,&Z1)) + { + printf("*** ECPSVDP-DH Failed\n"); + return 0; + } + + KDF1(&Z0,EAS,&KEY); + printf("Alice's DH Key= "); for (i=0;i