Skip to content

Instantly share code, notes, and snippets.

@melvyniandrag
Last active August 29, 2017 18:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save melvyniandrag/c8bfb6ea6f10f648381ccedcc1ac0912 to your computer and use it in GitHub Desktop.
Save melvyniandrag/c8bfb6ea6f10f648381ccedcc1ac0912 to your computer and use it in GitHub Desktop.
Creating and sharing ECDH keys to create a shared secret with openssl.
/*
Compile me with g++ main.cpp -lssl -lcrypto
The computeNeededSharedMemory() function has alot of stuff that is duplicated in main(). It should be refactored.
Also I forgot to free some stuff at the end. Just add the appropriate calls to the appropriate free methods. For me, its lunchtime
now.
*/
#include <cassert>
#include <string>
#include <cstring>
#include <iostream>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
size_t computeNeededSharedMem()
{
// If I don't set these to NULL, we get a segfault.
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY_CTX *kctx = NULL;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
EVP_PKEY *peerkey = NULL;
EVP_PKEY *params = NULL;
assert(NULL != (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)));
assert(1 == EVP_PKEY_paramgen_init(pctx));
assert(1 == EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1));
assert(1 == EVP_PKEY_paramgen(pctx, &params));
assert(NULL != (kctx = EVP_PKEY_CTX_new(params, NULL)));
assert(1 == EVP_PKEY_keygen_init(kctx));
assert(1 == EVP_PKEY_keygen(kctx, &pkey));
assert(1 == EVP_PKEY_keygen(kctx, &peerkey)); // Just populating the key with some stuff. Commenting this out causes a segfault.
assert( 0 == EVP_PKEY_cmp( pkey, peerkey ) );
// Verify the keys can be serialized / deserialized correctly.
// Serialize..
EC_KEY *Key1 = EVP_PKEY_get1_EC_KEY( pkey );
assert( NULL != Key1 );
const EC_POINT *Point1 = EC_KEY_get0_public_key( Key1 );
assert( NULL != Point1 );
const EC_GROUP *gp = EC_KEY_get0_group( Key1 );
assert( gp != NULL );
const size_t SizeOfBuffer = EC_POINT_point2oct(gp, Point1, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
unsigned char * serializedKey = static_cast<unsigned char*>( OPENSSL_malloc(SizeOfBuffer) );
const size_t VerifyBufferSize = EC_POINT_point2oct(gp, Point1, POINT_CONVERSION_UNCOMPRESSED, serializedKey, SizeOfBuffer, NULL);
assert( SizeOfBuffer == VerifyBufferSize );
return SizeOfBuffer;
}
void* create_shared_memory(size_t size) {
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_ANONYMOUS | MAP_SHARED;
return mmap(NULL, size, protection, visibility, 0, 0);
}
int main(int argc, char** argv){
size_t SizeOfSharedBuffer = computeNeededSharedMem();
void *shmem = create_shared_memory( SizeOfSharedBuffer );
int pid = fork();
// If I don't set these to NULL, we get a segfault.
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY_CTX *kctx = NULL;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
EVP_PKEY *peerkey = NULL;
EVP_PKEY *params = NULL;
assert(NULL != (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)));
assert(1 == EVP_PKEY_paramgen_init(pctx));
assert(1 == EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1));
assert(1 == EVP_PKEY_paramgen(pctx, &params));
assert(NULL != (kctx = EVP_PKEY_CTX_new(params, NULL)));
assert(1 == EVP_PKEY_keygen_init(kctx));
assert(1 == EVP_PKEY_keygen(kctx, &pkey));
assert(1 == EVP_PKEY_keygen(kctx, &peerkey)); // Just populating the key with some stuff. Commenting this out causes a segfault.
assert( 0 == EVP_PKEY_cmp( pkey, peerkey ) );
// Verify the keys can be serialized / deserialized correctly.
// Serialize..
EC_KEY *Key1 = EVP_PKEY_get1_EC_KEY( pkey );
assert( NULL != Key1 );
const EC_POINT *Point1 = EC_KEY_get0_public_key( Key1 );
assert( NULL != Point1 );
const EC_GROUP *gp = EC_KEY_get0_group( Key1 );
assert( gp != NULL );
const size_t SizeOfBuffer = EC_POINT_point2oct(gp, Point1, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
unsigned char * serializedKey = static_cast<unsigned char*>( OPENSSL_malloc(SizeOfBuffer) );
const size_t VerifyBufferSize = EC_POINT_point2oct(gp, Point1, POINT_CONVERSION_UNCOMPRESSED, serializedKey, SizeOfBuffer, NULL);
assert( SizeOfBuffer == VerifyBufferSize );
assert( serializedKey != NULL );
// Exchange keys.
unsigned char * recvSerializedKey = static_cast<unsigned char*>( OPENSSL_malloc(SizeOfBuffer) );
if (pid == 0)
{
memcpy( shmem, serializedKey, SizeOfBuffer );
std::cout << "Parent Sent\n:" << std::string( reinterpret_cast<char *>( serializedKey ) ) << "\n";
sleep(1);
}
else
{
sleep(1);
memcpy( recvSerializedKey, shmem, SizeOfBuffer );
std::cout << "Child Received\n:" << std::string( reinterpret_cast<char *>( recvSerializedKey ) ) << "\n";
}
sleep(1); // Just wait another second to make sure we're synced up.
if (pid != 0)
{
memcpy( shmem, serializedKey, SizeOfBuffer );
std::cout << "Child Sent:\n" << std::string( reinterpret_cast<char *>( serializedKey ) ) << "\n";
sleep(1);
}
else
{
sleep(1);
memcpy( recvSerializedKey, shmem, SizeOfBuffer );
std::cout << "Parent Received:\n" << std::string( reinterpret_cast< char *>( recvSerializedKey) ) << "\n";
}
// Deserialize
EC_POINT *deserialPt = EC_POINT_new( gp );
assert( 1 == EC_POINT_oct2point( gp, deserialPt, recvSerializedKey, SizeOfBuffer, NULL ) );
EC_KEY *Key2 = EVP_PKEY_get1_EC_KEY( peerkey );
assert( 1 == EC_KEY_set_public_key( Key2, deserialPt ) );
assert( Key2 != NULL );
assert( 1 == EVP_PKEY_set1_EC_KEY( peerkey, Key2 ) );
// Done verifying.
assert( 0 == EVP_PKEY_cmp( pkey, peerkey ) ); // The two parties ought to have different keys!
// Generate the shared secret:
size_t secret_len;
unsigned char* secret;
assert( NULL != (ctx = EVP_PKEY_CTX_new( pkey, NULL ) ) );
assert( 1 == EVP_PKEY_derive_init(ctx) );
assert( 1 == EVP_PKEY_derive_set_peer(ctx, peerkey));
assert( 1 == EVP_PKEY_derive(ctx, NULL, &secret_len));
assert( NULL != (secret = static_cast<unsigned char*>( OPENSSL_malloc( secret_len ) ) ) );
assert( 1 == ( EVP_PKEY_derive( ctx, secret, &secret_len ) ) );
std::cout << "Shared secret: " << std::string( reinterpret_cast<char *>( secret ) ) << std::endl;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(peerkey);
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(kctx);
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(pctx);
EC_KEY_free( Key1 );
// EC_POINT_free( Point1 ); // Can't free the Point because its a const pointer. It wont let me free() even if I use const_cast.
// EC_POINT_free( const_cast< EC_POINT *>( Point1 ) ); // Can't free the Point because its a const pointer. It wont let me free() even if I use const_cast.
EC_KEY_free( Key2 );
std::cout << "Successful run!" << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment