702 lines
18 KiB
C++
702 lines
18 KiB
C++
/*
|
|
* Copyright (c) 2012-2020 MIRACL UK Ltd.
|
|
*
|
|
* This file is part of MIRACL Core
|
|
* (see https://github.com/miracl/core).
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
HMAC functions
|
|
*/
|
|
|
|
#include "arch.h"
|
|
#include "core.h"
|
|
|
|
using namespace core;
|
|
|
|
#define ROUNDUP(a,b) ((a)-1)/(b)+1
|
|
#define CEIL(a,b) (((a)-1)/(b)+1)
|
|
|
|
/* General Purpose hash function, padding with zeros, optional input octets p and x, optional integer n,hash to octet w of length olen */
|
|
/* hash is the Hash family, either MC_SHA2 or MC_SHA3 */
|
|
/* hlen should be 32,48 or 64 for MC_SHA2 (that is SHA256/384/512) */
|
|
/* hlen should be 24,32,48,64 for MC_SHA3 */
|
|
/* olen=0 - output = hlen bytes */
|
|
/* olen<=hlen - output = olen bytes */
|
|
/* olen>hlen - output is padded with leading zeros and then hlen bytes */
|
|
|
|
void core::GPhash(int hash,int hlen,octet *w,int olen,int pad,octet *p,int n,octet *x)
|
|
{
|
|
hash256 sh256;
|
|
hash384 sh384;
|
|
hash512 sh512;
|
|
sha3 sh3;
|
|
int i,c[4];
|
|
char hh[64];
|
|
|
|
if (n>=0)
|
|
{
|
|
c[0] = (n >> 24) & 0xff;
|
|
c[1] = (n >> 16) & 0xff;
|
|
c[2] = (n >> 8) & 0xff;
|
|
c[3] = (n) & 0xff;
|
|
}
|
|
|
|
switch (hash)
|
|
{
|
|
case MC_SHA2 :
|
|
switch (hlen)
|
|
{
|
|
case SHA256 :
|
|
HASH256_init(&sh256);
|
|
for (i=0;i<pad;i++) HASH256_process(&sh256,0);
|
|
if (p!=NULL)
|
|
for (i=0;i<p->len;i++) HASH256_process(&sh256,p->val[i]);
|
|
if (n>=0)
|
|
for (i=0;i<4;i++) HASH256_process(&sh256,c[i]);
|
|
if (x!=NULL)
|
|
for (i=0;i<x->len;i++) HASH256_process(&sh256,x->val[i]);
|
|
HASH256_hash(&sh256,hh);
|
|
break;
|
|
case SHA384 :
|
|
HASH384_init(&sh384);
|
|
for (i=0;i<pad;i++) HASH384_process(&sh384,0);
|
|
if (p!=NULL)
|
|
for (i=0;i<p->len;i++) HASH384_process(&sh384,p->val[i]);
|
|
if (n>=0)
|
|
for (i=0;i<4;i++) HASH384_process(&sh384,c[i]);
|
|
if (x!=NULL)
|
|
for (i=0;i<x->len;i++) HASH384_process(&sh384,x->val[i]);
|
|
HASH384_hash(&sh384,hh);
|
|
break;
|
|
case SHA512 :
|
|
HASH512_init(&sh512);
|
|
for (i=0;i<pad;i++) HASH512_process(&sh512,0);
|
|
if (p!=NULL)
|
|
for (i=0;i<p->len;i++) HASH512_process(&sh512,p->val[i]);
|
|
if (n>=0)
|
|
for (i=0;i<4;i++) HASH512_process(&sh512,c[i]);
|
|
if (x!=NULL)
|
|
for (i=0;i<x->len;i++) HASH512_process(&sh512,x->val[i]);
|
|
HASH512_hash(&sh512,hh);
|
|
break;
|
|
}
|
|
break;
|
|
case MC_SHA3 :
|
|
SHA3_init(&sh3,hlen);
|
|
for (i=0;i<pad;i++) SHA3_process(&sh3,0);
|
|
if (p!=NULL)
|
|
for (i=0;p->len;i++) SHA3_process(&sh3,p->val[i]);
|
|
if (n>=0)
|
|
for (i=0;i<4;i++) SHA3_process(&sh3,c[i]);
|
|
if (x!=NULL)
|
|
for (i=0;x->len;i++) SHA3_process(&sh3,x->val[i]);
|
|
SHA3_hash(&sh3,hh);
|
|
break;
|
|
default: return;
|
|
}
|
|
OCT_empty(w);
|
|
if (!olen)
|
|
OCT_jbytes(w,hh,hlen);
|
|
else
|
|
{
|
|
if (olen<=hlen)
|
|
{
|
|
OCT_jbytes(w,hh,olen);
|
|
} else {
|
|
OCT_jbyte(w, 0, olen - hlen);
|
|
OCT_jbytes(w, hh, hlen);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Simple hash octet p to octet w of length hlen */
|
|
void core::SPhash(int hash, int hlen,octet *w, octet *p)
|
|
{
|
|
GPhash(hash, hlen, w, 0, 0, p, -1, NULL);
|
|
}
|
|
|
|
static int blksize(int hash,int hlen)
|
|
{
|
|
int blk=0;
|
|
switch (hash)
|
|
{
|
|
case MC_SHA2 :
|
|
blk=64;
|
|
if (hlen>32) blk=128;
|
|
break;
|
|
case MC_SHA3 :
|
|
blk=200-2*hlen;
|
|
break;
|
|
default: break;
|
|
}
|
|
return blk;
|
|
}
|
|
|
|
|
|
/* RFC 2104 */
|
|
void core::HMAC(int hash,int hlen,octet *TAG,int olen,octet *K,octet *M)
|
|
{
|
|
int blk;
|
|
char h[128],k0[200]; // assumes max block sizes
|
|
octet K0 = {0, sizeof(k0), k0};
|
|
octet H={0,sizeof(h),h};
|
|
|
|
blk=blksize(hash,hlen);
|
|
if (blk==0) return;
|
|
|
|
if (K->len > blk) SPhash(hash,hlen,&K0,K);
|
|
else OCT_copy(&K0,K);
|
|
|
|
OCT_jbyte(&K0,0,blk-K0.len);
|
|
|
|
OCT_xorbyte(&K0,0x36);
|
|
|
|
|
|
GPhash(hash,hlen,&H,0,0,&K0,-1,M);
|
|
|
|
OCT_xorbyte(&K0,0x6a); /* 0x6a = 0x36 ^ 0x5c */
|
|
GPhash(hash,hlen,&H,0,0,&K0,-1,&H);
|
|
|
|
OCT_empty(TAG);
|
|
OCT_jbytes(TAG,H.val,olen);
|
|
|
|
OCT_clear(&H);
|
|
OCT_clear(&K0);
|
|
}
|
|
|
|
/* RFC 5869 */
|
|
|
|
void core::HKDF_Extract(int hash,int hlen,octet *PRK,octet *SALT,octet *IKM)
|
|
{
|
|
char h[64];
|
|
octet H={0,sizeof(h),h};
|
|
if (SALT==NULL) {
|
|
OCT_jbyte(&H,0,hlen);
|
|
HMAC(hash,hlen,PRK,hlen,&H,IKM);
|
|
} else {
|
|
HMAC(hash,hlen,PRK,hlen,SALT,IKM);
|
|
}
|
|
}
|
|
|
|
void core::HKDF_Expand(int hash,int hlen,octet *OKM,int olen,octet *PRK,octet *INFO)
|
|
{
|
|
int i;
|
|
char t[1024]; // >= info.length+hlen+1
|
|
octet T={0,sizeof(t),t};
|
|
int n=olen/hlen;
|
|
int flen=olen%hlen;
|
|
OCT_empty(OKM);
|
|
|
|
for (i=1;i<=n;i++)
|
|
{
|
|
OCT_joctet(&T,INFO);
|
|
OCT_jbyte(&T,i,1);
|
|
HMAC(hash,hlen,&T,hlen,PRK,&T);
|
|
OCT_joctet(OKM,&T);
|
|
}
|
|
if (flen>0)
|
|
{
|
|
OCT_joctet(&T,INFO);
|
|
OCT_jbyte(&T,n+1,1);
|
|
HMAC(hash,hlen,&T,flen,PRK,&T);
|
|
OCT_joctet(OKM,&T);
|
|
}
|
|
}
|
|
|
|
/* https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/ */
|
|
|
|
void core::XOF_Expand(int hlen,octet *OKM,int olen,octet *DST,octet *M)
|
|
{
|
|
int i;
|
|
sha3 SHA3;
|
|
SHA3_init(&SHA3,hlen);
|
|
for (i=0;i<M->len;i++) SHA3_process(&SHA3,M->val[i]);
|
|
SHA3_process(&SHA3,olen/256);
|
|
SHA3_process(&SHA3,olen%256);
|
|
|
|
for (i=0;i<DST->len;i++)
|
|
SHA3_process(&SHA3,DST->val[i]);
|
|
SHA3_process(&SHA3,DST->len);
|
|
|
|
SHA3_shake(&SHA3,OKM->val,olen);
|
|
OKM->len=olen;
|
|
}
|
|
|
|
static void XMD_Expand_Short_DST(int hash, int hlen,octet *OKM,int olen,octet *DST,octet *M)
|
|
{
|
|
int i,blk;
|
|
int ell=CEIL(olen,hlen);
|
|
char tmp[260];
|
|
octet TMP={0,sizeof(tmp),tmp};
|
|
char h0[64];
|
|
octet H0 = {0, sizeof(h0), h0};
|
|
char h1[64];
|
|
octet H1 = {0, sizeof(h1), h1};
|
|
|
|
blk=blksize(hash,hlen);
|
|
OCT_jint(&TMP,olen,2);
|
|
OCT_jint(&TMP,0,1);
|
|
OCT_joctet(&TMP,DST);
|
|
OCT_jint(&TMP,DST->len,1);
|
|
|
|
GPhash(hash,hlen,&H0,0,blk,M,-1,&TMP);
|
|
OCT_empty(&TMP);
|
|
OCT_jint(&TMP,1,1);
|
|
OCT_joctet(&TMP,DST);
|
|
OCT_jint(&TMP,DST->len,1);
|
|
|
|
GPhash(hash,hlen,&H1,0,0,&H0,-1,&TMP);
|
|
OCT_empty(OKM);
|
|
OCT_joctet(OKM,&H1);
|
|
for (i=2;i<=ell;i++)
|
|
{
|
|
OCT_xor(&H1,&H0);
|
|
OCT_empty(&TMP);
|
|
OCT_jint(&TMP,i,1);
|
|
OCT_joctet(&TMP,DST);
|
|
OCT_jint(&TMP,DST->len,1);
|
|
GPhash(hash,hlen,&H1,0,0,&H1,-1,&TMP);
|
|
OCT_joctet(OKM,&H1);
|
|
}
|
|
OKM->len=olen;
|
|
}
|
|
|
|
void core::XMD_Expand(int hash, int hlen,octet *OKM,int olen,octet *DST,octet *M)
|
|
{
|
|
char w[64];
|
|
octet W = {0, sizeof(w), w};
|
|
char os[20];
|
|
octet OS={0,sizeof(os),os};
|
|
OCT_jstring(&OS,(char *)"H2C-OVERSIZE-DST-");
|
|
if (DST->len>=256)
|
|
{
|
|
GPhash(hash,hlen,&W,0,0,&OS,-1,DST);
|
|
XMD_Expand_Short_DST(hash,hlen,OKM,olen,&W,M);
|
|
} else {
|
|
XMD_Expand_Short_DST(hash,hlen,OKM,olen,DST,M);
|
|
}
|
|
}
|
|
|
|
/* Key Derivation Function */
|
|
|
|
void core::KDF2(int hash, int hlen, octet *key, int olen, octet *z, octet *p)
|
|
{
|
|
/* NOTE: the parameter olen is the length of the output k in bytes */
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
int counter, cthreshold;
|
|
|
|
OCT_empty(key);
|
|
|
|
cthreshold = ROUNDUP(olen, hlen);
|
|
|
|
for (counter = 1; counter <= cthreshold; counter++)
|
|
{
|
|
GPhash(hash,hlen, &H, 0, 0, z, counter, p);
|
|
if (key->len + hlen > olen) OCT_jbytes(key, H.val, olen % hlen);
|
|
else OCT_joctet(key, &H);
|
|
}
|
|
|
|
}
|
|
|
|
/* Password based Key Derivation Function */
|
|
/* Input password p, salt s, and repeat count */
|
|
/* Output key of length olen */
|
|
void core::PBKDF2(int hash, int hlen, octet *key, int olen, octet *p, octet *s, int rep)
|
|
{
|
|
int i, j, len, d = ROUNDUP(olen, hlen);
|
|
char f[64], u[64];
|
|
octet F = {0, sizeof(f), f};
|
|
octet U = {0, sizeof(u), u};
|
|
OCT_empty(key);
|
|
|
|
for (i = 1; i <= d; i++)
|
|
{
|
|
len = s->len;
|
|
OCT_jint(s, i, 4);
|
|
|
|
HMAC(hash, hlen, &F, hlen, s, p);
|
|
|
|
s->len = len;
|
|
OCT_copy(&U, &F);
|
|
for (j = 2; j <= rep; j++)
|
|
{
|
|
HMAC(hash, hlen, &U, hlen, &U, p);
|
|
OCT_xor(&F, &U);
|
|
}
|
|
|
|
OCT_joctet(key, &F);
|
|
}
|
|
|
|
OCT_chop(key, NULL, olen);
|
|
}
|
|
|
|
/* RSA Auxiliary Functions */
|
|
|
|
#define MAX_RSA_BYTES 512 /**< Maximum of 4096 */
|
|
|
|
/* Mask Generation Function */
|
|
|
|
static void MGF1(int sha, octet *z, int olen, octet *mask)
|
|
{
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
int hlen = sha;
|
|
int counter, cthreshold;
|
|
|
|
OCT_empty(mask);
|
|
|
|
cthreshold = ROUNDUP(olen, hlen);
|
|
for (counter = 0; counter < cthreshold; counter++)
|
|
{
|
|
GPhash(MC_SHA2,sha,&H,0,0,z,counter,NULL);
|
|
//hashit(sha, z, counter, &H);
|
|
if (mask->len + hlen > olen) OCT_jbytes(mask, H.val, olen % hlen);
|
|
else OCT_joctet(mask, &H);
|
|
}
|
|
OCT_clear(&H);
|
|
}
|
|
|
|
/* MGF1 plus masking */
|
|
static void MGF1XOR(int sha, octet *z, octet *w)
|
|
{
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
int i,len,wlen,hlen = sha;
|
|
int counter, cthreshold;
|
|
|
|
wlen=0;
|
|
cthreshold = ROUNDUP(w->len, hlen);
|
|
for (counter = 0; counter < cthreshold; counter++)
|
|
{
|
|
GPhash(MC_SHA2,sha,&H,0,0,z,counter,NULL);
|
|
if (wlen+hlen <= w->len)
|
|
len=hlen;
|
|
else
|
|
len=w->len%hlen;
|
|
|
|
for (i=0;i<len;i++)
|
|
w->val[wlen+i]^=H.val[i];
|
|
wlen+=len;
|
|
}
|
|
OCT_clear(&H);
|
|
}
|
|
|
|
|
|
/* SHAXXX identifier strings */
|
|
const unsigned char SHA256ID[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
|
|
const unsigned char SHA384ID[] = {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30};
|
|
const unsigned char SHA512ID[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
|
|
|
|
/* PKCS 1.5 padding of a message to be signed */
|
|
|
|
int core::PKCS15(int sha, octet *m, octet *w)
|
|
{
|
|
int olen = w->max;
|
|
int hlen = sha;
|
|
int idlen = 19;
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
|
|
if (olen < idlen + hlen + 10) return 0;
|
|
GPhash(MC_SHA2,sha,&H,0,0,m,-1,NULL);
|
|
|
|
OCT_empty(w);
|
|
OCT_jbyte(w, 0x00, 1);
|
|
OCT_jbyte(w, 0x01, 1);
|
|
OCT_jbyte(w, 0xff, olen - idlen - hlen - 3);
|
|
OCT_jbyte(w, 0x00, 1);
|
|
|
|
if (hlen == 32) OCT_jbytes(w, (char *)SHA256ID, idlen);
|
|
if (hlen == 48) OCT_jbytes(w, (char *)SHA384ID, idlen);
|
|
if (hlen == 64) OCT_jbytes(w, (char *)SHA512ID, idlen);
|
|
|
|
OCT_joctet(w, &H);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Alternate form, without the NULL 0500 */
|
|
|
|
/* SHAXXX identifier strings */
|
|
const unsigned char SHA256IDb[] = {0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20};
|
|
const unsigned char SHA384IDb[] = {0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30};
|
|
const unsigned char SHA512IDb[] = {0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40};
|
|
|
|
/* PKCS 1.5 padding of a message to be signed */
|
|
|
|
int core::PKCS15b(int sha, octet *m, octet *w)
|
|
{
|
|
int olen = w->max;
|
|
int hlen = sha;
|
|
int idlen = 17;
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
|
|
if (olen < idlen + hlen + 10) return 0;
|
|
GPhash(MC_SHA2,sha,&H,0,0,m,-1,NULL);
|
|
|
|
OCT_empty(w);
|
|
OCT_jbyte(w, 0x00, 1);
|
|
OCT_jbyte(w, 0x01, 1);
|
|
OCT_jbyte(w, 0xff, olen - idlen - hlen - 3);
|
|
OCT_jbyte(w, 0x00, 1);
|
|
|
|
if (hlen == 32) OCT_jbytes(w, (char *)SHA256IDb, idlen);
|
|
if (hlen == 48) OCT_jbytes(w, (char *)SHA384IDb, idlen);
|
|
if (hlen == 64) OCT_jbytes(w, (char *)SHA512IDb, idlen);
|
|
|
|
OCT_joctet(w, &H);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* PSS Encoding of message to be signed. Salt is hlen */
|
|
|
|
int core::PSS_ENCODE(int sha, octet *m, csprng *RNG, octet *w)
|
|
{
|
|
unsigned char mask;
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
char md[136];
|
|
octet MD={0,sizeof(md),md};
|
|
char salt[64];
|
|
octet SALT={0,sizeof(salt),salt};
|
|
int hlen=sha;
|
|
int emlen=w->max;
|
|
int embits=8*emlen-1;
|
|
|
|
OCT_rand(&SALT, RNG, hlen);
|
|
|
|
mask=(0xff)>>(8*emlen-embits);
|
|
|
|
GPhash(MC_SHA2,sha,&H,0,0,m,-1,NULL);
|
|
if (emlen < hlen + hlen + 2) return 0;
|
|
|
|
OCT_jbyte(&MD,0,8);
|
|
OCT_joctet(&MD,&H);
|
|
OCT_joctet(&MD,&SALT);
|
|
|
|
GPhash(MC_SHA2,sha,&H,0,0,&MD,-1,NULL);
|
|
OCT_clear(w);
|
|
OCT_jbyte(w,0,emlen-hlen-hlen-2);
|
|
OCT_jbyte(w,0x01,1);
|
|
OCT_joctet(w,&SALT);
|
|
MGF1XOR(sha,&H,w);
|
|
w->val[0]&=mask;
|
|
|
|
OCT_joctet(w,&H);
|
|
OCT_jbyte(w,0xbc,1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int core::PSS_VERIFY(int sha, octet *m,octet *w)
|
|
{
|
|
int i,k;
|
|
unsigned char mask;
|
|
char hmask[64];
|
|
octet HMASK = {0, sizeof(hmask), hmask};
|
|
char h[64];
|
|
octet H = {0, sizeof(h), h};
|
|
char db[MAX_RSA_BYTES];
|
|
octet DB = {0, sizeof(db), db};
|
|
char salt[64];
|
|
octet SALT={0,sizeof(salt),salt};
|
|
int hlen=sha;
|
|
int emlen=w->len;
|
|
int embits=8*emlen-1;
|
|
|
|
mask=(0xff)>>(8*emlen-embits);
|
|
|
|
GPhash(MC_SHA2,sha,&HMASK,0,0,m,-1,NULL);
|
|
if (emlen < hlen + hlen + 2) return 0;
|
|
if (w->val[emlen-1]!=(char)0xbc) return 0;
|
|
if ((w->val[0]&(~mask))!=0) return 0;
|
|
|
|
OCT_jbytes(&DB,w->val,emlen-hlen-1);
|
|
OCT_jbytes(&H,&w->val[emlen-hlen-1],hlen);
|
|
|
|
MGF1XOR(sha,&H,&DB);
|
|
DB.val[0]&=mask;
|
|
|
|
k=0;
|
|
for (i=0;i<emlen-hlen-hlen-2;i++)
|
|
k|=DB.val[i];
|
|
if (k!=0) return 0;
|
|
if (DB.val[emlen-hlen-hlen-2]!=0x01) return 0;
|
|
OCT_jbytes(&SALT,&DB.val[DB.len-hlen],hlen);
|
|
|
|
OCT_clear(&DB);
|
|
OCT_jbyte(&DB,0,8);
|
|
OCT_joctet(&DB,&HMASK);
|
|
OCT_joctet(&DB,&SALT);
|
|
GPhash(MC_SHA2,sha,&HMASK,0,0,&DB,-1,NULL);
|
|
|
|
if (!OCT_ncomp(&H,&HMASK,H.len))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* OAEP Message Encoding for Encryption */
|
|
|
|
int core::OAEP_ENCODE(int sha, octet *m, csprng *RNG, octet *p, octet *f)
|
|
{
|
|
int slen, olen = f->max - 1;
|
|
int mlen = m->len;
|
|
int hlen, seedlen;
|
|
char dbmask[MAX_RSA_BYTES], seed[64];
|
|
octet DBMASK = {0, sizeof(dbmask), dbmask};
|
|
octet SEED = {0, sizeof(seed), seed};
|
|
|
|
hlen = seedlen = sha;
|
|
if (mlen > olen - hlen - seedlen - 1) return 0;
|
|
if (m == f) return 0; /* must be distinct octets */
|
|
|
|
GPhash(MC_SHA2,sha,f,0,0,p,-1,NULL);
|
|
//hashit(sha, p, -1, f);
|
|
|
|
slen = olen - mlen - hlen - seedlen - 1;
|
|
|
|
OCT_jbyte(f, 0, slen);
|
|
OCT_jbyte(f, 0x1, 1);
|
|
OCT_joctet(f, m);
|
|
|
|
OCT_rand(&SEED, RNG, seedlen);
|
|
|
|
MGF1(sha, &SEED, olen - seedlen, &DBMASK);
|
|
|
|
OCT_xor(&DBMASK, f);
|
|
MGF1(sha, &DBMASK, seedlen, f);
|
|
|
|
OCT_xor(f, &SEED);
|
|
|
|
OCT_joctet(f, &DBMASK);
|
|
|
|
OCT_pad(f, f->max);
|
|
OCT_clear(&SEED);
|
|
OCT_clear(&DBMASK);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* OAEP Message Decoding for Decryption */
|
|
|
|
int core::OAEP_DECODE(int sha, octet *p, octet *f)
|
|
{
|
|
int comp, x, t;
|
|
int i, k, olen = f->max - 1;
|
|
int hlen, seedlen;
|
|
char dbmask[MAX_RSA_BYTES], seed[64], chash[64];
|
|
octet DBMASK = {0, sizeof(dbmask), dbmask};
|
|
octet SEED = {0, sizeof(seed), seed};
|
|
octet CHASH = {0, sizeof(chash), chash};
|
|
|
|
seedlen = hlen = sha;
|
|
if (olen < seedlen + hlen + 1) return 0;
|
|
if (!OCT_pad(f, olen + 1)) return 0;
|
|
|
|
GPhash(MC_SHA2,sha,&CHASH,0,0,p,-1,NULL);
|
|
//hashit(sha, p, -1, &CHASH);
|
|
|
|
x = f->val[0];
|
|
for (i = seedlen; i < olen; i++)
|
|
DBMASK.val[i - seedlen] = f->val[i + 1];
|
|
DBMASK.len = olen - seedlen;
|
|
|
|
MGF1(sha, &DBMASK, seedlen, &SEED);
|
|
for (i = 0; i < seedlen; i++) SEED.val[i] ^= f->val[i + 1];
|
|
MGF1(sha, &SEED, olen - seedlen, f);
|
|
OCT_xor(&DBMASK, f);
|
|
|
|
comp = OCT_ncomp(&CHASH, &DBMASK, hlen);
|
|
|
|
OCT_shl(&DBMASK, hlen);
|
|
|
|
OCT_clear(&SEED);
|
|
OCT_clear(&CHASH);
|
|
|
|
// find first non-zero t in array
|
|
t=k=0;
|
|
for (i=0;i<DBMASK.len;i++)
|
|
{
|
|
if (t==0 && DBMASK.val[i]!=0) {
|
|
k=i;
|
|
t=DBMASK.val[i];
|
|
}
|
|
}
|
|
|
|
if (!comp || x != 0 || t != 0x01)
|
|
{
|
|
OCT_clear(&DBMASK);
|
|
return 0;
|
|
}
|
|
|
|
OCT_shl(&DBMASK, k + 1);
|
|
OCT_copy(f, &DBMASK);
|
|
OCT_clear(&DBMASK);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/* g++ -O2 hmac.cpp oct.cpp hash.cpp rand.cpp -o hmac
|
|
|
|
int main()
|
|
{
|
|
char dst[100],msg[100],okm[100];
|
|
octet DST={0,sizeof(dst),dst};
|
|
octet MSG={0,sizeof(msg),msg};
|
|
octet OKM={0,sizeof(okm),okm};
|
|
|
|
OCT_jstring(&MSG,(char *)"abc");
|
|
OCT_jstring(&DST,(char *)"P256_XMD:SHA-256_SSWU_RO_TESTGEN");
|
|
// XMD_Expand(MC_SHA2,32,&OKM,48,&DST,&MSG);
|
|
XOF_Expand(SHAKE128,&OKM,48,&DST,&MSG);
|
|
|
|
printf("OKM= %d ",OKM.len); OCT_output(&OKM);
|
|
|
|
char ikm[22],salt[13],prk[32],info[10],okm[50];
|
|
octet IKM = {0, sizeof(ikm), ikm};
|
|
octet SALT={0,sizeof(salt),salt};
|
|
octet PRK={0,sizeof(prk),prk};
|
|
octet OKM={0,sizeof(okm),okm};
|
|
octet INFO={0,sizeof(info),info};
|
|
int i;
|
|
for (i=0;i<22;i++) IKM.val[i]=0x0b;
|
|
for (i=0;i<13;i++) SALT.val[i]=i;
|
|
for (i=0;i<10;i++) INFO.val[i]=0xf0+i;
|
|
|
|
IKM.len=22; SALT.len=13; INFO.len=10;
|
|
|
|
printf("IKM= "); OCT_output(&IKM);
|
|
printf("SALT= "); OCT_output(&SALT);
|
|
|
|
HKDF_Extract(MC_SHA2,32,&PRK,&SALT,&IKM);
|
|
|
|
//HMAC(&PRK,32,&SALT,&IKM,SHA2,32);
|
|
|
|
printf("PRK= "); OCT_output(&PRK);
|
|
|
|
HKDF_Expand(MC_SHA2,32,&OKM,42,&PRK,&INFO);
|
|
|
|
printf("OKM= %d ",OKM.len); OCT_output(&OKM);
|
|
}
|
|
|
|
*/
|