MastersThesis/PQ_TIIGER_TLS/sal/miracl-ubuntu22-11-04-24/includes/hmac.cpp
2024-04-19 14:16:07 +02:00

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);
}
*/