test-dh/dh.c
2024-11-11 18:41:18 +01:00

192 lines
4.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <openssl/bn.h>
#include <string.h>
#include "dh.h"
// gcc -Wall -o dh dh.c -lcrypto && ./dh
static int generatePrimeNumber(unsigned long long int p){
for (int i = 2; i < p; i++){
if ((unsigned long long int)p % i == 0)
return 1;
}
return 0;
}
static BIGNUM *generatePrivateKey(){
BIGNUM *bn = NULL;
char n[CHAR_SIZE];
unsigned long long int r = rand() % (PRIVATEKEY_MAX - PRIVATEKEY_MIN) + PRIVATEKEY_MIN;
sprintf(n, "%lld", r);
BN_dec2bn(&bn, n);
return bn;
}
static void dumpBN(const char *s, BIGNUM *bn){
char *n = BN_bn2dec(bn);
printf("%s: %s\n", s, n);
OPENSSL_free(n);
}
static int combineKey(BIGNUM **pubKey, BIGNUM *e, BIGNUM *x, BIGNUM *bnP, BN_CTX *ctx){
if (ctx == NULL)
ctx = BN_CTX_new();
if (*pubKey == NULL)
*pubKey = BN_new();
BIGNUM *exp = BN_new();
int res = BN_exp(exp, e, x, ctx);
//dumpBN("publicKey", exp);
if (res == 0){
BN_free(exp);
return 0;
}
res = BN_mod(*pubKey, exp, bnP, ctx);
BN_free(exp);
return 1;
}
static BIGNUM *generateP(){
BIGNUM *bnP = NULL;
unsigned long long int p = rand() % (500 - 200) + 500;
char nP[CHAR_SIZE];
int res = 0;
// First, we need to find a prime number of p
while (!generatePrimeNumber(p++));
sprintf(nP, "%lld", p);
res = BN_dec2bn(&bnP, nP);
if (res == 0)
return NULL;
return bnP;
}
static int charToDec(const char *s){
int dec = 0;
size_t l = strlen(s);
int pos = 1;
for (int i = 0; i < l; i++){
dec += (s[i] - '0') * pos;
pos *= 10;
}
return dec;
}
static BIGNUM *generateG(const char *nP){
BIGNUM *bnG = NULL;
char nG[CHAR_SIZE];
int res = 0;
int p = charToDec(nP); // Convert char* to int
unsigned long long int g = rand() % (p - 1);
sprintf(nG, "%lld", g);
res = BN_dec2bn(&bnG, nG);
if (res == 0)
return NULL;
return bnG;
}
static void cleanDH(struct bn_dh *dh){
if (dh->bnPrivateKey != NULL)
BN_free(dh->bnPrivateKey);
if (dh->bnPublicKey != NULL)
BN_free(dh->bnPublicKey);
if (dh->bnPublicKeyPeer != NULL)
BN_free(dh->bnPublicKeyPeer);
if (dh->bnPublicEphemeralKey != NULL)
BN_free(dh->bnPublicEphemeralKey);
if (dh->ctx != NULL)
BN_CTX_free(dh->ctx);
}
int main(void){
char *nP;
struct bn_dh dhA = {NULL};
struct bn_dh dhB = {NULL};
BIGNUM *bnP, *bnG = NULL;
// Init rand()
srand(time(NULL));
// First, we need to generate p, a prime number
bnP = generateP();
if (bnP == NULL)
exit(-1);
// Generate g, g must be between 1 and p - 1
nP = BN_bn2dec(bnP);
bnG = generateG(nP);
if (bnG == NULL){
cleanDH(&dhA);
cleanDH(&dhB);
BN_free(bnP);
exit(-1);
}
OPENSSL_free(nP);
dumpBN("p", bnP);
dumpBN("g", bnG);
// We generate the private key for both A and B
dhA.bnPrivateKey = generatePrivateKey();
if (dhA.bnPrivateKey == NULL){
cleanDH(&dhA);
cleanDH(&dhB);
BN_free(bnP);
BN_free(bnG);
exit(-1);
}
// Generate private keyB
dhB.bnPrivateKey = generatePrivateKey();
if (dhB.bnPrivateKey == NULL){
cleanDH(&dhA);
cleanDH(&dhB);
BN_free(bnP);
BN_free(bnG);
exit(-1);
}
dumpBN("Private keyA", dhA.bnPrivateKey);
dumpBN("Private keyB", dhB.bnPrivateKey);
// We are going to combine keys
combineKey(&dhA.bnPublicKey, bnG, dhA.bnPrivateKey, bnP, dhA.ctx);
dumpBN("Public keyA", dhA.bnPublicKey);
combineKey(&dhB.bnPublicKey, bnG, dhB.bnPrivateKey, bnP, dhB.ctx);
dumpBN("Public keyB", dhB.bnPublicKey);
// Send public key to the other
dhA.bnPublicKeyPeer = BN_new();
dhB.bnPublicKeyPeer = BN_new();
if(BN_copy(dhA.bnPublicKeyPeer, dhB.bnPublicKey) == NULL) {
printf("Failed to copy the public key\n");
cleanDH(&dhA);
cleanDH(&dhB);
BN_free(bnP);
BN_free(bnG);
}
if(BN_copy(dhB.bnPublicKeyPeer, dhA.bnPublicKey) == NULL){
printf("Failed to copy the public key\n");
cleanDH(&dhA);
cleanDH(&dhB);
BN_free(bnP);
BN_free(bnG);
}
// For the ephemeral shared key: public keyB ** private keyA % p
combineKey(&dhA.bnPublicEphemeralKey, dhA.bnPublicKeyPeer, dhA.bnPrivateKey, bnP, dhA.ctx);
dumpBN("Public ephemeral keyA", dhA.bnPublicEphemeralKey);
combineKey(&dhB.bnPublicEphemeralKey, dhB.bnPublicKeyPeer, dhB.bnPrivateKey, bnP, dhB.ctx);
dumpBN("Public ephemeral keyB", dhB.bnPublicEphemeralKey);
cleanDH(&dhA);
cleanDH(&dhB);
BN_free(bnP);
BN_free(bnG);
return 0;
}