Intel® Software Guard Extensions (Intel® SGX)
Discussion board focused on hardware-based isolation and memory encryption to provide extended code protection in solutions.

Calculate HMAC in the enclave

Svart_K_
Beginner
1,121 Views

Hi,

is there a predefined function that can be used inside the enclave to calculate a HMAC with SHA512?

If not is there a proper "workaround" or alternative?

 

Thanks

0 Kudos
7 Replies
Juan_d_Intel
Employee
1,121 Views

The SGX SDK exposes the IPP crypto API. 

You may include the IPP crypto header files in your enclave project to access the Keyed Hash API. 

A description of the relevant IPP Crypto API is posted here: https://software.intel.com/en-us/node/503181

HMAC with SHA512 is supported. You only need to pass the appropriate hash algorithm (IppHashAlgId = SHA-512) to the HMAC_Init call.

0 Kudos
Svart_K_
Beginner
1,121 Views

Hi,

thanks for the reply!

I managed to call the "ippsHMAC_GetSize" and "ippsHMAC_Init" functions successfully, but now I'm lost with the "HMAC_Update" one!?

Is there any example available!?

 

0 Kudos
Svart_K_
Beginner
1,121 Views

Okay I got it to work now with two different variants. The problem is when testing it with a predefined key and message, the returned hmac is different each time!?

This is the method that with the two variants:

int calculateHMAC(uint8_t *key, uint8_t *nonce, uint8_t *res_hmac) {
	IppsHMACState *ctx;
	IppStatus status;
	int psize = 0;

	//VARIANT 1
	status = ippsHMAC_GetSize(&psize);

	if (status == ippStsNullPtrErr) 
		return 1;

	ctx = (IppsHMACState*) malloc(psize);
	status = ippsHMAC_Init(key, HMAC_KEY_LENGTH, ctx, ippHashAlg_SHA512);

	if (status != ippStsNoErr)
		return 1;

	status = ippsHMAC_Update(nonce, HMAC_NONCE_LENGTH, ctx);

	if (status != ippStsNoErr)
		return 1;

	uint8_t hmac[HMAC_LENGTH];
	memset(hmac, '\0', HMAC_LENGTH);
	status = ippsHMAC_Final(hmac, HMAC_LENGTH, ctx);

	if (status != ippStsNoErr)
		return 1;

	status = ippsHMAC_GetTag(hmac, HMAC_LENGTH, ctx);

	if (status != ippStsNoErr)
		return 1;

	memcpy(res_hmac, hmac, HMAC_LENGTH);

	//VARIANT 2
//	uint8_t test_hmac[HMAC_LENGTH];
//	status = ippsHMAC_Message(nonce, HMAC_NONCE_LENGTH, key, HMAC_KEY_LENGTH, test_hmac, HMAC_LENGTH, ippHashAlg_SHA512);

//	if (status != ippStsNoErr)
//		return 1;

//	memcpy(res_hmac, test_hmac, HMAC_LENGTH);

	return 0;

}


 

This is a static example, that should when being executed result in the same hmac on each call:

 

 

char nonce[] = "7d93099f7fed16215836f7bad4db0e48";
char key[] = "a5b115536d5bf350c5b0fa6f69242f18";
uint8_t t_hmac[64];
memset(t_hmac, '\0', 64);

uint8_t ba_nonce[16];
int count = 0;
for (unsigned int i=0; i<32; i+=2) {
	char tmp[2];
	tmp[0] = nonce;
	tmp[1] = nonce[i+1];
	char byte = (char) strtol(tmp, NULL, 16);

	ba_nonce[count] = (unsigned char)byte;
	count++;
}

uint8_t ba_key[16];
count = 0;
for (unsigned int i=0; i<32; i+=2) {
	char tmp[2];
	tmp[0] = key;
	tmp[1] = key[i+1];
	char byte = (char) strtol(tmp, NULL, 16);

	ba_key[count] = (unsigned char)byte;
	count++;
}


int error = calculateHMAC(ba_key, ba_nonce, t_hmac);

 

The t_hmac variable contains the calculated HMAC, but is not the same for multiple executions!?

 

0 Kudos
Svart_K_
Beginner
1,121 Views

Can anyone help me with this issue, it's quite urgent!?

 

Thanks

0 Kudos
Juan_d_Intel
Employee
1,121 Views

The code above seems okay, except that you should only call ippsHMAC_GetTag to determine the current value of the message digest between the two calls to ippsHMAC_Update.

Are you sure the values of HMAC_KEY_LENGTH, HMAC_NONCE_LENGTH, and HMAC_LENGTH are correct? If you specify a larger buffer size you'd be operating on undefined data, hence the different HMAC values.

In case, it helps, this is what my enclave is producing:

KEY (16):
        a5b115536d5bf350c5b0fa6f69242f18
NONCE (16):
        7d93099f7fed1621583676bad4db0e48
HMAC (64):
        50b628bc940ac4ce5729a416320870094723d62e3e0d043c87e441547dea5934abcb74da488b49392d99c1bd5d8a8e8d94d6ce8acd9f3cd1dceb179fa6dc1349

 

0 Kudos
Svart_K_
Beginner
1,121 Views

Alright I've removed the ippsHMAC_GetTag call now to this:

int calculateHMAC(uint8_t *key, uint8_t *nonce, uint8_t *res_hmac) {
	IppsHMACState *ctx;
	IppStatus status;
	int psize = 0;

	//VARIANT 1
	status = ippsHMAC_GetSize(&psize);

	if (status == ippStsNullPtrErr) 
		return 1;

	ctx = (IppsHMACState*) malloc(psize);
	status = ippsHMAC_Init(key, 16, ctx, ippHashAlg_SHA512);

	if (status != ippStsNoErr)
		return 1;

	status = ippsHMAC_Update(nonce, 16, ctx);

	if (status != ippStsNoErr)
		return 1;

	uint8_t hmac[HMAC_LENGTH];
	memset(hmac, '\0', HMAC_LENGTH);
	status = ippsHMAC_Final(hmac, HMAC_LENGTH, ctx);

	if (status != ippStsNoErr)
		return 1;

	memcpy(res_hmac, hmac, HMAC_LENGTH);
}

 

And the call is the same:

 

char nonce[] = "7d93099f7fed16215836f7bad4db0e48";
char key[] = "a5b115536d5bf350c5b0fa6f69242f18";
uint8_t t_hmac[64];
memset(t_hmac, '\0', 64);

uint8_t ba_nonce[16];
int count = 0;
for (unsigned int i=0; i<32; i+=2) {
	char tmp[2];
	tmp[0] = nonce;
	tmp[1] = nonce[i+1];
	char byte = (char) strtol(tmp, NULL, 16);

	ba_nonce[count] = (unsigned char)byte;
	count++;
}

uint8_t ba_key[16];
count = 0;
for (unsigned int i=0; i<32; i+=2) {
	char tmp[2];
	tmp[0] = key;
	tmp[1] = key[i+1];
	char byte = (char) strtol(tmp, NULL, 16);

	ba_key[count] = (unsigned char)byte;
	count++;
}

int error = calculateHMAC(ba_key, ba_nonce, t_hmac);

mbedtls_printf("Key: ");
for(int i = 0; i < 16; i++)
	mbedtls_printf("%02x", (unsigned int)ba_key);

mbedtls_printf("\n");


mbedtls_printf("Nonce: ");
for(int i = 0; i < 16; i++)
	mbedtls_printf("%02x", (unsigned int)ba_nonce);

mbedtls_printf("\n");

mbedtls_printf("HMAC: ");
for(int i = 0; i < 64; i++)
	mbedtls_printf("%02x", (unsigned int)t_hmac);

mbedtls_printf("\n");

 

 

For which I receive the output:

Key: a5b115536d5bf350c5b0fa6f69242f18
Nonce: 7d93099f7fed16215836f7bad4db0e48
HMAC: 7d2f2e3d57c84a58945b9016fb37e2df03afdde313c9d79c31ec1e6612d6d6b20456a8fcf799ef74d16f60c7f283e621400004422885f33fb3d2bb7ae7a1daa3

But this is not the correct HMAC-SHA512 and neither is yours, since according to this tool http://beautifytools.com/hmac-generator.php

the result should be:

dd8406481da579254295ee9ea9632bd6cb80b56116b1b93207b1caa3245c0cbbbdf4b3ebcc0d1c4e85ff55fbdd2a65eca25f48b641a1a9bc0e6442467bd8ce79

0 Kudos
Juan_d_Intel
Employee
1,121 Views

This tools takes your data and key as ASCII strings. Make one of the hex letters uppercase and the result will change.

Your program takes the input as binary representation. 

I realized that the program does not terminate "tmp" properly. As a result, depending on what's in the stack strtol may not return what you'd expect. When I ran the original program, the nonce was translated into something slightly different, see below.

Originally: 7d93099f7fed16215836f7bad4db0e48

I was using: 7d93099f7fed1621583676bad4db0e48

After changing the conversion routine, I got the same HMAC as you.

KEY (16):
        a5b115536d5bf350c5b0fa6f69242f18
NONCE (16):
        7d93099f7fed16215836f7bad4db0e48
HMAC (64):
        7d2f2e3d57c84a58945b9016fb37e2df03afdde313c9d79c31ec1e6612d6d6b20456a8fcf799ef74d16f60c7f283e621400004422885f33fb3d2bb7ae7a1daa3

 

0 Kudos
Reply