Commit fdc84ad3 authored by manastasova's avatar manastasova
Browse files

Add all tests for derandomized qhkex

parent e6c75026
Loading
Loading
Loading
Loading

Makefile

0 → 100644
+136 −0
Original line number Diff line number Diff line
# Makefile for ETSI TS 103 744

# Detect the operating system
UNAME_S := $(shell uname -s)

# Compiler and flags
CC := gcc
CFLAGS := -Wall
LDFLAGS := -lcrypto -loqs

# Directories
WORKSPACE := $(shell pwd)/quantumsafe
BUILD_DIR := $(WORKSPACE)/build
LIB_DIR := $(BUILD_DIR)/lib
SRC_DIR := $(shell pwd)
OBJ_DIR := $(shell pwd)/obj
BIN_DIR := $(shell pwd)/bin

# Source and object files
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

# Target executable
TARGET := $(BIN_DIR)/etsi-hkex-test

# Dependencies
DEPS := openssl liboqs oqs-provider

# Phony targets
.PHONY: all update install setup openssl liboqs oqs-provider test-oqs update-ldconfig compile update-ldconfig clean
#

# Default target
all: update install setup openssl liboqs oqs-provider test-oqs compile run
# all: update install setup openssl liboqs oqs-provider test-oqs compile 


# Update and install necessary packages (OS-specific)
update:
ifeq ($(UNAME_S),Linux)
	sudo apt update
	sudo apt -y install git build-essential perl cmake autoconf libtool zlib1g-dev
else ifeq ($(UNAME_S),Darwin)
	brew update
	brew install git cmake autoconf automake libtool
endif

# Setup workspace and build directory
setup:
	mkdir -p $(LIB_DIR)

# Clone and build OpenSSL
openssl:
	@if [ ! -d $(WORKSPACE)/openssl ]; then \
		echo "Cloning and building OpenSSL..."; \
		cd $(WORKSPACE) && \
		git clone -b openssl-3.2 https://github.com/openssl/openssl && \
		cd openssl && \
		./Configure \
 			--prefix=$(BUILD_DIR) \
  			no-ssl no-tls1 no-tls1_1 no-afalgeng \
  			no-shared threads -lm && \
        make && \
		echo "OpenSSL cloned and built successfully."; \
	else \
		echo "OpenSSL directory already exists. Skipping clone and build."; \
	fi

# Clone and build liboqs
liboqs:
	@if [ ! -d $(WORKSPACE)/liboqs ]; then \
		echo "Cloning and building liboqs..."; \
		cd $(WORKSPACE) && \
		git clone https://github.com/open-quantum-safe/liboqs  && \
		cd liboqs  && \
		git checkout 0.13.0-release && \
		mkdir build && cd build  && \
		cmake \
			-DBUILD_SHARED_LIBS=ON \
			-DOQS_USE_OPENSSL=OFF \
			-DCMAKE_BUILD_TYPE=Release \
			-DOQS_BUILD_ONLY_LIB=ON \
			-DOQS_DIST_BUILD=ON \
			..   && \
		make  && \
		echo "liboqs cloned and built successfully."; \
	else \
		echo "liboqs directory already exists. Skipping clone and build."; \
	fi

# Clone and build oqs-provider
oqs-provider:
	@if [ ! -d $(WORKSPACE)/oqs-provider ]; then \
		echo "Cloning and building oqs-provider..." ; \
		cd $(WORKSPACE) && \
		git clone https://github.com/open-quantum-safe/oqs-provider  && \
		cd oqs-provider && \
		git checkout 0.7.0-release && \
		liboqs_DIR=$(BUILD_DIR) cmake \
			-DOPENSSL_ROOT_DIR=$(WORKSPACE)/openssl/ \
			-DCMAKE_BUILD_TYPE=Release \
			-S . \
			-B $(BUILD_DIR)  && \
		sudo cmake --build $(BUILD_DIR) ; \
		echo "oqs-provider cloned, built, and configured successfully."; \
	else \
		echo "oqs-provider directory already exists. Skipping clone and build."; \
	fi

# Test OQS provider
test-oqs:
	@echo "Testing OQS provider..."
	@export OPENSSL_MODULES=$(BUILD_DIR)/lib && openssl list -kem-algorithms -provider oqsprovider

# Compile the project
compile:
	@echo "Compiling the project..."
	gcc -Wall -o etsi-hkex-test main.c crypto.c qshkex.c -lcrypto -loqs \
		-I$(WORKSPACE)/liboqs/build/include/ \
		-L$(BUILD_DIR)/lib
	@echo "Compilation completed. Executable: etsi-hkex-test"


# Run the compiled program
run: compile
	@echo "Running etsi-hkex-test..."
ifeq ($(UNAME_S),Linux)
	@export OPENSSL_MODULES=$(BUILD_DIR)/lib  && ./etsi-hkex-test
else ifeq ($(UNAME_S),Darwin)
	@DYLD_LIBRARY_PATH=$(BUILD_DIR)/lib:$$DYLD_LIBRARY_PATH ./etsi-hkex-test
endif

# Clean up
clean:
	rm -rf $(WORKSPACE)
	rm -f etsi-hkex-test

crypto.c

0 → 100644
+210 −0
Original line number Diff line number Diff line
/*
    This file implements ETSI TC CYBER QSC Quantum-safe Hybrid Key Exchanges
    (Version 1.1.1)

    This is not intended for production use.  It is intended to be a reference
    implementation for test vectors for the specification.

    It uses OpenSSL version 3.4.0 libcrypto.

    gcc -Wall -o etsi-hkex-test main.c crypto.c qshkex.c -lcrypto -loqs
    ./etsi-hkex-test

    Copyright 2020 ETSI. All rights reserved
    SPDX-License-Identifier: BSD-3-Clause
*/

#include "crypto.h"
#include "qshkex.h"

#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/provider.h>
#include <openssl/err.h>

#include <oqs/oqs.h>
#include <oqs/rand.h>

// Custom deterministic RNG function
void deterministic_randombytes(unsigned char *random_array, size_t bytes_to_generate) 
{   
    uint32_t out_len = SEED_LEN_BYTES;
    ascii_hex_strings_to_uint8(random_array, &out_len, 1, deterministic_seed[current_seed_index]);
    if (out_len != bytes_to_generate) {
        return;
    }
    current_seed_index++;
}

int test_qhkex_derand_ecdh(const int curve, const char *priv_dataA, const char *peerB, uint8_t *pubA, size_t *PA1length, uint8_t *pubB, size_t *PB1length, uint8_t *ss, uint32_t *ss_len)
{
    int            rval = FAILURE;
    BIGNUM         *privA = NULL, *x = NULL;
    EC_POINT       *peer_pointB = NULL, *shared_secret_point = NULL, *pub_keyA = NULL;
    EC_GROUP       *groupA = NULL;
    EVP_PKEY_CTX   *ctxA = NULL;
    EVP_PKEY       *pkeyA = NULL, *pkeyB = NULL;
    size_t         field_len, ss_lenA;
    uint8_t        shared_secretA[X448_KEY_LEN_BYTES];
    uint8_t        hex_private_keyA[X448_KEY_LEN_BYTES];
    uint8_t        pubA_cpy[MAX_KEY_BYTE_LEN], pubB_cpy[MAX_KEY_BYTE_LEN];
    uint8_t        hex_exp_shared[MAX_KEY_BYTE_LEN];

    do {
       if (curve == EVP_PKEY_X25519 || curve == EVP_PKEY_X448) {
            field_len = X25519_KEY_LEN_BYTES;
            if (curve == EVP_PKEY_X448) {
                field_len = X448_KEY_LEN_BYTES;
            }
            for (int i = 0; i < field_len; i++) {
                sscanf(&priv_dataA[i * 2], "%2hhx", &hex_private_keyA[i]);
            }
            if (!(pkeyA = EVP_PKEY_new_raw_private_key(curve, NULL, hex_private_keyA, field_len))) {
                break;
            }
            if (EVP_PKEY_get_raw_public_key(pkeyA, pubA, &field_len) <= 0) {
                break;
            }
            *PA1length = field_len;
            for (int i = 0; i < field_len; i++) {
                sscanf(&peerB[i * 2], "%2hhx", &pubB[i]);
            }
            if(!(pkeyB = EVP_PKEY_new_raw_public_key(curve, NULL, pubB, field_len))) {
                break;
            }
            *PB1length = field_len;
            if (!(ctxA = EVP_PKEY_CTX_new(pkeyA, NULL))) {
                break;
            }
            if (EVP_PKEY_derive_init(ctxA) <= 0) {
                break;
            }
            if (EVP_PKEY_derive_set_peer(ctxA, pkeyB) <= 0) {
                break;
            }
            ss_lenA = field_len;
            if (EVP_PKEY_derive(ctxA, shared_secretA, &ss_lenA) <= 0) {
                break;
            }
            memcpy(ss, shared_secretA, ss_lenA); 
            *ss_len = ss_lenA;
            ascii_hex_strings_to_uint8(hex_exp_shared, (uint32_t *)&field_len, 1, strk1[current_seed_index/2]);
            if (memcmp(ss, hex_exp_shared, field_len) != 0) {
                    break;
            }
            rval = SUCCESS;
        } else {
            if (BN_hex2bn(&privA, priv_dataA) <= 0) {
                break;
            }
            if (!(groupA = EC_GROUP_new_by_curve_name(curve))) {
                break;
            }
            if (!(pub_keyA = EC_POINT_new(groupA))) {
                break;
            }
            if (!EC_POINT_mul(groupA, pub_keyA, privA, NULL, NULL, NULL)) {
                break;
            }
            if (!EC_POINT_point2oct(groupA, pub_keyA, POINT_CONVERSION_UNCOMPRESSED, pubA_cpy, MAX_KEY_BUF_BYTES, NULL)) {
                break;
            }
            if (!(peer_pointB = EC_POINT_hex2point(groupA, peerB, NULL, NULL))) {
                break;
            }
            if (!EC_POINT_point2oct(groupA, peer_pointB, POINT_CONVERSION_UNCOMPRESSED, pubB_cpy, MAX_KEY_BUF_BYTES, NULL)) {
                break;
            }
            if (!(shared_secret_point = EC_POINT_new(groupA))) {
                break;
            }
            if (!EC_POINT_mul(groupA, shared_secret_point, NULL, peer_pointB, privA, NULL)) {
                break;
            }
            if (!(x = BN_new())) {
                break;
            }
            if (!EC_POINT_get_affine_coordinates(groupA, shared_secret_point, x, NULL,  NULL)) {
                break;
            }
            if (!(field_len = EC_GROUP_get_degree(groupA)/8)) {
                break;
            }
            memcpy(pubA, pubA_cpy + 1, field_len*2);
            *PA1length = field_len*2;
            memcpy(pubB, pubB_cpy + 1, field_len*2);
            *PB1length = field_len*2;
            BN_bn2bin(x, ss);
            *ss_len = field_len;
            ascii_hex_strings_to_uint8(hex_exp_shared, (uint32_t *)&field_len, 1, strk1[current_seed_index/2]);
            if (memcmp(ss, hex_exp_shared, field_len) != 0) {
                    break;
            }
            rval = SUCCESS;
            }   
    } while (0);
    if (privA) {
        BN_free(privA);
    }
    if (x) {
        BN_free(x);
    }
    if (peer_pointB) {
        EC_POINT_free(peer_pointB);
    }
    if (shared_secret_point) {
        EC_POINT_free(shared_secret_point);
    }
    if (pub_keyA) {
        EC_POINT_free(pub_keyA);
    }
    if (groupA) {
        EC_GROUP_free(groupA);
    }
    if (ctxA) {
        EVP_PKEY_CTX_free(ctxA);
    }
    if (pkeyA) {
        EVP_PKEY_free(pkeyA);
    }
    if (pkeyB) {
        EVP_PKEY_free(pkeyB);
    }
    return rval;
}

int test_qhkex_derand_mlkem(const char * alg_name, uint8_t *pubA, size_t *PA2length, uint8_t *ctB, size_t *CTB2length, uint8_t *ss, uint32_t *ss_len)
{
    int       rval = FAILURE;
    OQS_KEM   *kem;
    uint8_t   sk[OQS_KEM_ml_kem_1024_length_secret_key], sharedB[OQS_KEM_ml_kem_1024_length_shared_secret], hex_exp_shared[OQS_KEM_ml_kem_1024_length_shared_secret];
    
    do {
        OQS_randombytes_custom_algorithm(deterministic_randombytes);
        if (!(kem = OQS_KEM_new(alg_name))) {
            break;
        }
        if (OQS_KEM_keypair(kem, pubA, sk) != OQS_SUCCESS) {
            break;
        }
        *PA2length = kem->length_public_key;
        if (OQS_KEM_encaps(kem, ctB, ss, pubA) != OQS_SUCCESS) {
            break;
        }
        *CTB2length = kem->length_ciphertext;
        if (OQS_KEM_decaps(kem, sharedB, ctB, sk) != OQS_SUCCESS) {
            break;
        }
        *ss_len = OQS_KEM_ml_kem_1024_length_shared_secret;
        ascii_hex_strings_to_uint8(hex_exp_shared, ss_len, 1, strk2[current_seed_index/2 - 1]);
        if (memcmp(ss, sharedB, kem->length_shared_secret) != 0 || 
            memcmp(ss, hex_exp_shared, kem->length_shared_secret) != 0) {
                break;
        }
        rval = SUCCESS;
        } while (0);
        if (kem) {
            OQS_KEM_free(kem);
        }
    return rval;
}
 No newline at end of file

crypto.h

0 → 100644
+35 −0
Original line number Diff line number Diff line
/*
    Header file for a reference implementation of
    ETSI TC CYBER QSC Quantum-safe Hybrid Key Exchanges (Version 1.1.1)

    This is not intended for production use.  It is intended to be a reference
    implementation for test vectors for the specification.

    Copyright 2020 ETSI. All rights reserved
    SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef _QS_H_CRYPTO_KEX_H_
#define _QS_H_CRYPTO_KEX_H_

#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include "qshkex.h"

#define SEED_LEN_BYTES             64
#define X25519_KEY_LEN_BYTES       32
#define X448_KEY_LEN_BYTES         56
#define MAX_KEY_BUF_BYTES          128

extern int current_seed_index;
extern const char *deterministic_seed[];
extern const char *strk1[];
extern const char *strk2[];

int test_qhkex_derand_ecdh(const int curve, const char *priv_dataA, const char *peerB, 
                        uint8_t *pubA, size_t *PA1length, uint8_t *pubB, size_t *PB1length, 
                        uint8_t *ss, uint32_t *ss_len);
int test_qhkex_derand_mlkem(const char * alg_name, uint8_t *pubA, size_t *PA2length, 
                        uint8_t *ctB, size_t *CTB2length, uint8_t *ss, uint32_t *ss_len);
#endif /*_QS_H_CRYPTO_KEX_H_*/
+805 −18

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#include <openssl/crypto.h>

/* Memory helper functions to handle null values */
static inline void *my_memcpy(void *dst, const void *src, size_t byte_len)
void *my_memcpy(void *dst, const void *src, size_t byte_len)
{
    if (src == NULL || dst == NULL) {
        return dst;
Loading