Skip to content

Commit

Permalink
Add a native wrapper for Key Agreements - DH & EC
Browse files Browse the repository at this point in the history
  • Loading branch information
pushkarnk committed Sep 27, 2023
1 parent f6046c3 commit a68b000
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 2 deletions.
6 changes: 6 additions & 0 deletions Makefile
Expand Up @@ -2,10 +2,12 @@ build:
@mkdir -p build/bin && cc -I/usr/local/include/openssl/ -I./include -c -fPIC src/drbg.c -o build/bin/drbg.o && \
cc -I/usr/local/include/openssl/ -I./include -c -fPIC src/init.c -o build/bin/init.o && \
cc -I/usr/local/include/openssl/ -I./include -c -fPIC src/cipher.c -o build/bin/cipher.o && \
cc -I/usr/local/include/openssl/ -I./include -c -fPIC src/keyagreement.c -o build/bin/keyagreement.o && \
cc -shared -fPIC -Wl,-soname,libjssl.so -o build/bin/libjssl.so \
build/bin/init.o \
build/bin/drbg.o \
build/bin/cipher.o \
build/bin/keyagreement.o \
-L/usr/local/lib64 -lcrypto -lssl

test-drbg: build
Expand All @@ -15,5 +17,9 @@ test-drbg: build
test-cipher: build
@mkdir -p build/test && cc -I./include/ -L./build/bin/ -o build/test/cipher_test test/cipher_test.c -ljssl && \
build/test/cipher_test 2>/dev/null

test-ka: build
@mkdir -p build/test && cc -I./include/ -L./build/bin/ -o build/test/keyagreement test/keyagreement.c -ljssl && \
build/test/keyagreement 2>/dev/null
clean:
@rm -rf build
4 changes: 2 additions & 2 deletions include/jssl.h
Expand Up @@ -8,5 +8,5 @@ OSSL_LIB_CTX* load_openssl_fips_provider(const char*);
#define MIN(a, b) (a > b ? b : a)
#define IS_NULL(a) (NULL == (void *)a)

/* Lets use 'byte' instead of 'char' */
typedef char byte;
/* Lets use 'byte' instead of 'unsigned char' */
typedef unsigned char byte;
45 changes: 45 additions & 0 deletions include/keyagreement.h
@@ -0,0 +1,45 @@
#include "jssl.h"
#include <openssl/evp.h>

typedef enum key_agreement_algorithm {
DIFFIE_HELLMAN, // Diffie-Hellman
ELLIPTIC_CURVE // Elliptic-Curve
} key_agreement_algorithm;

typedef struct shared_secret {
byte *bytes;
int length;
} shared_secret;

typedef struct key_agreement {
OSSL_LIB_CTX *libctx;
key_agreement_algorithm algorithm;
EVP_PKEY *private_key;
EVP_PKEY *peer_public_key;
shared_secret *secret;
} key_agreement;

typedef struct key_pair {
EVP_PKEY *key;
//EVP_PKEY_CTX *ctx;
} key_pair;

key_pair *generate_key(key_agreement_algorithm algo);

key_agreement* init_key_agreement(key_agreement_algorithm algo, OSSL_LIB_CTX *libctx);

void set_private_key(key_agreement *agreement, key_pair *private_key);

void set_peer_key(key_agreement *agreement, key_pair *peer_public_key);

shared_secret *generate_shared_secret(key_agreement *agreement);

int get_shared_secret_bytes(key_agreement *agreement, byte secret[]);

key_pair *generate_key(key_agreement_algorithm algo);

void free_key_agreement(key_agreement *this);

void free_shared_secret(shared_secret *this);

void free_key_pair(key_pair *this);
115 changes: 115 additions & 0 deletions src/keyagreement.c
@@ -0,0 +1,115 @@
#include "keyagreement.h"

key_agreement* init_key_agreement(key_agreement_algorithm algo, OSSL_LIB_CTX *libctx) {
key_agreement agreement = {0};
key_agreement *new_agreement = (key_agreement*)malloc(sizeof(key_agreement));
*new_agreement = agreement;
new_agreement->algorithm = algo;
new_agreement->libctx = libctx;
}

void set_private_key(key_agreement *agreement, key_pair *private_key) {
agreement->private_key = private_key->key;
}

void set_peer_key(key_agreement *agreement, key_pair *peer_public_key) {
agreement->peer_public_key = peer_public_key->key;
}

shared_secret *generate_shared_secret(key_agreement *agreement) {
if (agreement->private_key == NULL || agreement->peer_public_key == NULL) {
return NULL;
}

EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(agreement->libctx, agreement->private_key, NULL);
if (ctx == NULL) {
return NULL;
}

if (EVP_PKEY_derive_init(ctx) <= 0) {
return NULL;
}

if (EVP_PKEY_derive_set_peer(ctx, agreement->peer_public_key) <= 0) {
return NULL;
}

size_t secret_length = 0;
if (EVP_PKEY_derive(ctx, NULL, &secret_length) <= 0) {
return NULL;
}

byte *secret_bytes = OPENSSL_malloc(secret_length);

if (secret_bytes == NULL) {
return NULL;
}

if (EVP_PKEY_derive(ctx, secret_bytes, &secret_length) <= 0) {
return NULL;
}

shared_secret *secret = (shared_secret*)malloc(sizeof(shared_secret));
secret->bytes = secret_bytes;
secret->length = secret_length;
agreement->secret = secret;
return secret;
}

int get_shared_secret(key_agreement *agreement, byte secret[]) {
if (secret != NULL) {
memcpy(secret, agreement->secret->bytes, agreement->secret->length);
}
return agreement->secret->length;
}

key_pair *generate_key(key_agreement_algorithm algo) {
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *key = NULL;
OSSL_PARAM params[2];
if (algo == DIFFIE_HELLMAN) {
if(NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL))) {
return NULL;
}
params[0] = OSSL_PARAM_construct_utf8_string("group", "ffdhe2048", 0);
params[1] = OSSL_PARAM_construct_end();
} else {
if(NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) {
return NULL;
}
params[0] = OSSL_PARAM_construct_utf8_string("group", "prime256v1", 0);
params[1] = OSSL_PARAM_construct_end();
}

if(EVP_PKEY_keygen_init(pctx) <= 0) {
return NULL;
}

EVP_PKEY_CTX_set_params(pctx, params);

if(EVP_PKEY_keygen(pctx, &key) <= 0) {
return NULL;
}
key_pair *new_key = (key_pair*) malloc(sizeof(key_pair));
new_key->key = key;
return new_key;
}

void free_shared_secret(shared_secret *this) {
free(this->bytes);
free(this);
}

void free_key_agreement(key_agreement *this) {
EVP_PKEY_free(this->private_key);
EVP_PKEY_free(this->peer_public_key);
free_shared_secret(this->secret);
free(this);
}

void free_key_pair(key_pair *this) {
EVP_PKEY_free(this->key);
free(this);
}


51 changes: 51 additions & 0 deletions test/keyagreement.c
@@ -0,0 +1,51 @@
#include "jssl.h"
#include "keyagreement.h"

int compare(shared_secret *s1, shared_secret *s2) {
if (s1 == NULL || s2 == NULL) return 0;

if (s1->length != s2->length) return 0;

for(int i = 0; i < s1->length; i++) {
if (s1->bytes[i] != s2->bytes[i]) return 0;
}

return 1;
}

void test(key_agreement_algorithm algo, OSSL_LIB_CTX *libctx) {
switch(algo) {
case DIFFIE_HELLMAN: printf("Testing DIFFIE_HELLMAN key-agreement: "); break;
case ELLIPTIC_CURVE: printf("Testing ELLIPTIC_CURVE key-agreement: "); break;
}

shared_secret *alice_secret, *bob_secret;

key_pair *alice_key = generate_key(algo);
key_pair *bob_key = generate_key(algo);

key_agreement *alice = init_key_agreement(algo, libctx);
set_private_key(alice, alice_key);
set_peer_key(alice, bob_key);
alice_secret = generate_shared_secret(alice);


key_agreement *bob = init_key_agreement(algo, libctx);
set_private_key(bob, bob_key);
set_peer_key(bob, alice_key);
bob_secret = generate_shared_secret(bob);

if (compare(alice_secret, bob_secret)) {
printf(" PASSED\n");
}

free_key_agreement(alice);
free_key_agreement(bob);
}

int main(int argc, char *argv[]) {
OSSL_LIB_CTX *libctx = load_openssl_fips_provider("/usr/local/ssl/openssl.cnf");
test(DIFFIE_HELLMAN, libctx);
test(ELLIPTIC_CURVE, libctx);
}

0 comments on commit a68b000

Please sign in to comment.