From 9dbbfcd388a11d78a8efe1501aee1e385867b5a9 Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Wed, 7 Jul 2021 08:11:08 +0200 Subject: [PATCH] Mayaqua: Add new cryptographic functions for X25519/X448 keys management The files are created in a new folder to keep the source tree tidier. Please note that only X25519/X448 keys are supported due to an OpenSSL limitation: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_new.html We have functions that handle AES keys in Encrypt.c/.h. Ideally we should move them into the new files. --- src/Mayaqua/CMakeLists.txt | 4 +- src/Mayaqua/Crypto/Key.c | 221 +++++++++++++++++++++++++++++++++++++ src/Mayaqua/Crypto/Key.h | 36 ++++++ src/Mayaqua/Crypto/Types.h | 8 ++ src/Mayaqua/MayaType.h | 2 + 5 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 src/Mayaqua/Crypto/Key.c create mode 100644 src/Mayaqua/Crypto/Key.h create mode 100644 src/Mayaqua/Crypto/Types.h diff --git a/src/Mayaqua/CMakeLists.txt b/src/Mayaqua/CMakeLists.txt index ad6b2302..6bca56de 100644 --- a/src/Mayaqua/CMakeLists.txt +++ b/src/Mayaqua/CMakeLists.txt @@ -1,5 +1,5 @@ -file(GLOB SOURCES_MAYAQUA "*.c") -file(GLOB HEADERS_MAYAQUA "*.h") +file(GLOB SOURCES_MAYAQUA "*.c" "Crypto/*.c") +file(GLOB HEADERS_MAYAQUA "*.h" "Crypto/*.h") if(WIN32) add_library(mayaqua STATIC ${SOURCES_MAYAQUA} ${HEADERS_MAYAQUA}) diff --git a/src/Mayaqua/Crypto/Key.c b/src/Mayaqua/Crypto/Key.c new file mode 100644 index 00000000..fc6e482c --- /dev/null +++ b/src/Mayaqua/Crypto/Key.c @@ -0,0 +1,221 @@ +#include "Key.h" + +#include "Encrypt.h" +#include "Memory.h" +#include "Str.h" + +#include + +static int CryptoKeyTypeToID(const CRYPTO_KEY_TYPE type) +{ + switch (type) + { + case KEY_UNKNOWN: + break; + case KEY_X25519: + return EVP_PKEY_X25519; + case KEY_X448: + return EVP_PKEY_X448; + default: + Debug("CryptoKeyTypeToID(): Unhandled type %u!\n", type); + } + + return EVP_PKEY_NONE; +} + +UINT CryptoKeyTypeSize(const CRYPTO_KEY_TYPE type) +{ + switch (type) + { + case KEY_UNKNOWN: + break; + case KEY_X25519: + return KEY_X25519_SIZE; + case KEY_X448: + return KEY_X448_SIZE; + default: + Debug("CryptoKeyTypeSize(): Unhandled type %u!\n", type); + } + + return 0; +} + +CRYPTO_KEY_RAW *CryptoKeyRawNew(const void *data, const UINT size, const CRYPTO_KEY_TYPE type) +{ + if (size == 0 || size != CryptoKeyTypeSize(type)) + { + return NULL; + } + + CRYPTO_KEY_RAW *key = Malloc(sizeof(CRYPTO_KEY_RAW)); + key->Data = MallocEx(size, true); + key->Size = size; + key->Type = type; + + if (data == NULL) + { + Rand(key->Data, key->Size); + } + else + { + Copy(key->Data, data, key->Size); + } + + return key; +} + +void CryptoKeyRawFree(CRYPTO_KEY_RAW *key) +{ + if (key == NULL) + { + return; + } + + Free(key->Data); + Free(key); +} + +CRYPTO_KEY_RAW *CryptoKeyRawPublic(const CRYPTO_KEY_RAW *private) +{ + if (private == NULL) + { + return NULL; + } + + void *opaque = CryptoKeyRawToOpaque(private, false); + if (opaque == NULL) + { + return NULL; + } + + CRYPTO_KEY_RAW *public = NULL; + CryptoKeyOpaqueToRaw(opaque, NULL, &public); + CryptoKeyOpaqueFree(opaque); + + return public; +} + +void *CryptoKeyRawToOpaque(const CRYPTO_KEY_RAW *key, const bool public) +{ + if (key == NULL) + { + return NULL; + } + + const int id = CryptoKeyTypeToID(key->Type); + + if (public) + { + return EVP_PKEY_new_raw_public_key(id, NULL, key->Data, key->Size); + } + else + { + return EVP_PKEY_new_raw_private_key(id, NULL, key->Data, key->Size); + } +} + +void *CryptoKeyOpaqueNew(const CRYPTO_KEY_TYPE type) +{ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(CryptoKeyTypeToID(type), NULL); + if (ctx == NULL) + { + Debug("CryptoKeyOpaqueNew(): EVP_PKEY_CTX_new_id() returned NULL!\n"); + return false; + } + + EVP_PKEY *key = NULL; + + int ret = EVP_PKEY_keygen_init(ctx); + if (ret != 1) + { + Debug("CryptoKeyOpaqueNew(): EVP_PKEY_keygen_init() returned %d!\n", ret); + goto FINAL; + } + + ret = EVP_PKEY_keygen(ctx, &key); + if (ret != 1) + { + Debug("CryptoKeyOpaqueNew(): EVP_PKEY_keygen() returned %d!\n", ret); + } +FINAL: + EVP_PKEY_CTX_free(ctx); + return key; +} + +void CryptoKeyOpaqueFree(void *key) +{ + if (key != NULL) + { + EVP_PKEY_free(key); + } +} + +bool CryptoKeyOpaqueToRaw(const void *opaque, CRYPTO_KEY_RAW **private, CRYPTO_KEY_RAW **public) +{ + if (opaque == NULL || (private == NULL && public == NULL)) + { + return false; + } + + CRYPTO_KEY_TYPE type; + + switch (EVP_PKEY_id(opaque)) + { + case EVP_PKEY_X25519: + type = KEY_X25519; + break; + case EVP_PKEY_X448: + type = KEY_X448; + break; + default: + return false; + } + + if (private != NULL) + { + size_t size; + int ret = EVP_PKEY_get_raw_private_key(opaque, NULL, &size); + if (ret != 1) + { + Debug("CryptoKeyOpaqueToRaw(): #1 EVP_PKEY_get_raw_private_key() returned %d!\n", ret); + return false; + } + + CRYPTO_KEY_RAW *key = CryptoKeyRawNew(NULL, size, type); + + ret = EVP_PKEY_get_raw_private_key(opaque, key->Data, &size); + if (ret != 1) + { + Debug("CryptoKeyOpaqueToRaw(): #2 EVP_PKEY_get_raw_private_key() returned %d!\n", ret); + CryptoKeyRawFree(key); + return false; + } + + *private = key; + } + + if (public != NULL) + { + size_t size; + int ret = EVP_PKEY_get_raw_public_key(opaque, NULL, &size); + if (ret != 1) + { + Debug("CryptoKeyOpaqueToRaw(): #1 EVP_PKEY_get_raw_public_key() returned %d!\n", ret); + return false; + } + + CRYPTO_KEY_RAW *key = CryptoKeyRawNew(NULL, size, type); + + ret = EVP_PKEY_get_raw_public_key(opaque, key->Data, &size); + if (ret != 1) + { + Debug("CryptoKeyOpaqueToRaw(): #2 EVP_PKEY_get_raw_public_key() returned %d!\n", ret); + CryptoKeyRawFree(key); + return false; + } + + *public = key; + } + + return true; +} diff --git a/src/Mayaqua/Crypto/Key.h b/src/Mayaqua/Crypto/Key.h new file mode 100644 index 00000000..24cd34eb --- /dev/null +++ b/src/Mayaqua/Crypto/Key.h @@ -0,0 +1,36 @@ +#ifndef CRYPTO_KEY_H +#define CRYPTO_KEY_H + +#include "MayaType.h" + +#define KEY_X25519_SIZE 32 +#define KEY_X448_SIZE 56 + +enum CRYPTO_KEY_TYPE +{ + KEY_UNKNOWN, + KEY_X25519, + KEY_X448 +}; + +struct CRYPTO_KEY_RAW +{ + BYTE *Data; + UINT Size; + CRYPTO_KEY_TYPE Type; +}; + +UINT CryptoKeyTypeSize(const CRYPTO_KEY_TYPE type); + +CRYPTO_KEY_RAW *CryptoKeyRawNew(const void *data, const UINT size, const CRYPTO_KEY_TYPE type); +void CryptoKeyRawFree(CRYPTO_KEY_RAW *key); + +CRYPTO_KEY_RAW *CryptoKeyRawPublic(const CRYPTO_KEY_RAW *private); +void *CryptoKeyRawToOpaque(const CRYPTO_KEY_RAW *key, const bool public); + +void *CryptoKeyOpaqueNew(const CRYPTO_KEY_TYPE type); +void CryptoKeyOpaqueFree(void *key); + +bool CryptoKeyOpaqueToRaw(const void *opaque, CRYPTO_KEY_RAW **private, CRYPTO_KEY_RAW **public); + +#endif diff --git a/src/Mayaqua/Crypto/Types.h b/src/Mayaqua/Crypto/Types.h new file mode 100644 index 00000000..50d6f856 --- /dev/null +++ b/src/Mayaqua/Crypto/Types.h @@ -0,0 +1,8 @@ +#ifndef CRYPTO_TYPES_H +#define CRYPTO_TYPES_H + +typedef enum CRYPTO_KEY_TYPE CRYPTO_KEY_TYPE; + +typedef struct CRYPTO_KEY_RAW CRYPTO_KEY_RAW; + +#endif diff --git a/src/Mayaqua/MayaType.h b/src/Mayaqua/MayaType.h index 36b1eaea..95a21044 100644 --- a/src/Mayaqua/MayaType.h +++ b/src/Mayaqua/MayaType.h @@ -466,4 +466,6 @@ typedef struct DNS_CACHE_REVERSE DNS_CACHE_REVERSE; typedef struct DNS_RESOLVER DNS_RESOLVER; typedef struct DNS_RESOLVER_REVERSE DNS_RESOLVER_REVERSE; +#include "Crypto/Types.h" + #endif // MAYATYPE_H