Since I couldn't find any code showing how to protect arbitrary blocks
of data using OpenSSL's implementation of ECC+AES I've decided to share
what I developed by posting it to the list. The goal was to follow the
SECG standard for ECIES. I only gave the document describing the
standard a cursory reading and would welcome anyone's feedback.
Hopefully someday I'll be able to use the EVP_Seal interface to
accomplish the same thing as the code I'm sending out. ;)
On a side note, I started working on this code in an effort to replace
an equivalent piecemeal implementation I built years ago atop Libgcrypt.
Naturally I ran a number of simple benchmarks to compare my new
implementation based on OpenSSL against the older Libgcrypt code. I was
pleasantly surprised find the OpenSSL implementation ~10 to ~15 times
faster depending on the size of the data I encrypted/decrypted (using
equivalent curves/key sizes).
I hereby place the attached code in the public domain. As such it comes
without any warranty regarding its merchantability or fitness for a
particular purpose. Please use it at your own risk.
--
Ladar Levison
Lavabit LLC
http://lavabit.com
/**
* @file /cryptron/example.c
*
* @brief Example code for using the provided ECIES functions to encrypt data.
*
* $Author: Ladar Levison $
* $Website: http://lavabit.com $
* $Date: 2010/08/06 06:03:04 $
* $Revision: ccd79bf03e3e68a3cce213890129aec55a76d301 $
*
*/
#include "ecies.h"
void processor_cleanup(EC_KEY *key, secure_t *ciphered, char *hex_pub, char
*hex_priv, unsigned char *text, unsigned char *copy, unsigned char *original) {
if (key) {
ecies_key_free(key);
}
if (ciphered) {
secure_free(ciphered);
}
if (hex_pub) {
OPENSSL_free(hex_pub);
}
if (hex_priv) {
OPENSSL_free(hex_priv);
}
if (text) {
free(text);
}
if (copy) {
free(copy);
}
if (original) {
free(original);
}
return;
}
int processor(int iteration) {
int tlen;
size_t olen;
EC_KEY *key = NULL;
secure_t *ciphered = NULL;
char *hex_pub = NULL, *hex_priv = NULL;
unsigned char *text = NULL, *copy = NULL, *original = NULL;
// Generate random size for the block of data were going to encrypt.
Use a min value of 1 KB and a max of 1 MB.
do {
tlen = (rand() % (1024 * 1024));
} while (tlen < 1024);
if (!(text = malloc(tlen + 1)) || !(copy = malloc(tlen + 1))) {
printf("Memory error.\n");
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
return -1;
}
// Wipe and then fill the data blocks with random data.
memset(copy, 0, tlen + 1);
memset(text, 0, tlen + 1);
for (uint64_t j = 0; j < tlen; j++) {
*(copy + j) = *(text + j) = (rand() % 255);
}
// Generate a key for our theoretical user.
if (!(key = ecies_key_create())) {
printf("Key creation failed.\n");
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
return -1;
}
// Since we'll store the keys as hex values in reali life, extract the
appropriate hex values and release the original key structure.
if (!(hex_pub = ecies_key_public_get_hex(key)) || !(hex_priv =
ecies_key_private_get_hex(key))) {
printf("Serialization of the key to a pair of hex strings
failed.\n");
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
return -1;
}
if (!(ciphered = ecies_encrypt(hex_pub, text, tlen))) {
printf("The encryption process failed!\n");
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
return -1;
}
if (!(original = ecies_decrypt(hex_priv, ciphered, &olen))) {
printf("The decryption process failed!\n");
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
return -1;
}
if (olen != tlen || memcmp(original, copy, tlen)) {
printf("Comparison failure.\n");
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
return -1;
}
processor_cleanup(key, ciphered, hex_pub, hex_priv, text, copy,
original);
printf(" ... %i ... %i\n", iteration + 1, tlen);
return 0;
}
void main_cleanup(void) {
ecies_group_free();
// As a child I was taught that your done eating until your plate is
completely clean.
// The following should release _all_ of the memory allocated by the
OpenSSL functions used.
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_thread_state(NULL);
sk_pop_free((_STACK *)SSL_COMP_get_compression_methods(), CRYPTO_free);
return;
}
int main() {
SSL_library_init();
SSL_load_error_strings();
// Initializing the group once up front cut execution time in half!
However the code should function without a reusable group.
ecies_group_init();
// Comment this line out if you want the program to execute
consistently each time.
srand(time(NULL));
for (uint64_t i = 0; i < 100; i++) {
if (processor(i)) {
main_cleanup();
return 1;
}
}
printf("Finished.\n");
main_cleanup();
return 0;
}
/**
* @file /cryptron/ecies.c
*
* @brief ECIES encryption/decryption functions.
*
* $Author: Ladar Levison $
* $Website: http://lavabit.com $
* $Date: 2010/08/06 06:02:03 $
* $Revision: a51931d0f81f6abe29ca91470931d41a374508a7 $
*
*/
#include "ecies.h"
void * ecies_key_derivation(const void *input, size_t ilen, void *output,
size_t *olen) {
if (*olen < SHA512_DIGEST_LENGTH) {
return NULL;
}
*olen = SHA512_DIGEST_LENGTH;
return SHA512(input, ilen, output);
}
secure_t * ecies_encrypt(char *key, unsigned char *data, size_t length) {
void *body;
HMAC_CTX hmac;
int body_length;
secure_t *cryptex;
EVP_CIPHER_CTX cipher;
unsigned int mac_length;
EC_KEY *user, *ephemeral;
size_t envelope_length, block_length, key_length;
unsigned char envelope_key[SHA512_DIGEST_LENGTH],
iv[EVP_MAX_IV_LENGTH], block[EVP_MAX_BLOCK_LENGTH];
// Simple sanity check.
if (!key || !data || !length) {
printf("Invalid parameters passed in.\n");
return NULL;
}
// Make sure we are generating enough key material for the symmetric
ciphers.
if ((key_length = EVP_CIPHER_key_length(ECIES_CIPHER)) * 2 >
SHA512_DIGEST_LENGTH) {
printf("The key derivation method will not produce enough
envelope key material for the chosen ciphers. {envelope = %i / required =
%zu}", SHA512_DIGEST_LENGTH / 8,
(key_length * 2) / 8);
return NULL;
}
// Convert the user's public key from hex into a full EC_KEY structure.
if (!(user = ecies_key_create_public_hex(key))) {
printf("Invalid public key provided.\n");
return NULL;
}
// Create the ephemeral key used specifically for this block of data.
else if (!(ephemeral = ecies_key_create())) {
printf("An error occurred while trying to generate the
ephemeral key.\n");
EC_KEY_free(user);
return NULL;
}
// Use the intersection of the provided keys to generate the envelope
data used by the ciphers below. The ecies_key_derivation() function uses
// SHA 512 to ensure we have a sufficient amount of envelope key
material and that the material created is sufficiently secure.
else if (ECDH_compute_key(envelope_key, SHA512_DIGEST_LENGTH,
EC_KEY_get0_public_key(user), ephemeral, ecies_key_derivation) !=
SHA512_DIGEST_LENGTH) {
printf("An error occurred while trying to compute the envelope
key. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(ephemeral);
EC_KEY_free(user);
return NULL;
}
// Determine the envelope and block lengths so we can allocate a buffer
for the result.
else if ((block_length = EVP_CIPHER_block_size(ECIES_CIPHER)) == 0 ||
block_length > EVP_MAX_BLOCK_LENGTH || (envelope_length =
EC_POINT_point2oct(EC_KEY_get0_group(
ephemeral), EC_KEY_get0_public_key(ephemeral),
POINT_CONVERSION_COMPRESSED, NULL, 0, NULL)) == 0) {
printf("Invalid block or envelope length. {block = %zu /
envelope = %zu}\n", block_length, envelope_length);
EC_KEY_free(ephemeral);
EC_KEY_free(user);
return NULL;
}
// We use a conditional to pad the length if the input buffer is not
evenly divisible by the block size.
else if (!(cryptex = secure_alloc(envelope_length,
EVP_MD_size(ECIES_HASHER), length, length + (length % block_length ?
(block_length - (length % block_length)) : 0)))) {
printf("Unable to allocate a secure_t buffer to hold the
encrypted result.\n");
EC_KEY_free(ephemeral);
EC_KEY_free(user);
return NULL;
}
// Store the public key portion of the ephemeral key.
else if (EC_POINT_point2oct(EC_KEY_get0_group(ephemeral),
EC_KEY_get0_public_key(ephemeral), POINT_CONVERSION_COMPRESSED,
secure_key_data(cryptex), envelope_length,
NULL) != envelope_length) {
printf("An error occurred while trying to record the public
portion of the envelope key. {error = %s}\n", ERR_error_string(ERR_get_error(),
NULL));
EC_KEY_free(ephemeral);
EC_KEY_free(user);
secure_free(cryptex);
return NULL;
}
// The envelope key has been stored so we no longer need to keep the
keys around.
EC_KEY_free(ephemeral);
EC_KEY_free(user);
// For now we use an empty initialization vector.
memset(iv, 0, EVP_MAX_IV_LENGTH);
// Setup the cipher context, the body length, and store a pointer to
the body buffer location.
EVP_CIPHER_CTX_init(&cipher);
body = secure_body_data(cryptex);
body_length = secure_body_length(cryptex);
// Initialize the cipher with the envelope key.
if (EVP_EncryptInit_ex(&cipher, ECIES_CIPHER, NULL, envelope_key, iv)
!= 1 || EVP_CIPHER_CTX_set_padding(&cipher, 0) != 1 ||
EVP_EncryptUpdate(&cipher, body,
&body_length, data, length - (length % block_length))
!= 1) {
printf("An error occurred while trying to secure the data using
the chosen symmetric cipher. {error = %s}\n", ERR_error_string(ERR_get_error(),
NULL));
EVP_CIPHER_CTX_cleanup(&cipher);
secure_free(cryptex);
return NULL;
}
// Check whether all of the data was encrypted. If they don't match up,
we either have a partial block remaining, or an error occurred.
else if (body_length != length) {
// Make sure all that remains is a partial block, and their
wasn't an error.
if (length - body_length >= block_length) {
printf("Unable to secure the data using the chosen
symmetric cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(&cipher);
secure_free(cryptex);
return NULL;
}
// Copy the remaining data into our partial block buffer. The
memset() call ensures any extra bytes will be zero'ed out.
memset(block, 0, EVP_MAX_BLOCK_LENGTH);
memcpy(block, data + body_length, length - body_length);
// Advance the body pointer to the location of the remaining
space, and calculate just how much room is still available.
body += body_length;
if ((body_length = secure_body_length(cryptex) - body_length) <
0) {
printf("The symmetric cipher overflowed!\n");
EVP_CIPHER_CTX_cleanup(&cipher);
secure_free(cryptex);
return NULL;
}
// Pass the final partially filled data block into the cipher
as a complete block. The padding will be removed during the decryption process.
else if (EVP_EncryptUpdate(&cipher, body, &body_length, block,
block_length) != 1) {
printf("Unable to secure the data using the chosen
symmetric cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(&cipher);
secure_free(cryptex);
return NULL;
}
}
// Advance the pointer, then use pointer arithmetic to calculate how
much of the body buffer has been used. The complex logic is needed so that we
get
// the correct status regardless of whether there was a partial data
block.
body += body_length;
if ((body_length = secure_body_length(cryptex) - (body -
secure_body_data(cryptex))) < 0) {
printf("The symmetric cipher overflowed!\n");
EVP_CIPHER_CTX_cleanup(&cipher);
secure_free(cryptex);
return NULL;
}
else if (EVP_EncryptFinal_ex(&cipher, body, &body_length) != 1) {
printf("Unable to secure the data using the chosen symmetric
cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(&cipher);
secure_free(cryptex);
return NULL;
}
EVP_CIPHER_CTX_cleanup(&cipher);
// Generate an authenticated hash which can be used to validate the
data during decryption.
HMAC_CTX_init(&hmac);
mac_length = secure_mac_length(cryptex);
// At the moment we are generating the hash using encrypted data. At
some point we may want to validate the original text instead.
if (HMAC_Init_ex(&hmac, envelope_key + key_length, key_length,
ECIES_HASHER, NULL) != 1 || HMAC_Update(&hmac, secure_body_data(cryptex),
secure_body_length(cryptex))
!= 1 || HMAC_Final(&hmac, secure_mac_data(cryptex),
&mac_length) != 1) {
printf("Unable to generate a data authentication code. {error =
%s}\n", ERR_error_string(ERR_get_error(), NULL));
HMAC_CTX_cleanup(&hmac);
secure_free(cryptex);
return NULL;
}
HMAC_CTX_cleanup(&hmac);
return cryptex;
}
unsigned char * ecies_decrypt(char *key, secure_t *cryptex, size_t *length) {
HMAC_CTX hmac;
size_t key_length;
int output_length;
EVP_CIPHER_CTX cipher;
EC_KEY *user, *ephemeral;
unsigned int mac_length = EVP_MAX_MD_SIZE;
unsigned char envelope_key[SHA512_DIGEST_LENGTH],
iv[EVP_MAX_IV_LENGTH], md[EVP_MAX_MD_SIZE], *block, *output;
// Simple sanity check.
if (!key || !cryptex || !length) {
printf("Invalid parameters passed in.\n");
return NULL;
}
// Make sure we are generating enough key material for the symmetric
ciphers.
else if ((key_length = EVP_CIPHER_key_length(ECIES_CIPHER)) * 2 >
SHA512_DIGEST_LENGTH) {
printf("The key derivation method will not produce enough
envelope key material for the chosen ciphers. {envelope = %i / required =
%zu}", SHA512_DIGEST_LENGTH / 8,
(key_length * 2) / 8);
return NULL;
}
// Convert the user's public key from hex into a full EC_KEY structure.
else if (!(user = ecies_key_create_private_hex(key))) {
printf("Invalid private key provided.\n");
return NULL;
}
// Create the ephemeral key used specifically for this block of data.
else if (!(ephemeral =
ecies_key_create_public_octets(secure_key_data(cryptex),
secure_key_length(cryptex)))) {
printf("An error occurred while trying to recreate the
ephemeral key.\n");
EC_KEY_free(user);
return NULL;
}
// Use the intersection of the provided keys to generate the envelope
data used by the ciphers below. The ecies_key_derivation() function uses
// SHA 512 to ensure we have a sufficient amount of envelope key
material and that the material created is sufficiently secure.
else if (ECDH_compute_key(envelope_key, SHA512_DIGEST_LENGTH,
EC_KEY_get0_public_key(ephemeral), user, ecies_key_derivation) !=
SHA512_DIGEST_LENGTH) {
printf("An error occurred while trying to compute the envelope
key. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(ephemeral);
EC_KEY_free(user);
return NULL;
}
// The envelope key material has been extracted, so we no longer need
the user and ephemeral keys.
EC_KEY_free(ephemeral);
EC_KEY_free(user);
// Use the authenticated hash of the ciphered data to ensure it was not
modified after being encrypted.
HMAC_CTX_init(&hmac);
// At the moment we are generating the hash using encrypted data. At
some point we may want to validate the original text instead.
if (HMAC_Init_ex(&hmac, envelope_key + key_length, key_length,
ECIES_HASHER, NULL) != 1 || HMAC_Update(&hmac, secure_body_data(cryptex),
secure_body_length(cryptex))
!= 1 || HMAC_Final(&hmac, md, &mac_length) != 1) {
printf("Unable to generate the authentication code needed for
validation. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
HMAC_CTX_cleanup(&hmac);
return NULL;
}
HMAC_CTX_cleanup(&hmac);
// We can use the generated hash to ensure the encrypted data was not
altered after being encrypted.
if (mac_length != secure_mac_length(cryptex) || memcmp(md,
secure_mac_data(cryptex), mac_length)) {
printf("The authentication code was invalid! The ciphered data
has been corrupted!\n");
return NULL;
}
// Create a buffer to hold the result.
output_length = secure_body_length(cryptex);
if (!(block = output = malloc(output_length + 1))) {
printf("An error occurred while trying to allocate memory for
the decrypted data.\n");
return NULL;
}
// For now we use an empty initialization vector. We also clear out the
result buffer just to be on the safe side.
memset(iv, 0, EVP_MAX_IV_LENGTH);
memset(output, 0, output_length + 1);
EVP_CIPHER_CTX_init(&cipher);
// Decrypt the data using the chosen symmetric cipher.
if (EVP_DecryptInit_ex(&cipher, ECIES_CIPHER, NULL, envelope_key, iv)
!= 1 || EVP_CIPHER_CTX_set_padding(&cipher, 0) != 1 ||
EVP_DecryptUpdate(&cipher, block,
&output_length, secure_body_data(cryptex),
secure_body_length(cryptex)) != 1) {
printf("Unable to decrypt the data using the chosen symmetric
cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(&cipher);
free(output);
return NULL;
}
block += output_length;
if ((output_length = secure_body_length(cryptex) - output_length) != 0)
{
printf("The symmetric cipher failed to properly decrypt the
correct amount of data!\n");
EVP_CIPHER_CTX_cleanup(&cipher);
free(output);
return NULL;
}
if (EVP_DecryptFinal_ex(&cipher, block, &output_length) != 1) {
printf("Unable to decrypt the data using the chosen symmetric
cipher. {error = %s}\n", ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(&cipher);
free(output);
return NULL;
}
EVP_CIPHER_CTX_cleanup(&cipher);
*length = secure_orig_length(cryptex);
return output;
}
/**
* @file /cryptron/ecies.h
*
* @brief ECIES module functions.
*
* $Author: Ladar Levison $
* $Website: http://lavabit.com $
* $Date: 2010/08/06 06:02:03 $
* $Revision: a51931d0f81f6abe29ca91470931d41a374508a7 $
*
*/
#ifndef LAVABIT_ECIES_H
#define LAVABIT_ECIES_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <openssl/ssl.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/stack.h>
#define ECIES_CURVE NID_secp521r1
#define ECIES_CIPHER EVP_aes_256_cbc()
#define ECIES_HASHER EVP_sha512()
typedef struct {
struct {
uint64_t key;
uint64_t mac;
uint64_t orig;
uint64_t body;
} length;
} secure_head_t;
typedef char * secure_t;
void secure_free(secure_t *cryptex);
void * secure_key_data(secure_t *cryptex);
void * secure_mac_data(secure_t *cryptex);
void * secure_body_data(secure_t *cryptex);
uint64_t secure_key_length(secure_t *cryptex);
uint64_t secure_mac_length(secure_t *cryptex);
uint64_t secure_body_length(secure_t *cryptex);
uint64_t secure_orig_length(secure_t *cryptex);
uint64_t secure_total_length(secure_t *cryptex);
void * secure_alloc(uint64_t key, uint64_t mac, uint64_t orig, uint64_t body);
void ecies_group_init(void);
void ecies_group_free(void);
EC_GROUP * ecies_group(void);
void ecies_key_free(EC_KEY *key);
EC_KEY * ecies_key_create(void);
EC_KEY * ecies_key_create_public_hex(char *hex);
EC_KEY * ecies_key_create_private_hex(char *hex);
EC_KEY * ecies_key_create_public_octets(unsigned char *octets, size_t length);
char * ecies_key_public_get_hex(EC_KEY *key);
char * ecies_key_private_get_hex(EC_KEY *key);
secure_t * ecies_encrypt(char *key, unsigned char *data, size_t length);
unsigned char * ecies_decrypt(char *key, secure_t *cryptex, size_t *length);
#endif
/**
* @file /cryptron/keys.c
*
* @brief EC key management functions.
*
* $Author: Ladar Levison $
* $Website: http://lavabit.com $
* $Date: 2010/08/06 06:02:03 $
* $Revision: a51931d0f81f6abe29ca91470931d41a374508a7 $
*
*/
#include "ecies.h"
EC_GROUP *eliptic = NULL;
void ecies_group_init(void) {
EC_GROUP *group;
if (!(group = EC_GROUP_new_by_curve_name(ECIES_CURVE))) {
printf("EC_GROUP_new_by_curve_name failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
}
else if (EC_GROUP_precompute_mult(group, NULL) != 1) {
printf("EC_GROUP_precompute_mult failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
}
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_COMPRESSED);
eliptic = group;
return;
}
void ecies_group_free(void) {
EC_GROUP *group = eliptic;
eliptic = NULL;
if (group) {
EC_GROUP_free(group);
}
return;
}
// This is not thread-safe! You'll need to use a mutex if you want this to work
in a multi-threaded world.
// But its worth noting that duplicating the group instead of allocating it on
each pass reduced the execution time by 50%!
EC_GROUP * ecies_group(void) {
EC_GROUP *group;
if (eliptic) {
return EC_GROUP_dup(eliptic);
}
if (!(group = EC_GROUP_new_by_curve_name(ECIES_CURVE))) {
printf("EC_GROUP_new_by_curve_name failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
else if (EC_GROUP_precompute_mult(group, NULL) != 1) {
printf("EC_GROUP_precompute_mult failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
return NULL;
}
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_COMPRESSED);
return EC_GROUP_dup(group);
}
void ecies_key_free(EC_KEY *key) {
EC_KEY_free(key);
return;
}
EC_KEY * ecies_key_create(void) {
EC_GROUP *group;
EC_KEY *key = NULL;
if (!(key = EC_KEY_new())) {
printf("EC_KEY_new failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(group = ecies_group())) {
EC_KEY_free(key);
return NULL;
}
if (EC_KEY_set_group(key, group) != 1) {
printf("EC_KEY_set_group failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_KEY_free(key);
return NULL;
}
EC_GROUP_free(group);
if (EC_KEY_generate_key(key) != 1) {
printf("EC_KEY_generate_key failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
return key;
}
EC_KEY * ecies_key_create_public_octets(unsigned char *octets, size_t length) {
EC_GROUP *group;
EC_KEY *key = NULL;
EC_POINT *point = NULL;
if (!(key = EC_KEY_new())) {
printf("EC_KEY_new failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(group = ecies_group())) {
EC_KEY_free(key);
return NULL;
}
if (EC_KEY_set_group(key, group) != 1) {
printf("EC_KEY_set_group failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_KEY_free(key);
return NULL;
}
if (!(point = EC_POINT_new(group))) {
printf("EC_POINT_new failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_KEY_free(key);
return NULL;
}
if (EC_POINT_oct2point(group, point, octets, length, NULL) != 1) {
printf("EC_POINT_oct2point failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_KEY_free(key);
return NULL;
}
if (EC_KEY_set_public_key(key, point) != 1) {
printf("EC_KEY_set_public_key failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_POINT_free(point);
EC_KEY_free(key);
return NULL;
}
EC_GROUP_free(group);
EC_POINT_free(point);
if (EC_KEY_check_key(key) != 1) {
printf("EC_KEY_check_key failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
return key;
}
EC_KEY * ecies_key_create_public_hex(char *hex) {
EC_GROUP *group;
EC_KEY *key = NULL;
EC_POINT *point = NULL;
if (!(key = EC_KEY_new())) {
printf("EC_KEY_new\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(group = EC_GROUP_new_by_curve_name(ECIES_CURVE))) {
printf("EC_GROUP_new_by_curve_name failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_COMPRESSED);
if (EC_KEY_set_group(key, group) != 1) {
printf("EC_KEY_set_group\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_KEY_free(key);
return NULL;
}
if (!(point = EC_POINT_hex2point(group, hex, NULL, NULL))) {
printf("EC_POINT_hex2point\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
if (EC_KEY_set_public_key(key, point) != 1) {
printf("EC_KEY_set_public_key\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_POINT_free(point);
EC_KEY_free(key);
return NULL;
}
EC_GROUP_free(group);
EC_POINT_free(point);
if (EC_KEY_check_key(key) != 1) {
printf("EC_KEY_check_key\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
return key;
}
char * ecies_key_public_get_hex(EC_KEY *key) {
char *hex;
const EC_POINT *point;
const EC_GROUP *group;
if (!(point = EC_KEY_get0_public_key(key))) {
printf("EC_KEY_get0_public_key\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(group = EC_KEY_get0_group(key))) {
printf("EC_KEY_get0_group\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(hex = EC_POINT_point2hex(group, point,
POINT_CONVERSION_COMPRESSED, NULL))) {
printf("EC_POINT_point2hex\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
//printf("PUB: %s\n", hex);
return hex;
}
EC_KEY * ecies_key_create_private_hex(char *hex) {
EC_GROUP *group;
BIGNUM *bn = NULL;
EC_KEY *key = NULL;
if (!(key = EC_KEY_new())) {
printf("EC_KEY_new\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(group = EC_GROUP_new_by_curve_name(ECIES_CURVE))) {
printf("EC_GROUP_new_by_curve_name failed. {error = %s}\n",
ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_COMPRESSED);
if (EC_KEY_set_group(key, group) != 1) {
printf("EC_KEY_set_group\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_GROUP_free(group);
EC_KEY_free(key);
return NULL;
}
EC_GROUP_free(group);
if (!(BN_hex2bn(&bn, hex))) {
printf("BN_hex2bn\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
return NULL;
}
if (EC_KEY_set_private_key(key, bn) != 1) {
printf("EC_KEY_set_public_key\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
EC_KEY_free(key);
BN_free(bn);
return NULL;
}
BN_free(bn);
return key;
}
char * ecies_key_private_get_hex(EC_KEY *key) {
char *hex;
const BIGNUM *bn;
if (!(bn = EC_KEY_get0_private_key(key))) {
printf("EC_KEY_get0_private_key\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
if (!(hex = BN_bn2hex(bn))) {
printf("BN_bn2hex\n");
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
//printf("PRIV: %s\n", hex);
return hex;
}
/**
* @file /cryptron/secure.c
*
* @brief Functions for handling the secure data type.
*
* $Author: Ladar Levison $
* $Website: http://lavabit.com $
* $Date: 2010/08/05 11:43:50 $
* $Revision: c363dfa193830feb5d014a7c6f0abf2d1365f668 $
*
*/
#include "ecies.h"
uint64_t secure_key_length(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return head->length.key;
}
uint64_t secure_mac_length(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return head->length.mac;
}
uint64_t secure_body_length(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return head->length.body;
}
uint64_t secure_orig_length(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return head->length.orig;
}
uint64_t secure_total_length(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return sizeof(secure_head_t) + (head->length.key + head->length.mac +
head->length.body);
}
void * secure_key_data(secure_t *cryptex) {
return (char *)cryptex + sizeof(secure_head_t);
}
void * secure_mac_data(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return (char *)cryptex + (sizeof(secure_head_t) + head->length.key);
}
void * secure_body_data(secure_t *cryptex) {
secure_head_t *head = (secure_head_t *)cryptex;
return (char *)cryptex + (sizeof(secure_head_t) + head->length.key +
head->length.mac);
}
void * secure_alloc(uint64_t key, uint64_t mac, uint64_t orig, uint64_t body) {
secure_t *cryptex = malloc(sizeof(secure_head_t) + key + mac + body);
secure_head_t *head = (secure_head_t *)cryptex;
head->length.key = key;
head->length.mac = mac;
head->length.orig = orig;
head->length.body = body;
return cryptex;
}
void secure_free(secure_t *cryptex) {
free(cryptex);
return;
}