mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 00:55:17 +00:00
328 lines
7.8 KiB
Go
328 lines
7.8 KiB
Go
|
/*
|
||
|
* 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 */
|
||
|
|
||
|
package bls48581
|
||
|
|
||
|
//import "fmt"
|
||
|
import "source.quilibrium.com/quilibrium/ceremonyclient/ec/bls48581/core"
|
||
|
|
||
|
func reverse(X []byte) {
|
||
|
lx := len(X)
|
||
|
for i := 0; i < lx/2; i++ {
|
||
|
ch := X[i]
|
||
|
X[i] = X[lx-i-1]
|
||
|
X[lx-i-1] = ch
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func labeledExtract(SALT []byte, SUITE_ID []byte, label string, IKM []byte) []byte {
|
||
|
rfc := "HPKE-v1"
|
||
|
RFC := []byte(rfc)
|
||
|
LABEL := []byte(label)
|
||
|
var LIKM []byte
|
||
|
for i := 0; i < len(RFC); i++ {
|
||
|
LIKM = append(LIKM, RFC[i])
|
||
|
}
|
||
|
for i := 0; i < len(SUITE_ID); i++ {
|
||
|
LIKM = append(LIKM, SUITE_ID[i])
|
||
|
}
|
||
|
for i := 0; i < len(LABEL); i++ {
|
||
|
LIKM = append(LIKM, LABEL[i])
|
||
|
}
|
||
|
if IKM != nil {
|
||
|
for i := 0; i < len(IKM); i++ {
|
||
|
LIKM = append(LIKM, IKM[i])
|
||
|
}
|
||
|
}
|
||
|
return core.HKDF_Extract(core.MC_SHA2, HASH_TYPE, SALT, LIKM)
|
||
|
}
|
||
|
|
||
|
func labeledExpand(PRK []byte, SUITE_ID []byte, label string, INFO []byte, L int) []byte {
|
||
|
rfc := "HPKE-v1"
|
||
|
RFC := []byte(rfc)
|
||
|
LABEL := []byte(label)
|
||
|
AR := core.InttoBytes(L, 2)
|
||
|
var LINFO []byte
|
||
|
for i := 0; i < len(AR); i++ {
|
||
|
LINFO = append(LINFO, AR[i])
|
||
|
}
|
||
|
for i := 0; i < len(RFC); i++ {
|
||
|
LINFO = append(LINFO, RFC[i])
|
||
|
}
|
||
|
for i := 0; i < len(SUITE_ID); i++ {
|
||
|
LINFO = append(LINFO, SUITE_ID[i])
|
||
|
}
|
||
|
for i := 0; i < len(LABEL); i++ {
|
||
|
LINFO = append(LINFO, LABEL[i])
|
||
|
}
|
||
|
if INFO != nil {
|
||
|
for i := 0; i < len(INFO); i++ {
|
||
|
LINFO = append(LINFO, INFO[i])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return core.HKDF_Expand(core.MC_SHA2, HASH_TYPE, L, PRK, LINFO)
|
||
|
}
|
||
|
|
||
|
func extractAndExpand(config_id int, DH []byte, context []byte) []byte {
|
||
|
kem := config_id & 255
|
||
|
txt := "KEM"
|
||
|
KEM_ID := core.InttoBytes(kem, 2)
|
||
|
KEM := []byte(txt)
|
||
|
var SUITE_ID []byte
|
||
|
for i := 0; i < len(KEM); i++ {
|
||
|
SUITE_ID = append(SUITE_ID, KEM[i])
|
||
|
}
|
||
|
SUITE_ID = append(SUITE_ID, KEM_ID[0])
|
||
|
SUITE_ID = append(SUITE_ID, KEM_ID[1])
|
||
|
|
||
|
PRK := labeledExtract(nil, SUITE_ID, "eae_prk", DH)
|
||
|
return labeledExpand(PRK, SUITE_ID, "shared_secret", context, HASH_TYPE)
|
||
|
}
|
||
|
|
||
|
func DeriveKeyPair(config_id int, SK []byte, PK []byte, SEED []byte) bool {
|
||
|
counter := 0
|
||
|
kem := config_id & 255
|
||
|
|
||
|
txt := "KEM"
|
||
|
KEM_ID := core.InttoBytes(kem, 2)
|
||
|
KEM := []byte(txt)
|
||
|
var SUITE_ID []byte
|
||
|
for i := 0; i < len(KEM); i++ {
|
||
|
SUITE_ID = append(SUITE_ID, KEM[i])
|
||
|
}
|
||
|
SUITE_ID = append(SUITE_ID, KEM_ID[0])
|
||
|
SUITE_ID = append(SUITE_ID, KEM_ID[1])
|
||
|
|
||
|
PRK := labeledExtract(nil, SUITE_ID, "dkp_prk", SEED)
|
||
|
var S []byte
|
||
|
if kem == 32 || kem == 33 { // RFC7748
|
||
|
S = labeledExpand(PRK, SUITE_ID, "sk", nil, EGS)
|
||
|
reverse(S)
|
||
|
if kem == 32 {
|
||
|
S[EGS-1] &= 248
|
||
|
S[0] &= 127
|
||
|
S[0] |= 64
|
||
|
} else {
|
||
|
S[EGS-1] &= 252
|
||
|
S[0] |= 128
|
||
|
}
|
||
|
} else {
|
||
|
bit_mask := 0xff
|
||
|
if kem == 18 {
|
||
|
bit_mask = 1
|
||
|
}
|
||
|
for i := 0; i < EGS; i++ {
|
||
|
S = append(S, 0)
|
||
|
}
|
||
|
for !ECDH_IN_RANGE(S) && counter < 256 {
|
||
|
var INFO [1]byte
|
||
|
INFO[0] = byte(counter)
|
||
|
S = labeledExpand(PRK, SUITE_ID, "candidate", INFO[:], EGS)
|
||
|
S[0] &= byte(bit_mask)
|
||
|
counter++
|
||
|
}
|
||
|
}
|
||
|
for i := 0; i < EGS; i++ {
|
||
|
SK[i] = S[i]
|
||
|
}
|
||
|
ECDH_KEY_PAIR_GENERATE(nil, SK, PK)
|
||
|
if kem == 32 || kem == 33 {
|
||
|
reverse(PK)
|
||
|
}
|
||
|
if counter < 256 {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func Encap(config_id int, skE []byte, pkE []byte, pkR []byte) []byte {
|
||
|
DH := make([]byte, EFS)
|
||
|
var kemcontext []byte
|
||
|
kem := config_id & 255
|
||
|
|
||
|
if kem == 32 || kem == 33 {
|
||
|
reverse(pkR)
|
||
|
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
|
||
|
reverse(pkR)
|
||
|
reverse(DH[:])
|
||
|
} else {
|
||
|
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
|
||
|
}
|
||
|
for i := 0; i < len(pkE); i++ {
|
||
|
kemcontext = append(kemcontext, pkE[i])
|
||
|
}
|
||
|
for i := 0; i < len(pkR); i++ {
|
||
|
kemcontext = append(kemcontext, pkR[i])
|
||
|
}
|
||
|
return extractAndExpand(config_id, DH[:], kemcontext)
|
||
|
}
|
||
|
|
||
|
func Decap(config_id int, skR []byte, pkE []byte, pkR []byte) []byte {
|
||
|
DH := make([]byte, EFS)
|
||
|
var kemcontext []byte
|
||
|
kem := config_id & 255
|
||
|
|
||
|
if kem == 32 || kem == 33 {
|
||
|
reverse(pkE)
|
||
|
ECDH_ECPSVDP_DH(skR, pkE, DH[:], 0)
|
||
|
reverse(pkE)
|
||
|
reverse(DH[:])
|
||
|
} else {
|
||
|
ECDH_ECPSVDP_DH(skR, pkE, DH[:], 0)
|
||
|
}
|
||
|
|
||
|
for i := 0; i < len(pkE); i++ {
|
||
|
kemcontext = append(kemcontext, pkE[i])
|
||
|
}
|
||
|
for i := 0; i < len(pkR); i++ {
|
||
|
kemcontext = append(kemcontext, pkR[i])
|
||
|
}
|
||
|
return extractAndExpand(config_id, DH[:], kemcontext)
|
||
|
}
|
||
|
|
||
|
func AuthEncap(config_id int, skE []byte, skS []byte, pkE []byte, pkR []byte, pkS []byte) []byte {
|
||
|
pklen := len(pkE)
|
||
|
DH := make([]byte, EFS)
|
||
|
DH1 := make([]byte, EFS)
|
||
|
|
||
|
kemcontext := make([]byte, 3*pklen)
|
||
|
kem := config_id & 255
|
||
|
|
||
|
if kem == 32 || kem == 33 {
|
||
|
reverse(pkR)
|
||
|
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
|
||
|
ECDH_ECPSVDP_DH(skS, pkR, DH1[:], 0)
|
||
|
reverse(pkR)
|
||
|
reverse(DH[:])
|
||
|
reverse(DH1[:])
|
||
|
} else {
|
||
|
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
|
||
|
ECDH_ECPSVDP_DH(skS, pkR, DH1[:], 0)
|
||
|
}
|
||
|
ZZ := make([]byte, 2*EFS)
|
||
|
for i := 0; i < EFS; i++ {
|
||
|
ZZ[i] = DH[i]
|
||
|
ZZ[EFS+i] = DH1[i]
|
||
|
}
|
||
|
|
||
|
for i := 0; i < pklen; i++ {
|
||
|
kemcontext[i] = pkE[i]
|
||
|
kemcontext[pklen+i] = pkR[i]
|
||
|
kemcontext[2*pklen+i] = pkS[i]
|
||
|
}
|
||
|
return extractAndExpand(config_id, ZZ[:], kemcontext)
|
||
|
}
|
||
|
|
||
|
func AuthDecap(config_id int, skR []byte, pkE []byte, pkR []byte, pkS []byte) []byte {
|
||
|
pklen := len(pkE)
|
||
|
DH := make([]byte, EFS)
|
||
|
DH1 := make([]byte, EFS)
|
||
|
kemcontext := make([]byte, 3*pklen)
|
||
|
|
||
|
kem := config_id & 255
|
||
|
|
||
|
if kem == 32 || kem == 33 {
|
||
|
reverse(pkE)
|
||
|
reverse(pkS)
|
||
|
ECDH_ECPSVDP_DH(skR[:], pkE, DH[:], 0)
|
||
|
ECDH_ECPSVDP_DH(skR[:], pkS, DH1[:], 0)
|
||
|
reverse(pkE)
|
||
|
reverse(pkS)
|
||
|
reverse(DH[:])
|
||
|
reverse(DH1[:])
|
||
|
} else {
|
||
|
ECDH_ECPSVDP_DH(skR[:], pkE, DH[:], 0)
|
||
|
ECDH_ECPSVDP_DH(skR[:], pkS, DH1[:], 0)
|
||
|
}
|
||
|
ZZ := make([]byte, 2*EFS)
|
||
|
for i := 0; i < EFS; i++ {
|
||
|
ZZ[i] = DH[i]
|
||
|
ZZ[EFS+i] = DH1[i]
|
||
|
}
|
||
|
|
||
|
for i := 0; i < pklen; i++ {
|
||
|
kemcontext[i] = pkE[i]
|
||
|
kemcontext[pklen+i] = pkR[i]
|
||
|
kemcontext[2*pklen+i] = pkS[i]
|
||
|
}
|
||
|
return extractAndExpand(config_id, ZZ[:], kemcontext)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
func printBinary(array []byte) {
|
||
|
for i := 0; i < len(array); i++ {
|
||
|
fmt.Printf("%02x", array[i])
|
||
|
}
|
||
|
fmt.Printf("\n")
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
func KeySchedule(config_id int, mode int, Z []byte, info []byte, psk []byte, pskID []byte) ([]byte, []byte, []byte) {
|
||
|
var context []byte
|
||
|
|
||
|
kem := config_id & 255
|
||
|
kdf := (config_id >> 8) & 3
|
||
|
aead := (config_id >> 10) & 3
|
||
|
|
||
|
txt := "HPKE"
|
||
|
KEM := []byte(txt)
|
||
|
var SUITE_ID []byte
|
||
|
for i := 0; i < len(KEM); i++ {
|
||
|
SUITE_ID = append(SUITE_ID, KEM[i])
|
||
|
}
|
||
|
num := core.InttoBytes(kem, 2)
|
||
|
SUITE_ID = append(SUITE_ID, num[0])
|
||
|
SUITE_ID = append(SUITE_ID, num[1])
|
||
|
num = core.InttoBytes(kdf, 2)
|
||
|
SUITE_ID = append(SUITE_ID, num[0])
|
||
|
SUITE_ID = append(SUITE_ID, num[1])
|
||
|
num = core.InttoBytes(aead, 2)
|
||
|
SUITE_ID = append(SUITE_ID, num[0])
|
||
|
SUITE_ID = append(SUITE_ID, num[1])
|
||
|
|
||
|
ar := core.InttoBytes(mode, 1)
|
||
|
for i := 0; i < len(ar); i++ {
|
||
|
context = append(context, ar[i])
|
||
|
}
|
||
|
|
||
|
H := labeledExtract(nil, SUITE_ID, "psk_id_hash", pskID)
|
||
|
for i := 0; i < HASH_TYPE; i++ {
|
||
|
context = append(context, H[i])
|
||
|
}
|
||
|
H = labeledExtract(nil, SUITE_ID, "info_hash", info)
|
||
|
for i := 0; i < HASH_TYPE; i++ {
|
||
|
context = append(context, H[i])
|
||
|
}
|
||
|
//H=labeledExtract(nil,SUITE_ID,"psk_hash",psk)
|
||
|
//secret:=labeledExtract(H,SUITE_ID,"secret",Z)
|
||
|
|
||
|
secret := labeledExtract(Z, SUITE_ID, "secret", psk)
|
||
|
|
||
|
key := labeledExpand(secret, SUITE_ID, "key", context, AESKEY)
|
||
|
nonce := labeledExpand(secret, SUITE_ID, "base_nonce", context, 12)
|
||
|
exp_secret := labeledExpand(secret, SUITE_ID, "exp", context, HASH_TYPE)
|
||
|
|
||
|
return key, nonce, exp_secret
|
||
|
}
|