commit 578ef21219a8a6fef74d686f4d4f2c7fe6b8d9d3 Author: geoffrey Date: Sat Jan 31 16:45:53 2026 +0100 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a43f9f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +**.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..2cb8bb2 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# CryptoDit +CryptoDit (short for Cryptography Audit). This program audit the cryptography modules. +- The program check the speed for generating RSA/ECDSA key +- Check if the RSA key are compliant with FIPS Key size, exponent, ownership, file permissions, etc.) +- Check the entropy pool in the kernel with the eBPF technology + +## Requirements +The program use the library of OpenSSL for reading a certificate and eBPF for the entropy module. It's important to install the following package: + +* libssl-dev. +* bpftool +* clang-11 +* libbpf-dev +* gcc and gcc-multilib + + +# Examples + +## Speed test +``` +$ ./cryptodit -m speed -type all +Module: speed +The generation of the RSA key 2048 bits took 116 ms +The generation of the RSA key 4192 bits took 2218 ms +The generation of the EC key secp256 took 1 ms +``` + +## RSA public key compliance + +``` +$ ./cryptodit -m certificate -type rsa -pubin public.pem +Module: certificate +File information + Filename: public.pem + File size: 182 + Permission: 644 + +Checking file ownerships compliance... +Audit passed with success. The owner of the file isn't root. + +Checking file permissions compliance... +The certificate has the correct permission for the owner. +The group has the permission to manipulate the file. Should be removed. +The other has the permission to manipulate the file. Should be removed. + +Checking FIPS compliance... +Certificate information: + Key size: 64 bytes (512) + Exponent: 65537 + Format RSA key: SPKI + +Exponent result: + The exponent is correct, the FIPS compliance is respected. +Keysize result: + The key size is lower than 2048. The key should be at least 2048 bits. +``` + +## X.509 compliance + +``` +$ ./cryptodit -m certificate -type x509 -pubin cert.pem +``` +## Entropy +``` +$ sudo ./cryptodit -m entropy +Module: entropy +libbpf: elf: skipping unrecognized data section(8) .rodata.str1.1 +proc: (openssl); pid: 85059 +proc: (WebExtensions); pid: 4520 +proc: (Privileged; pid: 4549 +proc: (Isolated; pid: 82753 +proc: (MainThread); pid: 85089 +proc: (tracker-extract); pid: 85188 +proc: (tracker-extract); pid: 85209 +proc: (terminator); pid: 8774 +proc: (python3); pid: 85231 +``` + diff --git a/argparse.c b/argparse.c new file mode 100644 index 0000000..5643d4b --- /dev/null +++ b/argparse.c @@ -0,0 +1,22 @@ +#include "argparse.h" + +/* + * This function check all arguments + * Return the 0 if success or 1 if failed +*/ +int check_arguments(char **args, const int len, char *buf_module, const size_t bufsize){ + int i; + int res = -1; + // Bypass the first arguments, because it's the script itself + for (i = 1; i < len; i++){ + // check if it's an option + if (args[i][0] == '-'){ + if (args[i][1] == 'm') { + // Get the module + strcpy(buf_module, args[i + 1]); + res = 0; + } + } + } + return res; +} diff --git a/argparse.h b/argparse.h new file mode 100644 index 0000000..1083181 --- /dev/null +++ b/argparse.h @@ -0,0 +1,9 @@ +#ifndef H_ARGPARSE +#define H_ARGPARSE + +#include +#include + +int check_arguments(char **, const int, char *, const size_t); + +#endif diff --git a/audit/audit.h b/audit/audit.h new file mode 100644 index 0000000..2b7c78c --- /dev/null +++ b/audit/audit.h @@ -0,0 +1,13 @@ +#ifndef H_AUDIT +#define H_AUDIT + +#define BUF_SIZE_AUDIT 256 +#define TRUE 0 +#define FALSE 1 + +struct st_audit{ + char result[BUF_SIZE_AUDIT]; + int audit; /* TRUE or FALSE */ +}; + +#endif diff --git a/audit/file.c b/audit/file.c new file mode 100644 index 0000000..898829d --- /dev/null +++ b/audit/file.c @@ -0,0 +1,114 @@ +#include +#include "file.h" +#include "audit.h" + +/* + * This function check the ownership of the file + * If the owner is root, the audit test fail + * Return the struct st_audit which contain the result + */ +struct st_audit ownership(uid_t uid, char *username, size_t len){ + struct st_audit st_audit; + get_username(uid, username); + if (strncmp(username, "root", 64) == 0){ + //printf("The %s account is not recommended. You should change the owner.\n", username); + char result[BUF_SIZE_AUDIT]; + sprintf(st_audit.result, "The account %s is not recommended. You should change the owner.", username); + st_audit.audit = FALSE; + } + else{ + //printf("The owner of the file is not root, it's recommended.\n"); + sprintf(st_audit.result, "Audit passed with success. The owner of the file isn't root."); + st_audit.audit = TRUE; + } + return st_audit; +} +/* + * This function check the permission of the file + * Return the struct st_audit which contain the result + * https://www.man7.org/linux/man-pages/man2/chmod.2.html + */ +void permission(mode_t mode, struct st_audit *st_audit_owner, struct st_audit *st_audit_group, struct st_audit *st_audit_other){ + + /* Owner */ + int irusr = mode & S_IRUSR; + int iwusr = mode & S_IWUSR; + int ixusr = mode & S_IXUSR; + if (irusr == 0 && iwusr == 0) { + sprintf(st_audit_owner->result, "Audit passed with success. Only the owner has the privilege to read/write the file."); + st_audit_owner->audit = TRUE; + } + else if (ixusr != 0){ + sprintf(st_audit_owner->result, "The file can be executabled for the owner. The permission should be removed."); + st_audit_owner->audit = FALSE; + } + else{ + sprintf(st_audit_owner->result, "The certificate has the correct permission for the owner."); + st_audit_owner->audit = TRUE; + } + + /* Group */ + int irgrp = mode & S_IRGRP; + int iwgrp = mode & S_IWGRP; + int ixgrp = mode & S_IXGRP; + if (irgrp != 0 || iwgrp != 0 || ixgrp != 0){ + sprintf(st_audit_group->result, "The group has the permission to manipulate the file. Should be removed."); + st_audit_group->audit = FALSE; + } + else + st_audit_group->audit = TRUE; + + /* Other */ + int iroth = mode & S_IROTH; + int iwoth = mode & S_IWOTH; + int ixoth = mode & S_IXOTH; + if (iroth != 0 || iwoth != 0 || ixoth != 0){ + sprintf(st_audit_other->result, "The other has the permission to manipulate the file. Should be removed."); + st_audit_other->audit = FALSE; + } + else + st_audit_other->audit = TRUE; +} +/* + * This function convert the mode_t value to human-readable value + */ +int convert_mode_t(mode_t mode){ + int perm = 0; + + /* Owner */ + if (mode & S_IRUSR) + perm += 400; + if (mode & S_IWUSR) + perm += 200; + if (mode & S_IXUSR) + perm += 100; + /* Group */ + if (mode & S_IRGRP) + perm += 40; + if (mode & S_IWGRP) + perm += 20; + if (mode & S_IXGRP) + perm += 10; + /* Other */ + if (mode & S_IROTH) + perm += 4; + if (mode & S_IWOTH) + perm += 2; + if (mode & S_IXOTH) + perm += 1; + + return perm; +} +/* + * This function retrieve the username from the uid_t passed in argument + */ +static void get_username(uid_t uid, char *username){ + struct passwd *p; + p = getpwuid(uid); + if (p == NULL){ + //printf("Failed to get the username from the UID\n"); + strncpy(username, "Unknown", 8); + return; + } + strncpy(username, p->pw_name, 64); +} diff --git a/audit/file.h b/audit/file.h new file mode 100644 index 0000000..988f917 --- /dev/null +++ b/audit/file.h @@ -0,0 +1,13 @@ +#ifndef H_FILE +#define H_FILE + +#include +#include +#include + +struct st_audit ownership(uid_t, char *, size_t); +void permission(mode_t, struct st_audit *, struct st_audit *, struct st_audit *); +int convert_mode_t(mode_t); +static void get_username(uid_t uid, char *); + +#endif diff --git a/audit/fips.c b/audit/fips.c new file mode 100644 index 0000000..a22ada2 --- /dev/null +++ b/audit/fips.c @@ -0,0 +1,455 @@ +#include +#include +#include "fips.h" +#include "../utils.h" +#include "../error.h" + +/* + * SSL Format + * RSA PUBLIC KEY -> PKCS#1 format + * PUBLIC KEY -> PEM Format + */ + +static int DEBUG = 0; + +int fips(const char *pkey, struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const int type, const int is_pubkey, const int to_stdout){ + int res; + + if(type == TYPE_RSA){ + /* If it's a pub key, we are going to analyse it */ + if (is_pubkey == 1) + res = fips_pubkey_rsa(st_audit_fips, st_keyinfo, pkey, to_stdout); + else + res = fips_privkey_rsa(st_audit_fips, st_keyinfo, pkey, to_stdout); + } + else if (type == TYPE_X509){ + if (openssl_version() == 1) + res = fips_x509_v1(st_audit_fips, st_keyinfo, pkey, to_stdout); + else + res = fips_x509_v3(st_audit_fips, st_keyinfo, pkey, to_stdout); + } + return res; +} +/* + * This function load public RSA key and make an audit on it + */ +static int fips_pubkey_rsa(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey, const int to_stdout) { + struct rsa *rsa; + size_t keysize; + int res; + + /* + * Now, we check if the public certificate is compliant with FIPS + * The program check the length of the key, the exponent + */ + if (openssl_version() == 1) + res = loadkeys_rsa_v1(&rsa, pkey, &st_keyinfo->format); + else /* OpenSSL version 3 */ + res = loadkeys_rsa_v3(&rsa, pkey, &st_keyinfo->format); + + if (res > 0 || rsa == NULL){ + printf("Failed to read the public key\n"); + clean_rsa_st(rsa); + return res; + } + + audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); + + // Clean + clean_rsa_st(rsa); + return 0; +} +/* + * This function audit RSA private key + */ +static int fips_privkey_rsa(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey, const int to_stdout) { + int res; + struct rsa *rsa = NULL; + + if (openssl_version() == 1) + res = load_priv_rsa_keys_v1(&rsa, pkey); + else /* OpenSSL version 3 */ + res = load_priv_rsa_keys_v3(&rsa, pkey); + + if (res > 0){ + printf("Failed to read the private key\n"); + clean_rsa_st(rsa); + return res; + } + + audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); + + // Clean + clean_rsa_st(rsa); + return 0; +} + +/* + * If OpenSSL v3, we need tu use new OpenSSL functions for reading keys + */ +static int loadkeys_rsa_v3(struct rsa **rsa, const char *pkey, int *format){ + *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); + + if (*rsa == NULL){ + if (DEBUG) + printf("Cannot malloc the structure\n"); + return COMMON_ERR_MALLOC; + } + + memset(*rsa, 0, sizeof(struct rsa*)); + + (*rsa)->bio = BIO_new(BIO_s_file()); + if (BIO_read_filename((*rsa)->bio, pkey) == 0){ + printf("Failed to read BIO\n"); + return FIPS_ERR_READ_BIO; + } + + #if OPENSSL_VERSION_NUMBER > 0x03000000f + (*rsa)->evp = PEM_read_bio_PUBKEY_ex((*rsa)->bio, NULL, NULL, NULL, NULL, NULL); + if ((*rsa)->evp == NULL){ + return FIPS_ERR_LOAD_KEY; + } + + //printf("Keysize: %d\n", EVP_PKEY_bits((*rsa)->evp)); + (*rsa)->rsa = EVP_PKEY_get1_RSA((*rsa)->evp); + if ((*rsa)->rsa == NULL){ + return FIPS_ERR_LOAD_RSA_KEY; + } + #endif + + // Get the format of the key + *format = 0; + return 0; +} +static int loadkeys_rsa_v1(struct rsa **rsa, const char *pkey, int *format){ + *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); + + if (*rsa == NULL){ + if (DEBUG) + printf("Cannot malloc the structure\n"); + return COMMON_ERR_MALLOC; + } + memset(*rsa, 0, sizeof(struct rsa*)); + + (*rsa)->bio = BIO_new(BIO_s_file()); + if(BIO_read_filename((*rsa)->bio, pkey) == 0){ + printf("Failed to read BIO\n"); + return FIPS_ERR_READ_BIO; + } + + /* + * Works with PEM_read_RSAPublicKey, but when we try to read the file + * we cannot. This function "block" the access to the file + */ + /*rsa->rsa = PEM_read_RSAPublicKey(f, NULL, NULL, NULL); */ + + // Deprecated in OpenSSL v3 + /* + * RSAPublicKey read publickey at the PEM format + * RSA_PUBKEY read publickey at the PKCS1 format + */ + (*rsa)->rsa = PEM_read_bio_RSAPublicKey((*rsa)->bio, NULL, NULL, NULL); + if ((*rsa)->rsa == NULL){ + //print_error(); + + /* + * We need to reset or reseek the BIO, otherwise, we cannot read it + * https://docs.openssl.org/3.0/man3/BIO_ctrl/#synopsis + */ + //BIO_reset((*rsa)->bio); /* Works too */ + BIO_seek((*rsa)->bio, 0); + + (*rsa)->rsa = PEM_read_bio_RSA_PUBKEY((*rsa)->bio, NULL, NULL,NULL); + + if ((*rsa)->rsa == NULL){ + if (DEBUG) + printf("Cannot read the SPKI format of the public key\n"); + return FIPS_ERR_LOAD_KEY; + } + + *format = RSA_FORMAT_SPKI; + } + else + *format = RSA_FORMAT_PKCS1; + + return 0; +} + +/* + * This function load RSA Private key for OpenSSL v1 + */ +static int load_priv_rsa_keys_v1(struct rsa **rsa, const char *pkey){ + *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); + + if (*rsa == NULL){ + if (DEBUG) + printf("Cannot malloc the structure\n"); + return COMMON_ERR_MALLOC; + } + + (*rsa)->bio = BIO_new(BIO_s_file()); + if ((*rsa)->bio == NULL){ + if (DEBUG) + printf("Failed to create new BIO\n"); + return FIPS_ERR_NEW_BIO; + } + if(BIO_read_filename((*rsa)->bio, pkey) == 0){ + printf("Failed to read BIO\n"); + return FIPS_ERR_READ_BIO; + } + + (*rsa)->rsa = PEM_read_bio_RSAPrivateKey((*rsa)->bio, NULL, NULL, NULL); + if ((*rsa)->rsa == NULL){ + if (DEBUG) + printf("Failed to read BIO RSAPrivateKey\n"); + return FIPS_ERR_LOAD_RSA_PRIV_KEY; + } + + return 0; +} +/* + * This function load RSA Private key for OpenSSL v3 + */ +static int load_priv_rsa_keys_v3(struct rsa **rsa, const char *pkey){ + *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); + + if (*rsa == NULL){ + if (DEBUG) + printf("Cannot malloc the structure\n"); + return COMMON_ERR_MALLOC; + } + + (*rsa)->bio = BIO_new(BIO_s_file()); + if ((*rsa)->bio == NULL){ + if (DEBUG) + printf("Failed to create new BIO\n"); + return FIPS_ERR_NEW_BIO; + } + if(BIO_read_filename((*rsa)->bio, pkey) == 0){ + printf("Failed to read BIO\n"); + return FIPS_ERR_READ_BIO; + } + + #if OPENSSL_VERSION_NUMBER > 0x03000000f + (*rsa)->evp = PEM_read_bio_PrivateKey_ex((*rsa)->bio, NULL, NULL, NULL, NULL, NULL); + + if ((*rsa)->evp == NULL){ + if (DEBUG) + printf("Failed to read BIO PrivateKey\n"); + return FIPS_ERR_READ_BIO; + } + (*rsa)->rsa = EVP_PKEY_get1_RSA((*rsa)->evp); + if ((*rsa)->rsa == NULL) + return FIPS_ERR_LOAD_RSA_KEY; + #endif + + return 0; +} + +/* + * This function audit the RSA keys, both public and private + * For the audit, the function check the exponent (modulus) and the key size + */ +static void audit_rsa_keys(struct rsa *rsa, struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey){ + int res; + + st_keyinfo->keysize = RSA_size(rsa->rsa); + + st_keyinfo->algo = ALGO_RSA; + + // The return value is a const, shouldn't be freed + const BIGNUM *e = RSA_get0_e(rsa->rsa); + char *exponent = BN_bn2dec(e); + //free(exponent); + OPENSSL_free(exponent); + + /* Exponent has been set up, we can check it */ + res = check_exponent(e, st_audit_fips->audit_exponent.result, &st_keyinfo->exponent); + + /* + * Audit the key size. For a better security, the key size is at least 2048 bits + */ + if (st_keyinfo->keysize * 8 < 2048){ + sprintf(st_audit_fips->audit_keysize.result, "The key size is lower than 2048. The key should be at least 2048 bits."); + st_audit_fips->audit_keysize.audit = FALSE; + } + else{ + sprintf(st_audit_fips->audit_keysize.result, "The key size is upper or equal than 2048. The audit is passed with success."); + st_audit_fips->audit_keysize.audit = TRUE; + } +} + +/* + * In this function, we are going to check the exponent + * For testing if the exponent is odd or even, we apply a modulo 2 on the exponent + * If the result is 1, means the key has a remainder and the key is odd, if the result is 0, the exponent is even. + * Regarding to the FIPS 186-5, the exponent must be odd. + * The function check also the size of the exponent. + * When the key has been generated with OpenSSL, by default the exponent is 65537. + * The exponent e size must be 2 ** 16 < e < 2 ** 256 + */ +static int check_exponent(const BIGNUM *e, char *buf, unsigned long *exponent){ + BIGNUM *rem = BN_new(), *a = BN_new(), *m = BN_new(); + char nExponent[4]; + BN_CTX *ctx; + char *r; + int error = 0; + + sprintf(nExponent, "%d", 2); + BN_dec2bn(&m, nExponent); + //BN_mod(rem, e, m); + ctx = BN_CTX_new(); + BN_div(NULL, rem, e, m, ctx); + //r = malloc(4); + r = BN_bn2dec(rem); + //printf("%s\n", r); + + /* + * According to the FIPS 186-5, the exponent size must be 2 ** 16 < e < 2 ** 256 + * The exponent must be odd too + */ + char *exp = BN_bn2dec(e); + *exponent = (char2dec(exp[0]) * 10000) + (char2dec(exp[1]) * 1000) + (char2dec(exp[2])* 100) + (char2dec(exp[3]) * 10) + (char2dec(exp[4])); + // printf("Exp: %lu\n", exp); + + if (strcmp(r, "0") == 0){ + strncpy(buf, "The exponent is even, should be odd", BUF_SIZE_AUDIT); + error += 1; + } + + // Check the exponent size + double minSize = pow(2, 16); + double maxSize = pow(2, 256); + if (*exponent < minSize || *exponent > maxSize){ + strncpy(buf, "The exponent size is not correct. The minimum size is 2 ** 16 and maximum size 2 ** 256.", BUF_SIZE_AUDIT); + error += 1; + } + + // If no error + if (error == 0) + strncpy(buf, "The exponent is correct, the FIPS compliance is respected.", BUF_SIZE_AUDIT); + + // Cleaning + free(r); + BN_free(rem); + BN_free(a); + BN_free(m); + BN_CTX_free(ctx); + OPENSSL_free(exp); + return 0; +} + +/* + * This function load X509 certificate for OpenSSL v1 + */ +static int fips_x509_v1(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey, const int to_stdout){ + + return 0; +} +/* + * This function load X509 certificate for OpenSSL v3 + */ +static int fips_x509_v3(struct audit_fips *st_audit_fips, struct keyinfo *st_keyinfo, const char *pkey, const int to_stdout){ + struct rsa *rsa = (struct rsa*)malloc(sizeof(struct rsa*)); + + if (rsa == NULL){ + if (DEBUG) + printf("Cannot malloc the structure\n"); + return COMMON_ERR_MALLOC; + } + memset(rsa, 0, sizeof(struct rsa*)); + + rsa->bio = BIO_new(BIO_s_file()); + if (BIO_read_filename(rsa->bio, pkey) == 0){ + printf("Failed to read BIO\n"); + return FIPS_ERR_READ_BIO; + } + + #if OPENSSL_VERSION_NUMBER > 0x03000000f + rsa->evp = NULL; // Otherwise, I have a seg fault during clean rsa st + + X509 *x = PEM_read_bio_X509(rsa->bio, NULL, 0, NULL); + if (x == NULL){ + printf("Failed to read the X509 certificate\n"); + clean_rsa_st(rsa); + return FIPS_ERR_LOAD_X509; + } + + rsa->evp = X509_get_pubkey(x); + if (rsa->evp == NULL){ + printf("Failed to get public certificate\n"); + X509_free(x); + return FIPS_ERR_LOAD_RSA_KEY; + } + rsa->rsa = EVP_PKEY_get1_RSA(rsa->evp); + if (rsa->rsa == NULL){ + X509_free(x); + return FIPS_ERR_LOAD_RSA_KEY; + } + #endif + + /* + * TODO: Need to identify public-key cryptosystem: RSA or EC + */ + + // We have the RSA key, we can audit it + audit_rsa_keys(rsa, st_audit_fips, st_keyinfo, pkey); + + #if OPENSSL_VERSION_NUMBER > 0x03000000f + X509_free(x); + #endif + clean_rsa_st(rsa); + return 0; +} + +/* + * This function clean the RSA structure + */ +static void clean_rsa_st(struct rsa *rsa){ + if (DEBUG) + printf("\nCleaning RSA\n"); + + if (rsa == NULL) + return; + + if (rsa->bio != NULL) + BIO_free(rsa->bio); + + if (openssl_version() == 3){ + #if OPENSSL_VERSION_NUMBER > 0x03000000f + if (rsa->evp != NULL) + EVP_PKEY_free(rsa->evp); + #endif + } + + if (rsa->rsa != NULL) + RSA_free(rsa->rsa); + + free(rsa); + rsa = NULL; +} + +/* + * Return 1 if the version is upper than 1 and less than 3 + * Return 3 for the version v3 + */ +static int openssl_version(){ + unsigned long version = OPENSSL_VERSION_NUMBER; + + if (DEBUG) + printf("OpenSSL Version: %lx\n", version); + if (version <= 0x03000000f) + return 1; + if (version >= 0x03000000f) + return 3; +} +/* + * In case we have an error with OpenSSL librairy, we can print the error message + */ +static void print_error(){ + unsigned long err = ERR_get_error(); + char b[256]; + ERR_error_string(err, b); + printf("%s\n", b); +} + diff --git a/audit/fips.h b/audit/fips.h new file mode 100644 index 0000000..d5764a1 --- /dev/null +++ b/audit/fips.h @@ -0,0 +1,62 @@ +#ifndef H_FIPS +#define H_FIPS + +#include +#include +#include +#include +#include +#include "audit.h" + +#define TYPE_RSA 0x01 +#define TYPE_X509 0x02 + +#define RSA_FORMAT_PKCS1 0x1 +#define RSA_FORMAT_SPKI 0x2 + +#define BUF_SIZE_RESULT 256 + +#define ALGO_RSA 0x01 +#define ALGO_EC 0x02 + +struct audit_fips{ + struct st_audit audit_keysize; + struct st_audit audit_exponent; +}; + +struct rsa{ + RSA *rsa; + BIO *bio; +#if OPENSSL_VERSION_NUMBER > 0x03000000f + EVP_PKEY *evp; +#endif +}; + +struct keyinfo{ + int keysize; + unsigned long exponent; + int format; + char *key; + int algo; +}; + +int fips(const char *, struct audit_fips *, struct keyinfo *, const int, const int, const int); +/* RSA */ +static int fips_pubkey_rsa(struct audit_fips *, struct keyinfo *, const char *, const int); +static int fips_privkey_rsa(struct audit_fips *, struct keyinfo *, const char *, const int); +static int loadkeys_rsa_v1(struct rsa **, const char *, int *format); +static int loadkeys_rsa_v3(struct rsa **, const char *, int *format); +static int load_priv_rsa_keys_v1(struct rsa **, const char *); +static int load_priv_rsa_keys_v3(struct rsa **, const char *); +static void audit_rsa_keys(struct rsa *, struct audit_fips *, struct keyinfo *, const char *); + +/* X509 */ +static int fips_x509_v1(struct audit_fips *, struct keyinfo *, const char *, const int); +static int fips_x509_v3(struct audit_fips *, struct keyinfo *, const char *, const int); + +static int check_exponent(const BIGNUM *, char *, unsigned long *); +static void clean_rsa_st(struct rsa *); +static int openssl_version(); +static void print_error(); + +#endif diff --git a/certificate.c b/certificate.c new file mode 100644 index 0000000..78f71a9 --- /dev/null +++ b/certificate.c @@ -0,0 +1,187 @@ +#include "certificate.h" +#include "audit/audit.h" +#include "audit/file.h" + + +int certificate(char **argv, const int argc){ + int res; + int is_pubkey = 0; + int to_stdout = 0; + char buf_pkey[BUF_PATH_PKEY]; + struct stat st_stat; + int fd; + off_t len; + int type; /* Indicate the type of file: RSA, x509 */ + + /* struct st_audit for permission */ + struct st_audit st_audit_owner = {0}; + struct st_audit st_audit_group = {0}; + struct st_audit st_audit_other = {0}; + + /* struct audit_fips for the FIPS audit */ + struct audit_fips st_audit_fips = {0}; + + /* struct for keyinformation */ + struct keyinfo st_keyinfo = {0}; + + // TODO: need to review how to parse args + res = check_arguments_certificate(argv, argc, buf_pkey, &type, &is_pubkey, &to_stdout); + + if (res == -1) + return -1; + + if (type <= 0) + return -1; + + // Check if public key file exist + if (file_exist(buf_pkey) == -1){ + printf("The file %s doesn't exist\n", buf_pkey); + return -1; + } + + // Check if public key file exist + if (file_exist(buf_pkey) == -1){ + printf("The file %s doesn't exist\n", buf_pkey); + return -1; + } + + /* + * Print the filename, + * Owner of the file + * Size of the file + * And other information + */ + if ((fd = open(buf_pkey, O_RDONLY)) < 0){ + printf("Failed to open the file\n"); + } + fstat(fd, &st_stat); + + printf("File information\n"); + printf("\tFilename: %s\n", buf_pkey); + printf("\tFile size: %ld\n", st_stat.st_size); + printf("\tPermission: %d\n", convert_mode_t(st_stat.st_mode)); + + /* + * Check certificate's file + * - owner of the certificate + * - permission of the file + */ + printf("\nChecking file ownerships compliance...\n"); + + uid_t uid = st_stat.st_uid; + char username[64]; + struct st_audit audit_ownshp = ownership(uid, username, 64); + printf("%s\n", audit_ownshp.result); + + /* + * Checking permission file + * For a better security, only the owner can have the privilege to read/write the certificate + */ + printf("\nChecking file permissions compliance...\n"); + permission(st_stat.st_mode, &st_audit_owner, &st_audit_group, &st_audit_other); + printf("%s\n", st_audit_owner.result); + if (st_audit_group.audit == FALSE) + printf("%s\n", st_audit_group.result); + if (st_audit_other.audit == FALSE) + printf("%s\n", st_audit_other.result); + + /*************************/ + /* Check FIPS compliance */ + /*************************/ + printf("\nChecking FIPS compliance...\n"); + + /*if (type == TYPE_X509){ + printf("Cannot decrypt x509 certifcate, it is not implemented yet\n"); + return 0; + }*/ + res = fips(buf_pkey, &st_audit_fips, &st_keyinfo, type, is_pubkey, to_stdout); + if (res < 0){ + printf("Error during check FIPS compliance\n"); + return -1; + } + + /* Print information regarding the key */ + printf("Certificate information:\n"); + printf("\tKey size: %d bytes (%d)\n", st_keyinfo.keysize, (st_keyinfo.keysize * 8)); + printf("\tExponent: %lu\n", st_keyinfo.exponent); + if (st_keyinfo.algo == ALGO_RSA) + printf("\tAlgorithm: RSA\n"); + if (st_keyinfo.algo == ALGO_EC) + printf("\tAlgorithm: Elliptic Curve\n"); + + if (st_keyinfo.format == RSA_FORMAT_PKCS1) + printf("\tFormat RSA key: PKCS#1\n"); + if (st_keyinfo.format == RSA_FORMAT_SPKI) + printf("\tFormat RSA key: SPKI\n"); + + printf("\n"); + + /* Print the audit result */ + printf("Exponent result:\n"); + printf("\t%s\n", st_audit_fips.audit_exponent.result); + printf("Keysize result:\n"); + printf("\t%s\n", st_audit_fips.audit_keysize.result); + + printf("\n"); + + /* If we dump the key, we read it */ + if (to_stdout){ + int len = 0; + + st_keyinfo.key = (char *)malloc(st_stat.st_size + 1); + lseek(fd, 0, SEEK_SET); + len = read(fd, st_keyinfo.key, st_stat.st_size); + st_keyinfo.key[len] = '\0'; + + printf("Dump the key:\n%s\n", st_keyinfo.key); + + free(st_keyinfo.key); + } + + close(fd); +} +/* + * This function check arguments passed for executing the program. For the certificate module, the type argument is mandatory, which indicate the type of key (RSA or x509). + Also, the argument -privin or -pubin is mandatory. One is for the private key followed by the pathname and the second one is the public key. + */ +static int check_arguments_certificate(char **argv, const int argc, char *buf_pkey, int *type, int *is_pubkey, int *to_stdout){ + int res = -1; + /* we bypass the first action arguments */ + for (int i = 3; i < argc; i++){ + /*if(argv[i][0] == '-'){}*/ + size_t l = strlen(argv[i]); + if (strncmp(argv[i], "-type", l) == 0){ + if (strcmp(argv[i + 1], "rsa") == 0) + *type = TYPE_RSA; + else if (strcmp(argv[i + 1], "x509") == 0) + *type = TYPE_X509; + else + res = -1; + } + if (strncmp(argv[i], "-pubin", l) == 0){ + //printf("%s\n", argv[i + 1]); + strncpy(buf_pkey, argv[i + 1], BUF_PATH_PKEY); + res = 0; + *is_pubkey = 1; + } + if (strncmp(argv[i], "-privin", l) == 0){ + strncpy(buf_pkey, argv[i + 1], BUF_PATH_PKEY); + res = 0; + *is_pubkey = 0; + } + if (strncmp(argv[i], "-text", l) == 0) + *to_stdout = 1; + } + + return res; +} +/* + * This function check if the file exist + * If yes, return 0, otherwise return-1 + */ +static int file_exist(const char *file){ + if (access(file, F_OK) == 0) + return 0; + return -1; +} + diff --git a/certificate.h b/certificate.h new file mode 100644 index 0000000..132d01e --- /dev/null +++ b/certificate.h @@ -0,0 +1,23 @@ +#ifndef H_CERTIFICATE +#define H_CERTIFICATE + +#include "audit/fips.h" +#include +#include +#include +#include + +#define BUF_PATH_PKEY 256 + +struct args{ + char *pathname; + int is_pubkey; + int to_stdout; +}; + +int certificate(char **, const int); +static int check_arguments_certificate(char **, const int, char *, int *, int *, int *); +static int file_exist(const char *); +static void get_username(uid_t, char *); + +#endif diff --git a/common.h b/common.h new file mode 100644 index 0000000..3cdbf0a --- /dev/null +++ b/common.h @@ -0,0 +1,12 @@ +#ifndef H_COMMON +#define H_COMMON + +#define PROCNAME_SIZE 256 + +struct random{ + __u32 pid; + //__u32 len; + //char buf[128]; +}; + +#endif diff --git a/cryptodit b/cryptodit new file mode 100755 index 0000000..08a5f99 Binary files /dev/null and b/cryptodit differ diff --git a/entropy.c b/entropy.c new file mode 100644 index 0000000..17e421d --- /dev/null +++ b/entropy.c @@ -0,0 +1,88 @@ +#include "entropy.h" +#include "common.h" + + +int handle_event(void *ctx, void *data, size_t data_sz){ + struct random *s_random = (struct random*)data; + pid_t pid = s_random->pid; + char procname[PROCNAME_SIZE]; + char pathname[64]; + FILE *fd; + memset(procname, 0, PROCNAME_SIZE); + memset(pathname, 0, 64); + + // Get the proc name + snprintf(pathname, 64, "/proc/%d/stat", pid); + if ((fd = fopen(pathname, "r")) == NULL){ + printf("Failed to open the file\n"); + return -1; + } + fscanf(fd, "%*d %s", procname); + + printf("proc: %s; pid: %d\n", procname, s_random->pid); + + fclose(fd); + + return 0; +} +int entropy(char **argv, int argc){ + const char *fileObj = "entropy_ebpf.o"; + struct bpf_object *obj; + struct bpf_program *program; + struct ring_buffer *rb; + int err; + int fd_map_data; + int running = 1; + + // Load eBPF + obj = bpf_object__open_file(fileObj, NULL); + if (!obj){ + printf("Failed to open %s\n", fileObj); + return -1; + } + + err = bpf_object__load(obj); + + if (err){ + printf("Failed to load object\n"); + return -1; + } + + //program = bpf_object__find_program_by_name(obj, "get_random"); + program = bpf_object__find_program_by_name(obj, "get_random_user"); + if (!program){ + printf("Failed to find the program\n"); + return -1; + } + + fd_map_data = bpf_object__find_map_fd_by_name(obj, "data"); + if (!fd_map_data){ + printf("Failed to find the FD of the map\n"); + return -1; + } + + bpf_program__attach(program); + + /* Start the ringbuffer */ + rb = ring_buffer__new(fd_map_data, handle_event, NULL, NULL); + if (!rb){ + printf("Failed to create the ringbuf\n"); + bpf_object__close(obj); + return -1; + } + + while(running){ + err = ring_buffer__poll(rb, 100 /* timeout, ms */); + if (err == -EINTR){ + printf("Failed to get the ringbuf\n"); + running = 0; + break; + } + } + + ring_buffer__free(rb); + bpf_object__close(obj); + + // Generate RSA keys and check the entropy available + +} diff --git a/entropy.h b/entropy.h new file mode 100644 index 0000000..3507aaf --- /dev/null +++ b/entropy.h @@ -0,0 +1,17 @@ +#ifndef H_ENTROPY +#define H_ENTROPY + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int entropy(char **, int); + +#endif diff --git a/entropy_ebpf.c b/entropy_ebpf.c new file mode 100644 index 0000000..87ecda9 --- /dev/null +++ b/entropy_ebpf.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +//#include +#include "common.h" + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024 /* 256kb */); +} data SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 4194304); /* /proc/sys/kernel/pid_max */ + __type(key, __u32); + __type(value, __u32); +} m_pid SEC(".maps"); + +// https://lwn.net/Articles/605828/ + +// https://lwn.net/Articles/625077/ +// cat /proc/kallsyms | grep get_random_bytes +SEC("kprobe/get_random_bytes_user") +int get_random_user(){ + struct random *s_random = 0; + __u32 pid = bpf_get_current_pid_tgid() >> 32; + + __u32 *n_pid = bpf_map_lookup_elem(&m_pid, &pid); + if (!n_pid) + return 0; + // bpf_printk("pid: %d", pid); + + /* + * To avoid to "burst" the user-space + * We add the pid in a map. If doesn't exist, we send data to the ring buffer + */ + if (*n_pid == 0){ + // bpf_printk("value: %d %d", pid, *n_pid); + /* TODO: get the procname */ + /*struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + if (!task) + return 0; + struct mm_struct *mm = task->mm;*/ + + if (bpf_map_update_elem(&m_pid, &pid, &pid, BPF_ANY) < 0){ + bpf_printk("Failed to update map"); + return 0; + } + + s_random = bpf_ringbuf_reserve(&data, sizeof(struct random *), 0); + if (!s_random) + return 0; + + s_random->pid = pid; + bpf_ringbuf_submit(s_random, 0); + } + + return 0; +} +char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/entropy_ebpf.o b/entropy_ebpf.o new file mode 100644 index 0000000..658f403 Binary files /dev/null and b/entropy_ebpf.o differ diff --git a/error.h b/error.h new file mode 100644 index 0000000..1771521 --- /dev/null +++ b/error.h @@ -0,0 +1,16 @@ +#ifndef H_ERROR +#define H_ERROR + +/* Define all Common errors */ +#define COMMON_ERR_MALLOC 0x100 + +/* Define all FIPS errors */ +#define FIPS_ERR_LOAD_KEY 0x200 +#define FIPS_ERR_NEW_BIO 0x201 +#define FIPS_ERR_READ_BIO 0x202 +#define FIPS_ERR_LOAD_RSA_KEY 0x203 +#define FIPS_ERR_LOAD_RSA_PRIV_KEY 0x204 +#define FIPS_ERR_LOAD_X509 0x205 + + +#endif diff --git a/examples/cert.pem b/examples/cert.pem new file mode 100644 index 0000000..85d3d60 --- /dev/null +++ b/examples/cert.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBhzCCATECFD29f5mS/P9BLaM6ahD5OYfFZj9qMA0GCSqGSIb3DQEBCwUAMEUx +CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjYwMTI4MDc1NTA1WhcNMjYwMjI3MDc1 +NTA1WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE +CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAw +SAJBAK7yGMN7B8KGqJ2WJCrUTA8RmN37wWkofPt2gcz/emtIOQ6TPOlRQQiVlYSu +WYojc+xqLfUDYwAuGbTorfsz8KsCAwEAATANBgkqhkiG9w0BAQsFAANBAFrMiM8U +OUXEJVQXSy1sotuDu8vysnjfFuxwm1z86pY3qWm45bhHFiwePdjhAckrlOL+fv0l +/qD9p78RsKQfMdU= +-----END CERTIFICATE----- diff --git a/examples/csr.pem b/examples/csr.pem new file mode 100644 index 0000000..fcb0c70 --- /dev/null +++ b/examples/csr.pem @@ -0,0 +1,8 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIH/MIGqAgEAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwXDANBgkqhkiG9w0BAQEF +AANLADBIAkEArvIYw3sHwoaonZYkKtRMDxGY3fvBaSh8+3aBzP96a0g5DpM86VFB +CJWVhK5ZiiNz7Got9QNjAC4ZtOit+zPwqwIDAQABoAAwDQYJKoZIhvcNAQELBQAD +QQBEMrIke9mgePMjmOAhdRxQVJbL+s4pzOMxY2kf+EzkICIXW2yGg4/3EO4N+7tC +NBfzHKrFqxkdSEWLh4OOOZ+e +-----END CERTIFICATE REQUEST----- diff --git a/examples/foo.pem b/examples/foo.pem new file mode 100644 index 0000000..0b6ed9b --- /dev/null +++ b/examples/foo.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPQIBAAJBAKxX41iNOT0dknOVXnBJ/HJp7Ka4Mu0VKePBIBn2XHFO4f3ZDHXJ +Zt5xb+NJ8nUR640Gjcoc7lOOcw0QmEj1PbMCAwEAAQJBAITEJBDYooqxWFwQarNI +W+DsNvHsntbDYgThh1BY2Lg0EAM9KcJhBDmBF1X12yhMiFlrNbSxV0ZR7/tpMij2 +ycECIQDTvtc9rGQJGhD6GbAlFWP1ukWgwlB1NcC4xMZM+nalIQIhANBc4yVRq3gx +RtgcijG9m++d+IT7ZATHK8+0NlQJkzRTAiEAg5vUcLLbooSfFLQutX3sGWljqZ3d +IFz+olk739C1OcECIQCFVYt9jB+gEFh3XvwIDH/G/F3WK1C7xgCBL588c8whRQIh +AKPuzXozkJrD0K2LHU0GU9bRzl6j6m22+gBG8rDsWUwP +-----END RSA PRIVATE KEY----- diff --git a/examples/private.key b/examples/private.key new file mode 100644 index 0000000..6d433b9 --- /dev/null +++ b/examples/private.key @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBAK7yGMN7B8KGqJ2WJCrUTA8RmN37wWkofPt2gcz/emtIOQ6TPOlR +QQiVlYSuWYojc+xqLfUDYwAuGbTorfsz8KsCAwEAAQJBAKD6suDFyAkuwd9oNdWX +TnmbNrAlJf7uu7rkfGI3P92QrOY7gc8ZsUluv/63cpekRclsvSe76CgcQmMpo/Oa +TVECIQDcxc7GV91Y90g7ACfQFzO4Lz9GgmObYExBSfurRZ8g8wIhAMrcVVxNHhG3 +Mh6ZvIH0vTPHT6Wo3QUWzns+pSukxh9pAiBgl+NqgJMGE9t0hRLmRuCIG5Pxw6bV +GoMCpd4JB8Mh5QIgAkAVdlOorLuig7Ji4/IqEyP33zeTVBYfrkBQpr5KMFkCIQCd +WyZemsI/9PNb1OUUlpYMHFs+GBOGJQLbxRcFmNdjHg== +-----END RSA PRIVATE KEY----- diff --git a/examples/public.key b/examples/public.key new file mode 100644 index 0000000..bae13b4 --- /dev/null +++ b/examples/public.key @@ -0,0 +1,4 @@ +-----BEGIN RSA PUBLIC KEY----- +MEgCQQCu8hjDewfChqidliQq1EwPEZjd+8FpKHz7doHM/3prSDkOkzzpUUEIlZWE +rlmKI3Psai31A2MALhm06K37M/CrAgMBAAE= +-----END RSA PUBLIC KEY----- diff --git a/examples/public_ec.pem b/examples/public_ec.pem new file mode 100644 index 0000000..9f6b744 --- /dev/null +++ b/examples/public_ec.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEelQ5fSfII96Q/3fP+i97M8Cm94at +GV2W16RU4Ubto25b+AEjG7Lh6cSARLogvVe7EpxQ6wgxjomstHjREK5ZIA== +-----END PUBLIC KEY----- diff --git a/exec.sh b/exec.sh new file mode 100755 index 0000000..73a5b94 --- /dev/null +++ b/exec.sh @@ -0,0 +1,5 @@ +#!/usr/bin/bash + +clang-11 -g -O2 -target bpf -c entropy_ebpf.c -o entropy_ebpf.o + +gcc utils.c argparse.c audit/file.c certificate.c speed.c entropy.c audit/fips.c main.c -lbpf -lcrypto -o cryptodit diff --git a/main.c b/main.c new file mode 100644 index 0000000..4470692 --- /dev/null +++ b/main.c @@ -0,0 +1,63 @@ +#include +#include +#include "argparse.h" +#include "certificate.h" +#include "speed.h" +#include "entropy.h" + +#define BUF_MODULE_SIZE 64 + +static void usage(const char *); +int main(int argc, char *argv[]){ + int res = -1; + char modules[BUF_MODULE_SIZE]; + memset(modules, 0, BUF_MODULE_SIZE); + + res = check_arguments(argv, argc, modules, BUF_MODULE_SIZE); + + if (res == -1){ + usage(argv[0]); + return -1; + } + + printf("Module: %s\n", modules); + + + if (strncmp(modules, "speed", BUF_MODULE_SIZE) == 0){ + res = speed(argv, argc); + if (res == -1){ + usage(argv[0]); + return -1; + } + } + if (strncmp(modules, "certificate", BUF_MODULE_SIZE) == 0){ + res = certificate(argv, argc); + if (res == -1){ + usage(argv[0]); + return -1; + } + } + if (strncmp(modules, "entropy", BUF_MODULE_SIZE) == 0){ + res = entropy(argv, argc); + if (res == -1){ + usage(argv[0]); + return -1; + } + } + return 0; +} + +static void usage(const char *script){ + printf("Usage %s -m \n", script); + printf("Modules:\n"); + printf("\tcertificate: Check if the certificate is compliant with FIP 140-3 and check the certificate security file\n"); + printf("\tspeed: Check the time for creating the certificate\n"); + printf("\tentropy: Check the entropy in the kernel\n\n"); + printf("Certificate Modules:\n"); + printf("\t-type \n"); + printf("\t-pubin \n"); + printf("\t-privin \n"); + printf("\t-text: print in text the certificate\n\n"); + printf("Speed Modules:\n"); + printf("\t-type \n"); +} diff --git a/speed.c b/speed.c new file mode 100644 index 0000000..15c954a --- /dev/null +++ b/speed.c @@ -0,0 +1,268 @@ +#include "speed.h" +#include + +int speed(char **argv, int argc){ + int res = 0; + size_t keysize; + int type = 0; + int to_stdout = 0; + + res = check_arguments_speed(argv, argc, &type, &keysize, &to_stdout); + + if (res < 0) + return -1; + + // Generate key + if (type == TYPE_SPEED_RSA || type == TYPE_SPEED_ALL){ + res = speed_generate_rsa_keys(2048, to_stdout); + if (res < 0) + return -1; + + res = speed_generate_rsa_keys(4192, to_stdout); + if (res < 0 ) + return -1; + } + if (type == TYPE_SPEED_ELLIPTIC || type == TYPE_SPEED_ALL){ + res = speed_generate_elliptic_keys(2048, to_stdout); + } + + return res; +} +/* + * This function generate RSA keys + */ +static int speed_generate_rsa_keys(size_t keysize, const int to_stdout){ + RSA *rsa = NULL; + BIGNUM *e = NULL; + char nE[5]; + BIO *bioPublic = NULL; + BIO *bioPrivate = NULL; + char buf_public[2049]; + char buf_private[2049]; + size_t keys; + unsigned long ms_start; + unsigned long ms_end; + + // For the exponent: RSA_F4 = 65537 + sprintf(nE, "%ld", RSA_F4); + //printf("%s\n", nE); + BN_dec2bn(&e, nE); + + ms_start = getms(); + + rsa = RSA_new(); + if (rsa == NULL){ + printf("Failed to create RSA\n"); + return -1; + } + + RSA_generate_key_ex(rsa, keysize, e, NULL); + + bioPublic = BIO_new(BIO_s_mem()); + if (bioPublic == NULL){ + RSA_free(rsa); + BN_free(e); + printf("Failed to new BIO public\n"); + return -1; + } + + bioPrivate = BIO_new(BIO_s_mem()); + if (bioPrivate == NULL){ + printf("Failed to create BIO private key\n"); + RSA_free(rsa); + BIO_free(bioPublic); + BN_free(e); + return -1; + } + + PEM_write_bio_RSAPublicKey(bioPublic, rsa); + PEM_write_bio_RSAPrivateKey(bioPrivate, rsa, NULL, NULL, 0, NULL, NULL); + + ms_end = getms(); + long diff = ms_end - ms_start; + + /* Dump the both public and privte keys */ + if (to_stdout){ + printf("RSA public key:\n"); + print_key(bioPublic); + printf("RSA private key:\n"); + print_key(bioPrivate); + + } + + /* Print the output of the test */ + printf("The generation of the RSA key %ld bits took %ld ms\n", keysize, diff); + + // Clean + BIO_free(bioPublic); + BIO_free(bioPrivate); + RSA_free(rsa); + BN_free(e); + + return 0; +} +/* + * This function dump the key from BIO + */ +static void print_key(BIO *bio){ + char *buf = NULL; + size_t key_size = BIO_pending(bio); + + buf = malloc(key_size + 1); + if (buf == NULL){ + printf("Failed to allocate memory\n"); + return; + } + BIO_read(bio, buf, key_size); + buf[key_size] = '\0'; + printf("%s\n", buf); + free(buf); +} +/* + * This function generate elliptic keys + https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography + */ +static int speed_generate_elliptic_keys(size_t keysize, const int to_stdout){ + EC_GROUP *curve = NULL; + EC_KEY *key = NULL; + const EC_POINT *pub = NULL; + unsigned long ms_start; + unsigned long ms_end; + + /* + * List of curve: + * /usr/include/openssl/obj_mac.h + * $ openssl ecparam -list_curves + */ + /*curve = EC_GROUP_new_by_curve_name_ex(NULL, NULL, NID_X9_62_prime256v1); + if (curve == NULL){ + printf("Failed to generate the curve\n"); + return -1; + }*/ + + ms_start = getms(); + + key = EC_KEY_new_by_curve_name(NID_secp256k1); + if (key == NULL){ + printf("Failed to generate the curve keys\n"); + return -1; + } + + /* + * Generating both private and public keys + * return 1 on success, otherwise it's 0 + */ + if (EC_KEY_generate_key(key) == 0){ + EC_KEY_free(key); + return -1; + } + + ms_end = getms(); + long diff = ms_end - ms_start; + + /* + * Both private and public keys has been set up. + * We can get them + */ + + pub = EC_KEY_get0_public_key(key); + if (pub == NULL){ + printf("Failed to get the EC public key\n"); + EC_KEY_free(key); + return -1; + } + + if (to_stdout){ + if (ec_get_pub_key(key, pub) < 0){ + EC_KEY_free(key); + return -1; + } + } + + /* Print the output of the test */ + printf("The generation of the EC key secp256 took %ld ms\n", diff); + + EC_KEY_free(key); + return 0; +} + +/* + * This function load and dump the EC public key + */ +static int ec_get_pub_key(const EC_KEY *key, const EC_POINT *pub){ + const EC_GROUP *curve = NULL; + BIGNUM *bn = NULL; + uint8_t len = 0; + char *buf = NULL; + + bn = BN_new(); + if (bn == NULL){ + return -1; + } + + /* For pub key, get the EC group */ + curve = EC_KEY_get0_group(key); + if (curve == NULL){ + printf("Failed to get the EC Group\n"); + return -1; + } + BN_CTX *bn_ctx = BN_CTX_new(); + buf = EC_POINT_point2hex(curve, pub, POINT_CONVERSION_UNCOMPRESSED, bn_ctx); + + printf("Public key:\n%s\n", buf); + + // Galois Field degree + int bits = EC_GROUP_get_degree(curve); + //printf("%d\n", bits); + + bits = EC_GROUP_order_bits(curve); + //printf("%d\n", bits); + + // Save to file + /*FILE *f = fopen("public_ec.pem", "w"); + PEM_write_EC_PUBKEY(f, key); + fclose(f);*/ + + BN_free(bn); + OPENSSL_free(buf); + BN_CTX_free(bn_ctx); + return 0; +} + + +static int check_arguments_speed(char **argv, const int argc, int *type, size_t *keysize, int *to_stdout){ + int res = -1; + + /* we bypass the first action arguments */ + for (int i = 3; i < argc; i++){ + size_t l = strlen(argv[i]); + if (strncmp(argv[i], "-type", l) == 0){ + if (strcmp(argv[i + 1], "rsa") == 0) + *type = TYPE_SPEED_RSA; + else if (strcmp(argv[i + 1], "elliptic") == 0) + *type = TYPE_SPEED_ELLIPTIC; + else if (strcmp(argv[i + 1], "all") == 0) + *type = TYPE_SPEED_ALL; + res = 0; + } + + if (strncmp(argv[i], "-text", l) == 0) + *to_stdout = 1; + } + return res; +} +static unsigned long getms() { + /* + * struct timeval store second and microseconds values + * tv_sec -> seconds + * tv_usec -> microseconds + * https://man7.org/linux/man-pages/man3/timeval.3type.html + */ + struct timeval tp; + gettimeofday(&tp, NULL); + /* + * We multiple by 1000 for converting second to milliseconds + * Then, we need to convert micro to millis by dividing by 1000 + */ + return tp.tv_sec * 1000 + tp.tv_usec / 1000; +} diff --git a/speed.h b/speed.h new file mode 100644 index 0000000..ecff1a4 --- /dev/null +++ b/speed.h @@ -0,0 +1,24 @@ +#ifndef H_SPEED +#define H_SPEED + +#define TYPE_SPEED_ALL 0x1 +#define TYPE_SPEED_RSA 0x2 +#define TYPE_SPEED_ELLIPTIC 0x3 + +#include +#include +#include +#include +#include +#include +#include + +int speed(char **, int); +static int check_arguments_speed(char **, const int, int *, size_t *, int *); +static int speed_generate_rsa_keys(size_t, const int); +static void print_key(BIO *); +static int speed_generate_elliptic_keys(size_t, const int); +static int ec_get_pub_key(const EC_KEY *, const EC_POINT *); +static unsigned long getms(); + +#endif diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..e4ccce9 --- /dev/null +++ b/utils.c @@ -0,0 +1,5 @@ +#include "utils.h" + +int char2dec(const char c){ + return c - '0'; +} diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..108ea02 --- /dev/null +++ b/utils.h @@ -0,0 +1,7 @@ +#ifndef H_UTILS +#define H_UTILS + +int char2dec(const char); +unsigned long char2ulong(const char *); + +#endif