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