282 lines
7.9 KiB
C++
282 lines
7.9 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.
|
||
|
*/
|
||
|
|
||
|
/* Hybrid Public Key Encryption */
|
||
|
|
||
|
/* Following https://datatracker.ietf.org/doc/draft-irtf-cfrg-hpke/?include_text=1 */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include "hpke_ZZZ.h"
|
||
|
|
||
|
#define GROUP EGS_ZZZ
|
||
|
#define POINT (2*EFS_ZZZ+1)
|
||
|
#define MAX_HASH HASH_TYPE_ZZZ
|
||
|
#define MAX_LABEL 20 // may need adjustment
|
||
|
|
||
|
static void ZZZ::LabeledExtract(octet *PRK,octet *SALT,octet *SUITE_ID,char *label,octet *IKM)
|
||
|
{
|
||
|
char likm[18+MAX_LABEL+2*POINT];
|
||
|
octet LIKM={0,sizeof(likm),likm};
|
||
|
OCT_jstring(&LIKM,(char *)"HPKE-v1");
|
||
|
OCT_joctet(&LIKM,SUITE_ID);
|
||
|
OCT_jstring(&LIKM,label);
|
||
|
if (IKM!=NULL)
|
||
|
OCT_joctet(&LIKM,IKM);
|
||
|
HKDF_Extract(MC_SHA2,HASH_TYPE_ZZZ,PRK,SALT,&LIKM);
|
||
|
}
|
||
|
|
||
|
static void ZZZ::LabeledExpand(octet *OKM,octet *PRK,octet *SUITE_ID,char *label,octet *INFO,int L)
|
||
|
{
|
||
|
char linfo[20+MAX_LABEL+3*POINT];
|
||
|
octet LINFO={0,sizeof(linfo),linfo};
|
||
|
OCT_jint(&LINFO,L,2);
|
||
|
OCT_jstring(&LINFO,(char *)"HPKE-v1");
|
||
|
OCT_joctet(&LINFO,SUITE_ID);
|
||
|
OCT_jstring(&LINFO,label);
|
||
|
if (INFO!=NULL)
|
||
|
OCT_joctet(&LINFO,INFO);
|
||
|
HKDF_Expand(MC_SHA2,HASH_TYPE_ZZZ,OKM,L,PRK,&LINFO);
|
||
|
}
|
||
|
|
||
|
static void ZZZ::ExtractAndExpand(int config_id,octet *OKM,octet *DH,octet *CONTEXT)
|
||
|
{
|
||
|
char prk[MAX_HASH];
|
||
|
octet PRK={0,sizeof(prk),prk};
|
||
|
char suite_id[10];
|
||
|
octet SUITE_ID={0,sizeof(suite_id),suite_id};
|
||
|
|
||
|
int kem_id=config_id&255;
|
||
|
OCT_jstring(&SUITE_ID,(char *)"KEM");
|
||
|
OCT_jint(&SUITE_ID,kem_id,2);
|
||
|
|
||
|
LabeledExtract(&PRK,NULL,&SUITE_ID,(char *)"eae_prk",DH);
|
||
|
LabeledExpand(OKM, &PRK,&SUITE_ID,(char *)"shared_secret",CONTEXT,HASH_TYPE_ZZZ);
|
||
|
}
|
||
|
|
||
|
int ZZZ::DeriveKeyPair(int config_id,octet *SK,octet *PK,octet *SEED)
|
||
|
{
|
||
|
int counter=0;
|
||
|
char prk[MAX_HASH];
|
||
|
octet PRK={0,sizeof(prk),prk};
|
||
|
char suite_id[10];
|
||
|
octet SUITE_ID={0,sizeof(suite_id),suite_id};
|
||
|
char info[2];
|
||
|
octet INFO={0,sizeof(info),info};
|
||
|
int bit_mask,kem=config_id&255;
|
||
|
OCT_jstring(&SUITE_ID,(char *)"KEM");
|
||
|
OCT_jint(&SUITE_ID,kem,2);
|
||
|
LabeledExtract(&PRK,NULL,&SUITE_ID,(char *)"dkp_prk",SEED);
|
||
|
|
||
|
//printf("PRK= ");OCT_output(&PRK); printf("\n");
|
||
|
|
||
|
if (kem==32 || kem==33)
|
||
|
{ // RFC7748
|
||
|
LabeledExpand(SK,&PRK,&SUITE_ID,(char *)"sk",NULL,GROUP);
|
||
|
OCT_reverse(SK);
|
||
|
if (kem==32)
|
||
|
{
|
||
|
SK->val[GROUP-1]&=248;
|
||
|
SK->val[0]&=127;
|
||
|
SK->val[0]|=64;
|
||
|
} else {
|
||
|
SK->val[GROUP-1]&=252;
|
||
|
SK->val[0]|=128;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
if (kem==18) bit_mask=1;
|
||
|
else bit_mask=0xFF;
|
||
|
OCT_clear(SK);
|
||
|
while (!ECP_IN_RANGE(SK) && counter<256)
|
||
|
{
|
||
|
OCT_empty(&INFO);
|
||
|
OCT_jbyte(&INFO,counter,1);
|
||
|
LabeledExpand(SK,&PRK,&SUITE_ID,(char *)"candidate",&INFO,GROUP);
|
||
|
SK->val[0]&=bit_mask;
|
||
|
counter++;
|
||
|
}
|
||
|
}
|
||
|
//printf("SK= ");OCT_output(SK); printf("\n");
|
||
|
//printf("kem= %d\n",kem);
|
||
|
//printf("counter= %d\n",counter);
|
||
|
ECP_KEY_PAIR_GENERATE(NULL, SK, PK);
|
||
|
if (kem==32 || kem==33)
|
||
|
OCT_reverse(PK);
|
||
|
|
||
|
if (counter<256) return 1;
|
||
|
else return 0;
|
||
|
}
|
||
|
|
||
|
void ZZZ::HPKE_Encap(int config_id,octet *skE,octet *Z,octet *pkE,octet *pkR)
|
||
|
{
|
||
|
int res,kem;
|
||
|
char dh[POINT];
|
||
|
octet DH={0,sizeof(dh),dh};
|
||
|
char kemcontext[2*POINT];
|
||
|
octet KEMCONTEXT={0,sizeof(kemcontext),kemcontext};
|
||
|
kem=config_id&255;
|
||
|
|
||
|
if (kem==32 || kem==33)
|
||
|
{
|
||
|
OCT_reverse(pkR);
|
||
|
res=ECP_SVDP_DH(skE, pkR, &DH, 0);
|
||
|
OCT_reverse(pkR);
|
||
|
OCT_reverse(&DH);
|
||
|
} else {
|
||
|
res=ECP_SVDP_DH(skE, pkR, &DH, 0);
|
||
|
}
|
||
|
|
||
|
OCT_copy(&KEMCONTEXT,pkE);
|
||
|
OCT_joctet(&KEMCONTEXT,pkR);
|
||
|
ExtractAndExpand(config_id,Z,&DH,&KEMCONTEXT);
|
||
|
}
|
||
|
|
||
|
void ZZZ::HPKE_Decap(int config_id,octet *skR,octet *Z,octet *pkE,octet *pkR)
|
||
|
{
|
||
|
int res,kem;
|
||
|
char dh[POINT];
|
||
|
octet DH={0,sizeof(dh),dh};
|
||
|
char kemcontext[2*POINT];
|
||
|
octet KEMCONTEXT={0,sizeof(kemcontext),kemcontext};
|
||
|
kem=config_id&255;
|
||
|
|
||
|
if (kem==32 || kem==33)
|
||
|
{
|
||
|
OCT_reverse(pkE);
|
||
|
ECP_SVDP_DH(skR, pkE, &DH, 0);
|
||
|
OCT_reverse(pkE);
|
||
|
OCT_reverse(&DH);
|
||
|
} else {
|
||
|
ECP_SVDP_DH(skR, pkE, &DH, 0);
|
||
|
}
|
||
|
|
||
|
OCT_copy(&KEMCONTEXT,pkE);
|
||
|
OCT_joctet(&KEMCONTEXT,pkR);
|
||
|
|
||
|
ExtractAndExpand(config_id,Z,&DH,&KEMCONTEXT);
|
||
|
}
|
||
|
|
||
|
void ZZZ::HPKE_AuthEncap(int config_id,octet *skE,octet *skS,octet *Z,octet *pkE,octet *pkR,octet *pkS)
|
||
|
{
|
||
|
int res,kem;
|
||
|
char dh[2*POINT];
|
||
|
octet DH={0,sizeof(dh),dh};
|
||
|
char dh1[POINT];
|
||
|
octet DH1={0,sizeof(dh1),dh1};
|
||
|
char kemcontext[3*POINT];
|
||
|
octet KEMCONTEXT={0,sizeof(kemcontext),kemcontext};
|
||
|
|
||
|
kem=config_id&255;
|
||
|
|
||
|
if (kem==32 || kem==33)
|
||
|
{
|
||
|
OCT_reverse(pkR);
|
||
|
ECP_SVDP_DH(skE, pkR, &DH,0);
|
||
|
ECP_SVDP_DH(skS, pkR, &DH1,0);
|
||
|
OCT_reverse(pkR);
|
||
|
OCT_reverse(&DH);
|
||
|
OCT_reverse(&DH1);
|
||
|
} else {
|
||
|
ECP_SVDP_DH(skE, pkR, &DH, 0);
|
||
|
ECP_SVDP_DH(skS, pkR, &DH1,0);
|
||
|
}
|
||
|
|
||
|
OCT_joctet(&DH,&DH1);
|
||
|
OCT_copy(&KEMCONTEXT,pkE);
|
||
|
OCT_joctet(&KEMCONTEXT,pkR);
|
||
|
OCT_joctet(&KEMCONTEXT,pkS);
|
||
|
|
||
|
ExtractAndExpand(config_id,Z,&DH,&KEMCONTEXT);
|
||
|
}
|
||
|
|
||
|
void ZZZ::HPKE_AuthDecap(int config_id,octet *skR,octet *Z,octet *pkE,octet *pkR,octet *pkS)
|
||
|
{
|
||
|
int res,kem;
|
||
|
char dh[2*POINT];
|
||
|
octet DH={0,sizeof(dh),dh};
|
||
|
char dh1[POINT];
|
||
|
octet DH1={0,sizeof(dh1),dh1};
|
||
|
char kemcontext[3*POINT];
|
||
|
octet KEMCONTEXT={0,sizeof(kemcontext),kemcontext};
|
||
|
|
||
|
kem=config_id&255;
|
||
|
|
||
|
if (kem==32 || kem==33) {
|
||
|
OCT_reverse(pkE);
|
||
|
OCT_reverse(pkS);
|
||
|
ECP_SVDP_DH(skR, pkE, &DH,0);
|
||
|
ECP_SVDP_DH(skR, pkS, &DH1,0);
|
||
|
OCT_reverse(pkE);
|
||
|
OCT_reverse(pkS);
|
||
|
OCT_reverse(&DH);
|
||
|
OCT_reverse(&DH1);
|
||
|
} else {
|
||
|
ECP_SVDP_DH(skR, pkE, &DH, 0);
|
||
|
ECP_SVDP_DH(skR, pkS, &DH1, 0);
|
||
|
}
|
||
|
OCT_joctet(&DH,&DH1);
|
||
|
|
||
|
OCT_copy(&KEMCONTEXT,pkE);
|
||
|
OCT_joctet(&KEMCONTEXT,pkR);
|
||
|
OCT_joctet(&KEMCONTEXT,pkS);
|
||
|
|
||
|
ExtractAndExpand(config_id,Z,&DH,&KEMCONTEXT);
|
||
|
}
|
||
|
|
||
|
void ZZZ::HPKE_KeySchedule(int config_id,octet *key,octet *nonce,octet *exp_secret,int mode,octet *Z,octet *info,octet *psk,octet *pskID)
|
||
|
{
|
||
|
char context[1+2*MAX_HASH];
|
||
|
octet CONTEXT={0,sizeof(context),context};
|
||
|
|
||
|
char h[MAX_HASH];
|
||
|
octet H={0,sizeof(h),h};
|
||
|
char secret_h[MAX_HASH];
|
||
|
octet secret={0,sizeof(secret_h),secret_h};
|
||
|
|
||
|
int kem_id=config_id&255;
|
||
|
int kdf_id=(config_id>>8)&3;
|
||
|
int aead_id=(config_id>>10)&3;
|
||
|
|
||
|
char suite_id[10];
|
||
|
octet SUITE_ID={0,sizeof(suite_id),suite_id};
|
||
|
OCT_jstring(&SUITE_ID,(char *)"HPKE");
|
||
|
OCT_jint(&SUITE_ID,kem_id,2);
|
||
|
OCT_jint(&SUITE_ID,kdf_id,2);
|
||
|
OCT_jint(&SUITE_ID,aead_id,2);
|
||
|
|
||
|
OCT_jint(&CONTEXT,mode,1);
|
||
|
|
||
|
LabeledExtract(&H,NULL,&SUITE_ID,(char *)"psk_id_hash",pskID);
|
||
|
OCT_joctet(&CONTEXT,&H);
|
||
|
LabeledExtract(&H,NULL,&SUITE_ID,(char *)"info_hash",info);
|
||
|
OCT_joctet(&CONTEXT,&H);
|
||
|
|
||
|
LabeledExtract(&secret,Z,&SUITE_ID,(char *)"secret",psk);
|
||
|
|
||
|
//LabeledExtract(&H,NULL,&SUITE_ID,(char *)"psk_hash",psk);
|
||
|
//LabeledExtract(&secret,&H,&SUITE_ID,(char *)"secret",Z);
|
||
|
|
||
|
LabeledExpand(key,&secret,&SUITE_ID,(char *)"key",&CONTEXT,AESKEY_ZZZ);
|
||
|
LabeledExpand(nonce,&secret,&SUITE_ID,(char *)"base_nonce",&CONTEXT,12);
|
||
|
if (exp_secret!=NULL)
|
||
|
LabeledExpand(exp_secret,&secret,&SUITE_ID,(char *)"exp",&CONTEXT,HASH_TYPE_ZZZ);
|
||
|
}
|