/***************************************************************************
*
Copyright 2013 CertiVox UK Ltd. *
*
This file is part of CertiVox MIRACL Crypto SDK. *
*
The CertiVox MIRACL 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 MIRACL 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 MIRACL 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 MIRACL Crypto SDK *
without disclosing the source code of your own applications, or shipping *
the CertiVox MIRACL 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;
}