authme-unix/src/mpass_openssl.c
authme_err_t
mpass_openssl_envelope_decrypt(mpass_handle mh, int key, char * in_buf, unsigned char ** out_buf, size_t * out_buf_len)
{
	unsigned char * worker_buf;
	size_t worker_buf_len;
	unsigned char * wrap_buf;
	size_t enc_wrap_buf_len, wrap_buf_len;
	unsigned char * secret_buf;
	int aes_iv_len, enc_secret_len;
	int i, j;
	EVP_PKEY * pkey;
	EVP_CIPHER_CTX *ctx;
	EVP_PKEY_CTX *pctx;
	authme_master_password_t * amp = (authme_master_password_t *)mh;

	authme_err_t err;

	if (amp == NULL)
		return AUTHME_ERR_NO_CRYPTO;

	/* For now we only know how to decrypt using the service private key */
	if (key != MPASS_SERVICE_PRIVATE_KEY)
	{
		MPASS_SET_ERROR(amp, "Can only unwrap using service private key");
		return AUTHME_ERR_INVALID_KEY;
	}

	pkey = amp->amp_service_key;
	if (pkey == NULL)
	{
		MPASS_SET_ERROR(amp, "Private key not loaded");
		return AUTHME_ERR_INVALID_KEY;
	}

	/* Decode the buffer */
	if ((err = mpass_openssl_b64_decode(amp, in_buf, &worker_buf, &worker_buf_len)) != AUTHME_ERR_OK)
		return err;

	if (worker_buf_len < 4)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, "Base64 decode buffer too short");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	/* Get size of wrap */
	wrap_buf_len = 0;
	enc_wrap_buf_len = 0;
	for (i = 0; i < 4; ++i)
	{
		enc_wrap_buf_len = enc_wrap_buf_len << 8;
		enc_wrap_buf_len = enc_wrap_buf_len | worker_buf[i];
	}

	if (enc_wrap_buf_len > worker_buf_len + 4 || enc_wrap_buf_len <= 0)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, "Wrapped key buffer size invalid");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	/* Decrypt the wrap */
	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_decrypt_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_decrypt(pctx, NULL, &wrap_buf_len, &(worker_buf[4]), enc_wrap_buf_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;
	}

	// Decrypt
	if (EVP_PKEY_decrypt(pctx, wrap_buf, &wrap_buf_len, &(worker_buf[4]), enc_wrap_buf_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;
	}

	/* Free the key */
	EVP_PKEY_CTX_free(pctx);

	/* Have an AES key - let's use it */
	if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
	{
		// Bad
		free(worker_buf);
		free(wrap_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, wrap_buf, &(worker_buf[4 + enc_wrap_buf_len]), 0);
	aes_iv_len = EVP_CIPHER_CTX_iv_length(ctx);
	memset(wrap_buf, 0, wrap_buf_len);
	free(wrap_buf);

	/* Sanity checks */
	enc_secret_len = (int)worker_buf_len - 4 - (int)enc_wrap_buf_len - aes_iv_len;
	if (enc_secret_len <= 0)
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, "Internal assertion on buffer lengths failed - help!");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}

	/* Holding buffer */
	if ((secret_buf = (unsigned char*)malloc(enc_secret_len)) == NULL)
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, "Memory allocation error");
		return AUTHME_ERR_OUT_OF_MEMORY;

	}

	// Decrypt
	i = enc_secret_len;
	if (!EVP_CipherUpdate(ctx, secret_buf, &i, &worker_buf[4 + enc_wrap_buf_len + aes_iv_len], enc_secret_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 = enc_secret_len - i;

	if (!EVP_CipherFinal_ex(ctx, &secret_buf[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);

	// Return
	*out_buf_len = i + j;
	*out_buf = secret_buf;

	return AUTHME_ERR_OK;
}
/* ---------------------------------------------------------------- *
* Decrypt an envelope using our key if we have one
* ---------------------------------------------------------------- */
Decrypt an envelope using our key if we have one
Decrypt an envelope using our key if we have one
authme_err_t
mpass_openssl_envelope_decrypt(mpass_handle mh, int key, char * in_buf, unsigned char ** out_buf, size_t * out_buf_len)
{
	unsigned char * worker_buf;
	size_t worker_buf_len;
	unsigned char * wrap_buf;
	size_t enc_wrap_buf_len, wrap_buf_len;
	unsigned char * secret_buf;
	int aes_iv_len, enc_secret_len;
	int i, j;
	EVP_PKEY * pkey;
	EVP_CIPHER_CTX *ctx;
	EVP_PKEY_CTX *pctx;
	authme_master_password_t * amp = (authme_master_password_t *)mh;
	authme_err_t err;
	if (amp == NULL)
		return AUTHME_ERR_NO_CRYPTO;
	if (key != MPASS_SERVICE_PRIVATE_KEY)
	{
		MPASS_SET_ERROR(amp, "Can only unwrap using service private key");
		return AUTHME_ERR_INVALID_KEY;
	}
	pkey = amp->amp_service_key;
	if (pkey == NULL)
	{
		MPASS_SET_ERROR(amp, "Private key not loaded");
		return AUTHME_ERR_INVALID_KEY;
	}
	if ((err = mpass_openssl_b64_decode(amp, in_buf, &worker_buf, &worker_buf_len)) != AUTHME_ERR_OK)
		return err;
	if (worker_buf_len < 4)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, "Base64 decode buffer too short");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	wrap_buf_len = 0;
	enc_wrap_buf_len = 0;
	for (i = 0; i < 4; ++i)
	{
		enc_wrap_buf_len = enc_wrap_buf_len << 8;
		enc_wrap_buf_len = enc_wrap_buf_len | worker_buf[i];
	}
	if (enc_wrap_buf_len > worker_buf_len + 4 || enc_wrap_buf_len <= 0)
	{
		free(worker_buf);
		MPASS_SET_ERROR(amp, "Wrapped key buffer size invalid");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	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_decrypt_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_decrypt(pctx, NULL, &wrap_buf_len, &(worker_buf[4]), enc_wrap_buf_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_decrypt(pctx, wrap_buf, &wrap_buf_len, &(worker_buf[4]), enc_wrap_buf_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;
	}
	EVP_PKEY_CTX_free(pctx);
	if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
	{
		free(worker_buf);
		free(wrap_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, wrap_buf, &(worker_buf[4 + enc_wrap_buf_len]), 0);
	aes_iv_len = EVP_CIPHER_CTX_iv_length(ctx);
	memset(wrap_buf, 0, wrap_buf_len);
	free(wrap_buf);
	enc_secret_len = (int)worker_buf_len - 4 - (int)enc_wrap_buf_len - aes_iv_len;
	if (enc_secret_len <= 0)
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, "Internal assertion on buffer lengths failed - help!");
		return AUTHME_ERR_CRYPTO_OPERATION;
	}
	if ((secret_buf = (unsigned char*)malloc(enc_secret_len)) == NULL)
	{
		free(worker_buf);
		EVP_CIPHER_CTX_free(ctx);
		MPASS_SET_ERROR(amp, "Memory allocation error");
		return AUTHME_ERR_OUT_OF_MEMORY;
	}
	i = enc_secret_len;
	if (!EVP_CipherUpdate(ctx, secret_buf, &i, &worker_buf[4 + enc_wrap_buf_len + aes_iv_len], enc_secret_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 = enc_secret_len - i;
	if (!EVP_CipherFinal_ex(ctx, &secret_buf[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);
	*out_buf_len = i + j;
	*out_buf = secret_buf;
	return AUTHME_ERR_OK;
}
authme_err_t mpass_openssl_envelope_decrypt ( mpass_handle mh , int key , char * in_buf , unsigned char * * out_buf , size_t * out_buf_len ) { unsigned char * worker_buf ; size_t worker_buf_len ; unsigned char * wrap_buf ; size_t enc_wrap_buf_len , wrap_buf_len ; unsigned char * secret_buf ; int aes_iv_len , enc_secret_len ; int i , j ; EVP_PKEY * pkey ; EVP_CIPHER_CTX * ctx ; EVP_PKEY_CTX * pctx ; authme_master_password_t * amp = ( authme_master_password_t * ) mh ; authme_err_t err ; if ( amp == NULL ) return AUTHME_ERR_NO_CRYPTO ; if ( key != MPASS_SERVICE_PRIVATE_KEY ) { MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_INVALID_KEY ; } pkey = amp -> amp_service_key ; if ( pkey == NULL ) { MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_INVALID_KEY ; } if ( ( err = mpass_openssl_b64_decode ( amp , in_buf , & worker_buf , & worker_buf_len ) ) != AUTHME_ERR_OK ) return err ; if ( worker_buf_len < 4 ) { free ( worker_buf ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } wrap_buf_len = 0 ; enc_wrap_buf_len = 0 ; for ( i = 0 ; i < 4 ; ++ i ) { enc_wrap_buf_len = enc_wrap_buf_len << 8 ; enc_wrap_buf_len = enc_wrap_buf_len | worker_buf [ i ] ; } if ( enc_wrap_buf_len > worker_buf_len + 4 || enc_wrap_buf_len <= 0 ) { free ( worker_buf ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } 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_decrypt_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_decrypt ( pctx , NULL , & wrap_buf_len , & ( worker_buf [ 4 ] ) , enc_wrap_buf_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_decrypt ( pctx , wrap_buf , & wrap_buf_len , & ( worker_buf [ 4 ] ) , enc_wrap_buf_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 ; } EVP_PKEY_CTX_free ( pctx ) ; if ( ( ctx = EVP_CIPHER_CTX_new ( ) ) == NULL ) { free ( worker_buf ) ; free ( wrap_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 , wrap_buf , & ( worker_buf [ 4 + enc_wrap_buf_len ] ) , 0 ) ; aes_iv_len = EVP_CIPHER_CTX_iv_length ( ctx ) ; memset ( wrap_buf , 0 , wrap_buf_len ) ; free ( wrap_buf ) ; enc_secret_len = ( int ) worker_buf_len - 4 - ( int ) enc_wrap_buf_len - aes_iv_len ; if ( enc_secret_len <= 0 ) { free ( worker_buf ) ; EVP_CIPHER_CTX_free ( ctx ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_CRYPTO_OPERATION ; } if ( ( secret_buf = ( unsigned char * ) malloc ( enc_secret_len ) ) == NULL ) { free ( worker_buf ) ; EVP_CIPHER_CTX_free ( ctx ) ; MPASS_SET_ERROR ( amp , " " ) ; return AUTHME_ERR_OUT_OF_MEMORY ; } i = enc_secret_len ; if ( ! EVP_CipherUpdate ( ctx , secret_buf , & i , & worker_buf [ 4 + enc_wrap_buf_len + aes_iv_len ] , enc_secret_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 = enc_secret_len - i ; if ( ! EVP_CipherFinal_ex ( ctx , & secret_buf [ 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 ) ; * out_buf_len = i + j ; * out_buf = secret_buf ; return AUTHME_ERR_OK ; }
Decrypt an envelope using our key if we have one
Decrypt an envelope using our key if we have one
/* For now we only know how to decrypt using the service private key */ /* Decode the buffer */ /* Get size of wrap */ /* Decrypt the wrap */ // Initialise ctx // Get buffer length to write to // Decrypt /* Free the key */ /* Have an AES key - let's use it */ // Bad /* Sanity checks */ /* Holding buffer */ // Decrypt // Done the AES part // Return