MBED TLS Symetric Key Wrap - c

I'm trying to use MBED TLS cryptography functions to unwrap a key which has been encrypted using AES-128 key wrapping using a symmetric key, which I have.
I'm new to encryption and my understanding is that key wrapping/unwrapping is different to encrypting/decrypting. Is this correct?
There are examples listed on this page but the aes examples are doing decryption rather than key unwrapping, and the wrap examples are using public keys rather than symmetrical keys.
Is there some reference or example for using MBED TLS to do key-unwrapping using AES-128 encryption?
I have tried simply using the decryption function and I do not get the correct data as a result. See below.
//Initialise AES context
mbedtls_aes_init( &aes_ctx );
//Set-up the context
mbedtls_aes_setkey_dec( &aes_ctx, AES_key, 128 );
//Process the encrypted data in blocks of 16 bytes
for(i = 0; i< encryptedDataLength; i+= 16)
{
mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_DECRYPT, pEncryptedData + i, pPlainValue + i);
}
//Free the context
mbedtls_aes_free( &aes_ctx );
Thanks!

I found a solution, using the nist_kw interface
//Initialise key-wrap context
mbedtls_nist_kw_init(&kw_ctx);
//Set up the context
mbedtls_nist_kw_setkey(&kw_ctx, MBEDTLS_CIPHER_ID_AES, AES_key, 128, 0);
//Process the encrypted data
mbedtls_nist_kw_unwrap(&kw_ctx, MBEDTLS_KW_MODE_KW,
pEncryptedData, encrypted_length,
pPlainValue, &decrypted_length,
encryptedDataLength);
//Free the context
mbedtls_nist_kw_free(&kw_ctx);
This decrypts the data correctly for me. Thanks for being my rubber ducky!

Related

mbedTLS ECC Operations

I've already searched for my question in the documentation of mbedtls but there was no explicit answer.
Is there any way to generate public and private ECC keys with mbedTLS? I've already got sha256 properly working, with the help of a tutorial, but it seems that ECC operations are not well documented.
Is there an example, on how to generate a private/public key on the NIST P-256 curve?
Thanks for you help.
Here is a sample code to generate ECC keys (but without any check of the return value):
mbedtls_pk_context key;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_pk_type_t pk_alg = MBEDTLS_PK_ECKEY;
mbedtls_pk_init(&key);
mbedtls_entropy_init( &entropy );
mbedtls_ctr_drbg_init(&ctr_drbg);
ret = mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(pk_alg));
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&entropy,
(const unsigned char *) "ecdsa",
strlen(pers)
);
ret = mbedtls_ecp_gen_key(<KEY TYPE>,
mbedtls_pk_ec(key),
mbedtls_ctr_drbg_random,
&ctr_drbg
);
Where <KEY_TYPE> can be found at: https://tls.mbed.org/api/ecp_8h.html#af79e530ea8f8416480f805baa20b1a2d and in your case should be MBEDTLS_ECP_DP_SECP256R1.

How to verify ECC Signature from wolfSSL with OpenSSL

I am new to Elliptic Curve Cryptography, openSSL and wolfSSL. My context is that I generate KeyPair from command line with openssl and import the private key to my code. Then I use wolfSSL to generate signature and output it.
I save the output in DER format and try to verify with openSSL, the verification fails.
If I Sign and Verify inside my code with wolfSSL, it verifies successfully and also it's successful if I sign and verify in command line with openSSL.
Is there an encoding issue, which I am not sure about?
Update Code
// ECC public key
const uint8_t pubKey[] ={Hex Format key};
// ECC Signature from wolfSSL
char* sigString = {Signature from wolfSSL returned as char};
/* TYPE CONVERTIONS*/
const uint8_t *der_bytes_copy;
const uint8_t *pub_bytes_copy;
der_bytes_copy = (const unsigned char*)sigString;
pub_bytes_copy = pubKey;
EC_KEY *ECpubkey;
size_t keySize = sizeof(pubKey);
int eccgrp;
eccgrp = OBJ_txt2nid("secp256r1");
ECpubkey = EC_KEY_new_by_curve_name(eccgrp);
o2i_ECPublicKey(&ECpubkey, &pub_bytes_copy, keySize);
ECDSA_SIG *signature;
signature = d2i_ECDSA_SIG(NULL, &der_bytes_copy, signedSize);
uint8_t digest[36];
int verified;
const char message[] = "Test for Authenticate Kernel with ECC";
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, (const uint8_t*)message,sizeof(message));
SHA256_Final(digest, &ctx);
verified = ECDSA_do_verify(digest, sizeof(digest), signature, ECpubkey);
The private key is used with wolfSSL to sign the message and then the public key with openssl to verify, but this stops abruptly.
In the past when working with openSSL and comparing sign values to wolfSSL I have found that OpenSSL does the following steps when signing:
Read in and decode the key
compute a hash
Signature Encode the hash
sign the encoded hash
Base64 Encode the signature
OpenSSL does not make this apparent or user-friendly so unfortunately it's something you have to discover as you have.
Please use the following steps in wolfSSL to achieve your desired output:
1 Create or import your ECC key
2 Compute the sha hash on the input as you did previously
3 Encode the hash with this API call: encodedSz = wc_EncodeSignature(encodedOutput, hashInput, SHA256_DIGEST_SIZE, SHA256h);
4 Sign the encoded hash
5 Now do the verify
Let us know if that works for you.

Openssl how to find out what the bit size of the public key in an X509 certificate is

If I have an X509* that openssl has provided me, what's the best way to figure out the bit-ness of the RSA public key in the certificate? I can't quite figure this out. I'm pretty sure that if I'm in the SSL certificate verification callback, I can get the X509 ptr with
X509 * cert = X509_STORE_CTX_get_current_cert(the_x509_store_ctx);
and I would surmise I get the public key like this
EVP_PKEY *public_key = X509_get_pubkey(cert);
and then I need to check whether it's RSA, presumably?
if (public_key && (EVP_PKEY_RSA == public_key->type))
and once I know that I got a public key back and that it's RSA, I'd like to do this:
int key_length = BN_num_bits(public_key->pkey.rsa->n);
but I've found that while this works quite nicely on openssl 0.9.8, on 1.0.1h it segfaults on Windows. The BIGNUM 'n' doesn't seem to be valid - the data ptr in it has a garbage pointer.
Any idea what's wrong?
As already suggested, to get the RSA modulus size in bytes (so not "bit size"...) use:
EVP_PKEY * public_key = X509_get_pubkey(cert);
RSA *rsa_key = EVP_PKEY_get1_RSA(public_key);
int key_length = RSA_size(rsa_key);
...
RSA_free(rsa_key);

OpenAES/OpenSSL compatibility

I'm trying to use both OpenAES and OpenSSL in C, this way:
Application 1 encodes a password using OpenAES
Application 2 decodes the password using OpenSSL
The problem is that I can't decode it, actually I'm quite surprised as OpenAES generates a
different block each time when OpenSSL or any other AES implementation I've seen always generate
the same block.
Another difference I noticed is that the OpenAES generated block is 48 bytes, when OpenSSL generates 16.
This is how I encrypt the string (OpenAES):
pCtx = oaes_alloc();
if (pCtx == NULL)
return FALSE;
oRet = oaes_key_import(pCtx, sKey, szKey);
if (oRet != OAES_RET_SUCCESS)
{
return FALSE;
}
// Get the required buffer size
oRet = oaes_encrypt(pCtx, (const uint8_t*)csSource, szLen, NULL, pOutLen);
if (oRet != OAES_RET_SUCCESS)
{
oaes_free(&pCtx);
return FALSE;
}
*ppOut = (char*)calloc(*pOutLen, sizeof(char));
oRet = oaes_encrypt(pCtx, (const uint8_t*)csSource, szLen, (uint8_t*)*ppOut, pOutLen);
if (oRet != OAES_RET_SUCCESS)
{
oaes_free(&pCtx);
free(*ppOut);
return FALSE;
}
oaes_free(&pCtx);
And this is how I decrypt it (OpenSSL):
AES_KEY kDecrypt;
AES_set_decrypt_key(sKey, 128, &kDecrypt);
AES_decrypt(pEncoded, pDecoded, &kDecrypt);
sKey being the key generated with OpenAES
pEncoded the crypted block from OpenAES
pDecoded the output data.
I can't put my finger on the problem yet...
Is there a particular way to use OpenAES so the result can be decrypted by OpenSSL, or is it just not compatible?
OpenAES prefixes the encrypted data with a OpenAES specific header, followed by the iv and then the encrypted data (+ padding).
As the IV seems to be generated randomly by OpenAES that explains why the data differs with each encrypt.

How to encrypt data using RSA, with SHA-256 as hash function and MGF1 as mask generating function?

I was doing some experiments with cryptography. Now I have the public key of receiver and i want to encrypt some data and pass to the receiver.
I want to use RSAES-OAEP algorithm. with SHA-256 as hash function and MGF1 as mask generation function.
I want do this using openssl. I found a function RSA_public_encrypt() with this function we can specify the padding. One of the padding option available was
RSA_PKCS1_OAEP_PADDING
EME-OAEP as defined in PKCS #1 v2.0 with SHA-1 , MGF1 .
they are using sha-1.
I want to reconfigure the function to use SHA256 as hash function ans MGF1 as hash function. How can I do it ?
The following excerpt allows using OAEP with SHA256 for both the MGF and hash function. Tested with OpenSSL 1.0.2L
int flags = CMS_BINARY | CMS_PARTIAL | CMS_KEY_PARAM;
cms = CMS_encrypt(NULL, in, cipher, flags)
ri = CMS_add1_recipient_cert(cms, cert, flags);
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(pctx, EVP_sha256());
EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, EVP_sha256());
With a newer OpenSSL 1.0.2+ you can do it using the command:
openssl pkeyutl -in PlaintextKeyMaterial.bin -out EncryptedKeyMaterial.bin -inkey PublicKey.bin -keyform DER -pubin -encrypt -pkeyopt rsa_padding_mode:oaep
-pkeyopt rsa_oaep_md:sha256
This is taken from AWS KMS doc here: https://aws.amazon.com/es/premiumsupport/knowledge-center/invalidciphertext-kms/
OpenSSL uses definitions from PKCS #1 v2.0 and so the default for EME-OAEP is SHA-1 and MGF1. If you need to use SHA-256, you'll need to do the encoding yourself. This isn't terribly difficult however, see PKCS #1 v2.2 PDF Page 18 for details.
In the latest version of Openssl(1.0.2k) the signature of the API is changed which gives us more flexibility. Please find the details below,
int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const unsigned char *from, int flen,
int num, const unsigned char *param,
int plen, const EVP_MD *md,
const EVP_MD *mgf1md)
You can pass the EVP_MD structure to invoke the SHA-256 hashing using this.
The PKCS#1 doc referred to above is more mathematical and doesn't give coding examples, and the CMS answer is for ASN.1/SMIME data and not really relevant for the question asked, which was how to replace RSA_public_encrypt() which deals with simple binary/text data. I spent a whole day with trial and error and online searching to find the answer to this, and eventually got the answer (which was to use OpenSSL's EVP API) from looking at the source code of "openssl pkeyutl" - once I discovered that it was not difficult.
In my case I was looking to replace RSA_private_decrypt() for decryption using the private key and this is how to do that - it should be pretty easy to put to together an RSA_public_encrypt() replacement based on this:
EVP_PKEY *privKey = NULL;
BIO *bioPrivKey;
int outLen = 0, ret;
if ((bioPrivKey = BIO_new(BIO_s_mem())))
{
// Read the private key from the RSA context into the memory BIO,
// then convert it to an EVP_PKEY:
if ((ret = PEM_write_bio_RSAPrivateKey(bioPrivKey, rsaCtxt, NULL, NULL, 0, NULL, NULL)) &&
(privKey = PEM_read_bio_PrivateKey(bioPrivKey, NULL, NULL, NULL)))
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(privKey, NULL);
EVP_PKEY_free(privKey);
if (ctx)
{
if (EVP_PKEY_decrypt_init(ctx) > 0)
{
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_padding_mode", "oaep");
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_oaep_md", "sha256");
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_mgf1_md", "sha256");
outLen = dataOutMax;
ret = EVP_PKEY_decrypt(ctx, dataOut, &outLen, dataIn, inDataLen);
if (ret > 0 && outLen > 0 && outLen <= dataOutMax)
{
// Success :-)
}
}
EVP_PKEY_CTX_free(ctx);
}
}
BIO_free_all(bioPrivKey);
}
You can add error handling for the failure cases using ERR_get_error().

Resources