1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-09-13 07:13:00 +03:00

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.
This commit is contained in:
Davide Beatrici 2021-07-07 08:11:08 +02:00
parent 4328e6e5ab
commit 9dbbfcd388
5 changed files with 269 additions and 2 deletions

View File

@ -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})

221
src/Mayaqua/Crypto/Key.c Normal file
View File

@ -0,0 +1,221 @@
#include "Key.h"
#include "Encrypt.h"
#include "Memory.h"
#include "Str.h"
#include <openssl/evp.h>
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;
}

36
src/Mayaqua/Crypto/Key.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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