/* * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Hyra nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #define KEY_SIZE 32 int gen_x25519_keypair(struct x25519_keypair *res) { EVP_PKEY_CTX *ctx; EVP_PKEY *keypair_raw = NULL; struct x25519_keypair keypair; int retor; if (res == NULL) { return -1; } ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); if (ctx == NULL) { printf("ecdh: Failed to create X25519 keygen context\n"); return -1; } if (EVP_PKEY_keygen_init(ctx) <= 0) { printf("ecdh: Failed to init X25519 keygen context\n"); EVP_PKEY_CTX_free(ctx); return -1; } /* Create X25519 key pair */ if (EVP_PKEY_keygen(ctx, &keypair_raw) <= 0) { printf("ecdh: Failed to generate X25519 keypair\n"); EVP_PKEY_CTX_free(ctx); return -1; } /* Allocate a buffer for the public key */ EVP_PKEY_get_raw_public_key(keypair_raw, NULL, &keypair.pubkey_len); keypair.pubkey = malloc(keypair.pubkey_len); if (keypair.pubkey == NULL) { printf(" ecdh: Failed to allocate memory for public key\n"); EVP_PKEY_free(keypair_raw); EVP_PKEY_CTX_free(ctx); return -1; } /* Allocate a buffer for the private key */ EVP_PKEY_get_raw_private_key(keypair_raw, NULL, &keypair.privkey_len); keypair.privkey = malloc(keypair.privkey_len); if (keypair.privkey == NULL) { printf("ecdh: Failed allocating memory for private key\n"); EVP_PKEY_free(keypair_raw); EVP_PKEY_CTX_free(ctx); return -1; } retor = EVP_PKEY_get_raw_private_key(keypair_raw, keypair.privkey, &keypair.privkey_len); if (retor <= 0) { printf("Failed to extract private key\n"); EVP_PKEY_free(keypair_raw); EVP_PKEY_CTX_free(ctx); } retor = EVP_PKEY_get_raw_public_key(keypair_raw, keypair.pubkey, &keypair.pubkey_len); if (retor <= 0) { printf("Failed to extract public key\n"); EVP_PKEY_free(keypair_raw); EVP_PKEY_CTX_free(ctx); } EVP_PKEY_free(keypair_raw); EVP_PKEY_CTX_free(ctx); *res = keypair; return 0; } int free_x25519_keypair(struct x25519_keypair *xkp) { if (xkp == NULL) { return -1; } free(xkp->pubkey); free(xkp->privkey); return 0; } int gen_session_key(const unsigned char *priv, const unsigned char *peer_key, unsigned char **res) { size_t tmp; unsigned char *session_key; EVP_PKEY *own_key = NULL; EVP_PKEY *peer_pubkey = NULL; EVP_PKEY_CTX *ctx = NULL; /* Allocate memory for session key */ session_key = malloc(KEY_SIZE); if (session_key == NULL) { printf("Failed to allocate session key memory\n"); return -1; } /* Lock and load session key pages */ if (mlock(session_key, KEY_SIZE) != 0) { printf("Failed to lock session key pages\n"); free(session_key); return -1; } /* Create an EVP_PKEY from our private key */ own_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv, KEY_SIZE); if (own_key == NULL) { printf("Failed to serialize private key\n"); free_session_key(session_key); return -1; } /* Create an EVP_PKEY for peer public key */ peer_pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, peer_key, KEY_SIZE); if (peer_pubkey == NULL) { printf("Failed to serialize peer public key\n"); EVP_PKEY_free(own_key); free_session_key(session_key); return -1; } ctx = EVP_PKEY_CTX_new(own_key, NULL); if (ctx == NULL) { printf("Failed to create context\n"); EVP_PKEY_free(own_key); EVP_PKEY_free(peer_pubkey); free_session_key(session_key); return -1; } /* Initialize key derivation */ if (EVP_PKEY_derive_init(ctx) <= 0) { printf("Failed initializing key derivation\n"); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(own_key); EVP_PKEY_free(peer_pubkey); free_session_key(session_key); return -1; } /* Set peer public key */ if (EVP_PKEY_derive_set_peer(ctx, peer_pubkey) <= 0) { printf("Failed to set peer key\n"); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(own_key); EVP_PKEY_free(peer_pubkey); free_session_key(session_key); return -1; } /* Derive the session key */ tmp = KEY_SIZE; if (EVP_PKEY_derive(ctx, session_key, &tmp) <= 0) { printf("Failed to derive session key\n"); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(own_key); EVP_PKEY_free(peer_pubkey); free_session_key(session_key); return -1; } EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(own_key); EVP_PKEY_free(peer_pubkey); *res = session_key; return 0; } int free_session_key(unsigned char *session_key) { munlock(session_key, KEY_SIZE); free(session_key); }