blob: 2bb456587645062e3a290b6f81f52d19319da53f [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oqs/oqs.h>
#include <amcl/pqnist.h>
#include <amcl/utils.h>
#include <amcl/randapi.h>
#include <amcl/bls_BLS381.h>
#define G2LEN 4*BFS_BLS381
#define SIGLEN BFS_BLS381+1
// Generate BLS public and private key
int pqnist_bls_keys(char* seed, char* BLSpk, char* BLSsk)
{
int rc;
octet PK = {0,G2LEN,BLSpk};
octet SK = {0,BGS_BLS381,BLSsk};
if (seed==NULL)
{
rc = BLS_BLS381_KEY_PAIR_GENERATE(NULL,&SK,&PK);
}
else
{
octet SEED = {PQNIST_SEED_LENGTH,PQNIST_SEED_LENGTH,seed};
// CSPRNG
csprng RNG;
// initialise strong RNG
CREATE_CSPRNG(&RNG,&SEED);
// Generate BLS key pair
rc = BLS_BLS381_KEY_PAIR_GENERATE(&RNG,&SK,&PK);
}
if (rc)
{
return rc;
}
#ifdef DEBUG
printf("pqnist_keys BLSpklen %d BLSpk ", PK.len);
OCT_output(&PK);
printf("pqnist_keys BLSsklen %d BLSsk ", SK.len);
OCT_output(&SK);
#endif
return 0;
}
// Sign message using the BLS algorithm
int pqnist_bls_sign(char* M, char* sk, char* S)
{
octet SIG = {0,SIGLEN,S};
octet SK = {BGS_BLS381,BGS_BLS381,sk};
#ifdef DEBUG
printf("pqnist_bls_sign SK: ");
OCT_output(&SK);
#endif
int rc = BLS_BLS381_SIGN(&SIG,M,&SK);
if (rc!=BLS_OK)
{
return rc;
}
#ifdef DEBUG
printf("pqnist_bls_sign SIG: ");
OCT_output(&SIG);
#endif
return 0;
}
// Verify a signature using the BLS algorithm
int pqnist_bls_verify(char* M, char* pk, char* S)
{
octet SIG = {SIGLEN,SIGLEN,S};
octet PK = {G2LEN,G2LEN,pk};
#ifdef DEBUG
printf("pqnist_bls_verify M %s\n", M);
printf("pqnist_bls_verify PK: ");
OCT_output(&PK);
printf("pqnist_bls_verify SIG: ");
OCT_output(&SIG);
#endif
int rc=BLS_BLS381_VERIFY(&SIG,M,&PK);
if (rc!=BLS_OK)
{
return rc;
}
return 0;
}
// Add two members from the group G1
int pqnist_bls_addg1(char* r1, char* r2, char* r)
{
octet R1 = {BGS_BLS381,BGS_BLS381,r1};
octet R2 = {BGS_BLS381,BGS_BLS381,r2};
octet R = {BGS_BLS381,BGS_BLS381,r};
int rc=BLS_BLS381_ADD_G1(&R1,&R2,&R);
if (rc!=BLS_OK)
{
return rc;
}
#ifdef DEBUG
printf("pqnist_bls_addg1 R1: ");
OCT_output(&R1);
printf("pqnist_bls_addg1 R2: ");
OCT_output(&R2);
printf("pqnist_bls_addg1 R: ");
OCT_output(&R);
#endif
return 0;
}
// Add two members from the group G2
int pqnist_bls_addg2(char* r1, char* r2, char* r)
{
octet R1 = {G2LEN,G2LEN,r1};
octet R2 = {G2LEN,G2LEN,r2};
octet R = {G2LEN,G2LEN,r};
int rc=BLS_BLS381_ADD_G2(&R1,&R2,&R);
if (rc!=BLS_OK)
{
return rc;
}
#ifdef DEBUG
printf("pqnist_bls_addg2 R1: ");
OCT_output(&R1);
printf("pqnist_bls_addg2 R2: ");
OCT_output(&R2);
printf("pqnist_bls_addg2 R: ");
OCT_output(&R);
#endif
return 0;
}
// Use Shamir's secret sharing to distribute BLS secret keys
int pqnist_bls_make_shares(int k, int n, char* pSEED, char* pX, char* pY, char* pSKI, char* pSKO)
{
int rc;
octet SEED = {PQNIST_SEED_LENGTH,PQNIST_SEED_LENGTH,pSEED};
octet SKI = {BGS_BLS381,BGS_BLS381,pSKI};
octet SKO = {BGS_BLS381,BGS_BLS381,pSKO};
octet X[n];
octet Y[n];
for(int i=0; i<n; i++)
{
Y[i].max = BGS_BLS381;
Y[i].len = BGS_BLS381;
Y[i].val = &pY[i*BGS_BLS381];
X[i].max = BGS_BLS381;
X[i].len = BGS_BLS381;
X[i].val = &pX[i*BGS_BLS381];
}
// CSPRNG
csprng RNG;
// initialise strong RNG
CREATE_CSPRNG(&RNG,&SEED);
// Make shares of BLS secret key
rc = BLS_BLS381_MAKE_SHARES(k, n, &RNG, X, Y, &SKI, &SKO);
if (rc)
{
return rc;
}
#ifdef DEBUG
printf("pqnist_keys SEED: ");
OCT_output(&SEED);
printf("\n");
for(int i=0; i<n; i++)
{
printf("X[%d] ", i);
OCT_output(&X[i]);
printf("Y[%d] ", i);
OCT_output(&Y[i]);
printf("\n");
}
printf("SKI: ");
OCT_output(&SKI);
printf("SKO: ");
OCT_output(&SKO);
#endif
return 0;
}
// Use Shamir's secret sharing to recover a BLS secret key
int pqnist_bls_recover_secret(int k, char* pX, char* pY, char* pSK)
{
int rc;
octet SK = {BGS_BLS381,BGS_BLS381,pSK};
octet X[k];
octet Y[k];
for(int i=0; i<k; i++)
{
Y[i].max = BGS_BLS381;
Y[i].len = BGS_BLS381;
Y[i].val = &pY[i*BGS_BLS381];
X[i].max = BGS_BLS381;
X[i].len = BGS_BLS381;
X[i].val = &pX[i*BGS_BLS381];
}
// Recover BLS secret key
rc = BLS_BLS381_RECOVER_SECRET(k, X, Y, &SK);
if (rc)
{
return rc;
}
#ifdef DEBUG
printf("SK: ");
OCT_output(&SK);
#endif
return 0;
}
// Use Shamir's secret sharing to recover a BLS signature
int pqnist_bls_recover_signature(int k, char* pX, char* pY, char* pSIG)
{
int rc;
octet SIG = {SIGLEN,SIGLEN,pSIG};
octet X[k];
octet Y[k];
for(int i=0; i<k; i++)
{
Y[i].max = SIGLEN;
Y[i].len = SIGLEN;
Y[i].val = &pY[(SIGLEN)*i];
X[i].max = BGS_BLS381;
X[i].len = BGS_BLS381;
X[i].val = &pX[BGS_BLS381*i];
}
// Recover BLS signature
rc = BLS_BLS381_RECOVER_SIGNATURE(k, X, Y, &SIG);
if (rc)
{
return rc;
}
#ifdef DEBUG
printf("pqnist_bls_recover_signature SIG: ");
OCT_output(&SIG);
#endif
return 0;
}
// Generate SIKE and BLS public and private key pairs
int pqnist_sike_keys(char* seed, char* SIKEpk, char* SIKEsk)
{
int rc;
// Initialise KAT RNG
rc = OQS_randombytes_switch_algorithm(OQS_RAND_alg_nist_kat);
if (rc != OQS_SUCCESS)
{
return rc;
}
OQS_randombytes_nist_kat_init(seed, NULL, 256);
// Generate SIKE key pair
rc = OQS_KEM_sike_p751_keypair(SIKEpk, SIKEsk);
if (rc != OQS_SUCCESS)
{
return rc;
}
#ifdef DEBUG
int i = OQS_KEM_sike_p751_length_public_key;
printf("pqnist_keys SIKEpklen %d SIKEpk: ", i);
amcl_print_hex(SIKEpk, i);
i = OQS_KEM_sike_p751_length_secret_key;
printf("pqnist_keys SIKE sklen %d SIKEsk: ", i);
amcl_print_hex(SIKEsk, i);
printf("\n");
#endif
return 0;
}
/* The message is encrypted using AES-256. The key
is generated inside this function as an output
from the encapsulation function.
*/
int pqnist_encapsulate_encrypt(char* P, int Plen, char* IV, char* pk, char* ek)
{
// AES-256 key
uint8_t K[OQS_KEM_sike_p751_length_shared_secret];
#ifdef DEBUG
printf("Plaintext %d P: ", Plen);
amcl_print_hex(P, Plen);
int i = OQS_KEM_sike_p751_length_public_key;
printf("pklen %d pk: ", i);
amcl_print_hex(pk, i);
#endif
OQS_STATUS rc = OQS_KEM_sike_p751_encaps(ek, K, pk);
if (rc != OQS_SUCCESS)
{
OQS_MEM_cleanse(K, OQS_KEM_sike_p751_length_shared_secret);
return rc;
}
#ifdef DEBUG
i = OQS_KEM_sike_p751_length_ciphertext;
printf("ek1 %d ek1: ", i);
amcl_print_hex(ek, i);
i = OQS_KEM_sike_p751_length_shared_secret;
printf("K %d K: ", i);
amcl_print_hex(K, i);
#endif
// Encrypt plaintext
pqnist_aes_cbc_encrypt(K, PQNIST_AES_KEY_LENGTH, IV, P, Plen);
#ifdef DEBUG
printf("K: ");
amcl_print_hex(K, PQNIST_AES_KEY_LENGTH);
printf("IV: ");
amcl_print_hex((uint8_t*)IV, PQNIST_AES_IV_LENGTH);
// Ciphertext
printf("C: ");
amcl_print_hex((uint8_t*)P, Plen);
#endif
return 0;
}
/* Decapsulate the AES key and use it to decrypt the
ciphertext. The plaintext is returned using the C
parameter.
*/
int pqnist_decapsulate_decrypt(char* C, int Clen, char* IV, char* sk, char* ek)
{
char sec[OQS_KEM_sike_p751_length_shared_secret*2];
// Encapsulated secret is 24 byte therefore needs to be run twice to
// generate 32 byte AES Key
OQS_STATUS rc = OQS_KEM_sike_p751_decaps(sec, ek, sk);
if (rc != OQS_SUCCESS)
{
OQS_MEM_cleanse(sec, OQS_KEM_sike_p751_length_secret_key);
return rc;
}
#ifdef DEBUG
int i = OQS_KEM_sike_p751_length_shared_secret;
printf("sec1 %d sec1: ", i);
amcl_print_hex(sec, i);
printf("sec2 %d sec2: ", i);
amcl_print_hex(&sec[OQS_KEM_sike_p751_length_shared_secret], i);
#endif
// Decrypt the ciphertext
pqnist_aes_cbc_decrypt(sec, PQNIST_AES_KEY_LENGTH, IV, C, Clen);
return 0;
}
// AES encryption using GCM mode
void pqnist_aes_gcm_encrypt(char* K, int Klen, char* IV, int IVlen, char* A, int Alen, char* P, int Plen, char* C, char* T)
{
gcm g;
GCM_init(&g,Klen,K,IVlen,IV);
GCM_add_header(&g,A,Alen);
GCM_add_plain(&g,C,P,Plen);
GCM_finish(&g,T);
}
// AES Decryption using GCM mode
void pqnist_aes_gcm_decrypt(char* K, int Klen, char* IV, int IVlen, char* A, int Alen, char* C, int Clen, char* P, char* T)
{
gcm g;
GCM_init(&g,Klen,K,IVlen,IV);
GCM_add_header(&g,A,Alen);
GCM_add_cipher(&g,P,C,Clen);
GCM_finish(&g,T);
}
// AES encryption using CBC mode
void pqnist_aes_cbc_encrypt(char* K, int Klen, char* IV, char* P, int Plen)
{
#ifdef DEBUG
printf("pqnist_aes_cbc_encrypt Klen %d K: \n", Klen);
amcl_print_hex(K, Klen);
printf("pqnist_aes_cbc_encrypt IVlen %d IV: \n", PQNIST_AES_IV_LENGTH);
amcl_print_hex(IV, PQNIST_AES_IV_LENGTH);
printf("pqnist_aes_cbc_encrypt Plen %d P: \n", Plen);
amcl_print_hex(P, Plen);
#endif
int blockSize=16;
amcl_aes a;
AES_init(&a,CBC,Klen,K,IV);
for (int i=0; i<(Plen/blockSize); i++)
{
AES_encrypt(&a,&P[i*blockSize]);
}
#ifdef DEBUG
printf("pqnist_aes_cbc_encrypt Clen %d C: \n", Plen);
amcl_print_hex(P, Plen);
#endif
}
// AES decryption using CBC mode
void pqnist_aes_cbc_decrypt(char* K, int Klen, char* IV, char* C, int Clen)
{
#ifdef DEBUG
printf("pqnist_aes_cbc_decrypt Klen %d K: \n", Klen);
amcl_print_hex(K, Klen);
printf("pqnist_aes_cbc_decrypt IVlen %d IV: \n", PQNIST_AES_IV_LENGTH);
amcl_print_hex(IV, PQNIST_AES_IV_LENGTH);
printf("pqnist_aes_cbc_decrypt Clen %d C: \n", Clen);
amcl_print_hex(C, Clen);
#endif
int blockSize=16;
amcl_aes a;
AES_init(&a,CBC,Klen,K,IV);
for (int i=0; i<(Clen/blockSize); i++)
{
AES_decrypt(&a,&C[i*blockSize]);
}
#ifdef DEBUG
printf("pqnist_aes_cbc_decrypt Plen %d P: \n", Clen);
amcl_print_hex(C, Clen);
#endif
}