authme-unix/src/mpass_openssl.c
authme_err_t
mpass_openssl_envelope_encrypt(mpass_handle mh, int key, unsigned char * in_buf, size_t in_buf_len, unsigned char ** out_buf, size_t * out_buf_len)
{
	unsigned char * worker_buf;
	int worker_buf_len;
	unsigned char * wrap_buf;
	size_t wrap_buf_len;
	int i, j;
	EVP_CIPHER_CTX *ctx;
	EVP_PKEY_CTX *pctx;
	EVP_PKEY * pkey;
	unsigned char aes_key[EVP_MAX_KEY_LENGTH];
	unsigned char aes_iv[EVP_MAX_IV_LENGTH];
	int aes_iv_len;
	int aes_key_len;
	authme_master_password_t * amp = (authme_master_password_t *)mh;

	if (amp == NULL)
		return AUTHME_ERR_NO_CRYPTO;

	/* Sanity check */
	switch (key)
	{
	case MPASS_SERVICE_PUBLIC_KEY:
		pkey = amp->amp_service_public_key;
		break;
	case MPASS_USER_PUBLIC_KEY:
		pkey = amp->amp_user_public_key;
		break;
	default:
		MPASS_SET_ERROR(amp, "Unknown key passed into envelope encrypt");
		return AUTHME_ERR_INVALID_KEY;
	}

	/* Allocate enough space for the AES crypto part*/
	worker_buf_len = (int)in_buf_len + EVP_MAX_BLOCK_LENGTH + EVP_MAX_IV_LENGTH;
	if ((worker_buf = (unsigned char *)malloc(worker_buf_len)) == NULL)
	{
		// This would be bad!
		return AUTHME_ERR_OUT_OF_MEMORY;
	}

	// Now start creating keys and things
	if (RAND_bytes(aes_key, sizeof(aes_key)) != 1 ||
		RAND_bytes(aes_iv, sizeof(aes_iv)) != 1 ||
		(ctx = EVP_CIPHER_CTX_new()) == NULL)
	{
		// Also bad
		free(worker_buf);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_INIT;
	}

	EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, aes_key, aes_iv, 1);
	aes_iv_len = EVP_CIPHER_CTX_iv_length(ctx);
	aes_key_len = EVP_CIPHER_CTX_key_length(ctx);

	/* Sanity checks */
	if ((aes_iv_len + in_buf_len + EVP_CIPHER_CTX_block_size(ctx)) > worker_buf_len)
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, "Internal assertion on buffer lengths failed - help!");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	// Easy day - let's encrypt!
	memcpy(worker_buf, aes_iv, aes_iv_len);
	i = worker_buf_len - aes_iv_len;
	if (!EVP_CipherUpdate(ctx, &worker_buf[aes_iv_len], &i, in_buf, (int)in_buf_len))
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;

	}
	j = worker_buf_len - aes_iv_len - i;

	if (!EVP_CipherFinal_ex(ctx, &worker_buf[aes_iv_len + i], &j))
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	// Done the AES part
	EVP_CIPHER_CTX_free(ctx);
	worker_buf_len = aes_iv_len + i + j;

	// Now the RSA part
	if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	// Initialise ctx
	if (EVP_PKEY_encrypt_init(pctx) <= 0 ||
		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) <= 0)
	{
		free(worker_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	// Get buffer length to write to
	if (EVP_PKEY_encrypt(pctx, NULL, &wrap_buf_len, aes_key, aes_key_len) <= 0)
	{
		free(worker_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	if ((wrap_buf = (unsigned char *)malloc(wrap_buf_len)) == NULL)
	{
		free(worker_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, "Error allocating memory for crypto operation");
		return AUTHME_ERR_OUT_OF_MEMORY;
	}

	// Encrypt
	if (EVP_PKEY_encrypt(pctx, wrap_buf, &wrap_buf_len, aes_key, aes_key_len) <= 0)
	{
		free(worker_buf);
		free(wrap_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	// Done - cleanup and copy to output
	memset(aes_key, 0, sizeof(aes_key));

	*out_buf_len = 4 + (int)wrap_buf_len + worker_buf_len;
	if ((*out_buf = (unsigned char *)malloc(*out_buf_len)) == NULL)
	{
		free(worker_buf);
		free(wrap_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, "Error allocating final buffer");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	// For our envelope, start of the buffer is always a 4 byte unsigned int
	(*out_buf)[0] = ((unsigned int)wrap_buf_len >> 24) & 0xFF;
	(*out_buf)[1] = ((unsigned int)wrap_buf_len >> 16) & 0xFF;
	(*out_buf)[2] = ((unsigned int)wrap_buf_len >> 8) & 0xFF;
	(*out_buf)[3] = (unsigned int)wrap_buf_len & 0xFF;

	// Then the wrap itself
	memcpy(&((*out_buf)[4]), wrap_buf, wrap_buf_len);

	// then the encrypted data
	memcpy(&((*out_buf)[4 + wrap_buf_len]), worker_buf, worker_buf_len);

	free(worker_buf);
	free(wrap_buf);

	return AUTHME_ERR_OK;

}
/* ---------------------------------------------------------------- *
* Encrypt with a randomly generated AES key and then wrap the key
* using the provided public key
* ---------------------------------------------------------------- */
Encrypt with a randomly generated AES key and then wrap the key
using the provided public key
Encrypt with a randomly generated AES key and then wrap the key using the provided public key
authme_err_t
mpass_openssl_envelope_encrypt(mpass_handle mh, int key, unsigned char * in_buf, size_t in_buf_len, unsigned char ** out_buf, size_t * out_buf_len)
{
	unsigned char * worker_buf;
	int worker_buf_len;
	unsigned char * wrap_buf;
	size_t wrap_buf_len;
	int i, j;
	EVP_CIPHER_CTX *ctx;
	EVP_PKEY_CTX *pctx;
	EVP_PKEY * pkey;
	unsigned char aes_key[EVP_MAX_KEY_LENGTH];
	unsigned char aes_iv[EVP_MAX_IV_LENGTH];
	int aes_iv_len;
	int aes_key_len;
	authme_master_password_t * amp = (authme_master_password_t *)mh;
	if (amp == NULL)
		return AUTHME_ERR_NO_CRYPTO;
	switch (key)
	{
	case MPASS_SERVICE_PUBLIC_KEY:
		pkey = amp->amp_service_public_key;
		break;
	case MPASS_USER_PUBLIC_KEY:
		pkey = amp->amp_user_public_key;
		break;
	default:
		MPASS_SET_ERROR(amp, "Unknown key passed into envelope encrypt");
		return AUTHME_ERR_INVALID_KEY;
	}
	worker_buf_len = (int)in_buf_len + EVP_MAX_BLOCK_LENGTH + EVP_MAX_IV_LENGTH;
	if ((worker_buf = (unsigned char *)malloc(worker_buf_len)) == NULL)
	{
		return AUTHME_ERR_OUT_OF_MEMORY;
	}
	if (RAND_bytes(aes_key, sizeof(aes_key)) != 1 ||
		RAND_bytes(aes_iv, sizeof(aes_iv)) != 1 ||
		(ctx = EVP_CIPHER_CTX_new()) == NULL)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_INIT;
	}
	EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, aes_key, aes_iv, 1);
	aes_iv_len = EVP_CIPHER_CTX_iv_length(ctx);
	aes_key_len = EVP_CIPHER_CTX_key_length(ctx);
	if ((aes_iv_len + in_buf_len + EVP_CIPHER_CTX_block_size(ctx)) > worker_buf_len)
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, "Internal assertion on buffer lengths failed - help!");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	memcpy(worker_buf, aes_iv, aes_iv_len);
	i = worker_buf_len - aes_iv_len;
	if (!EVP_CipherUpdate(ctx, &worker_buf[aes_iv_len], &i, in_buf, (int)in_buf_len))
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	j = worker_buf_len - aes_iv_len - i;
	if (!EVP_CipherFinal_ex(ctx, &worker_buf[aes_iv_len + i], &j))
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	EVP_CIPHER_CTX_free(ctx);
	worker_buf_len = aes_iv_len + i + j;
	if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	if (EVP_PKEY_encrypt_init(pctx) <= 0 ||
		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) <= 0)
	{
		free(worker_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	if (EVP_PKEY_encrypt(pctx, NULL, &wrap_buf_len, aes_key, aes_key_len) <= 0)
	{
		free(worker_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	if ((wrap_buf = (unsigned char *)malloc(wrap_buf_len)) == NULL)
	{
		free(worker_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, "Error allocating memory for crypto operation");
		return AUTHME_ERR_OUT_OF_MEMORY;
	}
	if (EVP_PKEY_encrypt(pctx, wrap_buf, &wrap_buf_len, aes_key, aes_key_len) <= 0)
	{
		free(worker_buf);
		free(wrap_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, strdup(ERR_error_string(ERR_get_error(), NULL)));
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	memset(aes_key, 0, sizeof(aes_key));
	*out_buf_len = 4 + (int)wrap_buf_len + worker_buf_len;
	if ((*out_buf = (unsigned char *)malloc(*out_buf_len)) == NULL)
	{
		free(worker_buf);
		free(wrap_buf);
		EVP_PKEY_CTX_free(pctx);
		MPASS_SET_ERROR(amp, "Error allocating final buffer");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	(*out_buf)[0] = ((unsigned int)wrap_buf_len >> 24) & 0xFF;
	(*out_buf)[1] = ((unsigned int)wrap_buf_len >> 16) & 0xFF;
	(*out_buf)[2] = ((unsigned int)wrap_buf_len >> 8) & 0xFF;
	(*out_buf)[3] = (unsigned int)wrap_buf_len & 0xFF;
	memcpy(&((*out_buf)[4]), wrap_buf, wrap_buf_len);
	memcpy(&((*out_buf)[4 + wrap_buf_len]), worker_buf, worker_buf_len);
	free(worker_buf);
	free(wrap_buf);
	return AUTHME_ERR_OK;
}
authme_err_t mpass_openssl_envelope_encrypt ( mpass_handle mh , int key , unsigned char * in_buf , size_t in_buf_len , unsigned char * * out_buf , size_t * out_buf_len ) { unsigned char * worker_buf ; int worker_buf_len ; unsigned char * wrap_buf ; size_t wrap_buf_len ; int i , j ; EVP_CIPHER_CTX * ctx ; EVP_PKEY_CTX * pctx ; EVP_PKEY * pkey ; unsigned char aes_key [ EVP_MAX_KEY_LENGTH ] ; unsigned char aes_iv [ EVP_MAX_IV_LENGTH ] ; int aes_iv_len ; int aes_key_len ; authme_master_password_t * amp = ( authme_master_password_t * ) mh ; if ( amp == NULL ) return AUTHME_ERR_NO_CRYPTO ; switch ( key ) { case MPASS_SERVICE_PUBLIC_KEY : pkey = amp -> amp_service_public_key ; break ; case MPASS_USER_PUBLIC_KEY : pkey = amp -> amp_user_public_key ; break ; default : MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_INVALID_KEY ; } worker_buf_len = ( int ) in_buf_len + EVP_MAX_BLOCK_LENGTH + EVP_MAX_IV_LENGTH ; if ( ( worker_buf = ( unsigned char * ) malloc ( worker_buf_len ) ) == NULL ) { return AUTHME_ERR_OUT_OF_MEMORY ; } if ( RAND_bytes ( aes_key , sizeof ( aes_key ) ) != 1 || RAND_bytes ( aes_iv , sizeof ( aes_iv ) ) != 1 || ( ctx = EVP_CIPHER_CTX_new ( ) ) == NULL ) { free ( worker_buf ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_INIT ; } EVP_CipherInit_ex ( ctx , EVP_aes_256_cbc ( ) , NULL , aes_key , aes_iv , 1 ) ; aes_iv_len = EVP_CIPHER_CTX_iv_length ( ctx ) ; aes_key_len = EVP_CIPHER_CTX_key_length ( ctx ) ; if ( ( aes_iv_len + in_buf_len + EVP_CIPHER_CTX_block_size ( ctx ) ) > worker_buf_len ) { free ( worker_buf ) ; EVP_CIPHER_CTX_free ( ctx ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } memcpy ( worker_buf , aes_iv , aes_iv_len ) ; i = worker_buf_len - aes_iv_len ; if ( ! EVP_CipherUpdate ( ctx , & worker_buf [ aes_iv_len ] , & i , in_buf , ( int ) in_buf_len ) ) { free ( worker_buf ) ; EVP_CIPHER_CTX_free ( ctx ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } j = worker_buf_len - aes_iv_len - i ; if ( ! EVP_CipherFinal_ex ( ctx , & worker_buf [ aes_iv_len + i ] , & j ) ) { free ( worker_buf ) ; EVP_CIPHER_CTX_free ( ctx ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } EVP_CIPHER_CTX_free ( ctx ) ; worker_buf_len = aes_iv_len + i + j ; if ( ( pctx = EVP_PKEY_CTX_new ( pkey , NULL ) ) == NULL ) { free ( worker_buf ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } if ( EVP_PKEY_encrypt_init ( pctx ) <= 0 || EVP_PKEY_CTX_set_rsa_padding ( pctx , RSA_PKCS1_PADDING ) <= 0 ) { free ( worker_buf ) ; EVP_PKEY_CTX_free ( pctx ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } if ( EVP_PKEY_encrypt ( pctx , NULL , & wrap_buf_len , aes_key , aes_key_len ) <= 0 ) { free ( worker_buf ) ; EVP_PKEY_CTX_free ( pctx ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } if ( ( wrap_buf = ( unsigned char * ) malloc ( wrap_buf_len ) ) == NULL ) { free ( worker_buf ) ; EVP_PKEY_CTX_free ( pctx ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_OUT_OF_MEMORY ; } if ( EVP_PKEY_encrypt ( pctx , wrap_buf , & wrap_buf_len , aes_key , aes_key_len ) <= 0 ) { free ( worker_buf ) ; free ( wrap_buf ) ; EVP_PKEY_CTX_free ( pctx ) ; MPASS_SET_ERROR ( amp , strdup ( ERR_error_string ( ERR_get_error ( ) , NULL ) ) ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } memset ( aes_key , 0 , sizeof ( aes_key ) ) ; * out_buf_len = 4 + ( int ) wrap_buf_len + worker_buf_len ; if ( ( * out_buf = ( unsigned char * ) malloc ( * out_buf_len ) ) == NULL ) { free ( worker_buf ) ; free ( wrap_buf ) ; EVP_PKEY_CTX_free ( pctx ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } ( * out_buf ) [ 0 ] = ( ( unsigned int ) wrap_buf_len >> 24 ) & 0xFF ; ( * out_buf ) [ 1 ] = ( ( unsigned int ) wrap_buf_len >> 16 ) & 0xFF ; ( * out_buf ) [ 2 ] = ( ( unsigned int ) wrap_buf_len >> 8 ) & 0xFF ; ( * out_buf ) [ 3 ] = ( unsigned int ) wrap_buf_len & 0xFF ; memcpy ( & ( ( * out_buf ) [ 4 ] ) , wrap_buf , wrap_buf_len ) ; memcpy ( & ( ( * out_buf ) [ 4 + wrap_buf_len ] ) , worker_buf , worker_buf_len ) ; free ( worker_buf ) ; free ( wrap_buf ) ; return AUTHME_ERR_OK ; }
Encrypt with a randomly generated AES key and then wrap the key
using the provided public key
Encrypt with a randomly generated AES key and then wrap the key using the provided public key
/* Sanity check */ /* Allocate enough space for the AES crypto part*/ // This would be bad! // Now start creating keys and things // Also bad /* Sanity checks */ // Easy day - let's encrypt! // Done the AES part // Now the RSA part // Initialise ctx // Get buffer length to write to // Encrypt // Done - cleanup and copy to output // For our envelope, start of the buffer is always a 4 byte unsigned int // Then the wrap itself // then the encrypted data