This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Why does CRYS_ECPKI_GenKeyPair() adds 0x01 to last byte of private key when fixed_vector is used instead of CRYS_RND_GenerateVector?

Hi All,

Since I couldn't find a CC310 function for calculating a public key from a private one, I got around it by providing to CRYS_ECPKI_GenKeyPair() the private key through the fixed_vector() function, rather than providing the usual pointer to the random vector generation function CRYS_RND_GenerateVector (as done in an older implementation of Solo).

The problem is that CRYS_ECPKI_GenKeyPair() modifies the original input private key passed using fixed_vector() by adding 0x01 to it's last byte. The generated public key is then mistakenly derived from the private key with 0x01 added to its last byte, rather than the original private key. Why does this happen?

I worked around this by subtracting 0x01 to the last byte of the private key I pass to fixed_vector() as in the script below. It works, however I don't understand why this addition of 0x01 is happening. What am I missing?

In short: why does Line 27 make my code work successfully?

Thank you.

uint8_t fixed_vector_hmac[32];
int fixed_vector_iter = 31;
uint32_t fixed_vector(void * rng, uint16_t sz, uint8_t * out)
{
    while(sz--)
    {
        *out++ = fixed_vector_hmac[fixed_vector_iter--];
        if (fixed_vector_iter == -1)
        {
            fixed_vector_iter = 31;
        }
    }
    return 0;
}

void compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
    CRYS_ECPKI_UserPrivKey_t nrfpriv;
    CRYS_ECPKI_UserPublKey_t nrfpub;
    CRYS_ECPKI_KG_TempData_t tmp;
    CRYS_ECPKI_KG_FipsContext_t FipsBuff;
    uint32_t ret;
    uint32_t sz;
    uint8_t pubkey1[65];

    memmove(fixed_vector_hmac, privkey, 32);
    fixed_vector_hmac[31] -= 1;	// Contrast CRYS_ECPKI_GenKeyPair() which adds 1 to last byte of private key
    fixed_vector_iter=31;

    // There isn't a CC310 function for calculating a public key from a private,
    // so to get around it, we can "fix" the RNG input to GenKeyPair
	ret = CRYS_ECPKI_GenKeyPair(&rndState_ptr,
			fixed_vector,
			/*CRYS_RND_GenerateVector,*/
			_es256_curve,
			&nrfpriv, &nrfpub, &tmp, &FipsBuff);

	if (ret != SA_SILIB_RET_OK){
		printf2(TAG_ERR, "Gen key failed with 0x%x \n",ret);
		exit(1);
	}

	/* Check that nrfpriv is same as privkey*/
	#include "ssi_pal_mem.h"

	//Export UserPrivKey into buffer
	uint8_t privKeyBuffCompare[256];
	sz = 32;
	ret = CRYS_ECPKI_ExportPrivKey(&nrfpriv, privKeyBuffCompare, &sz);
	if (ret != 0 || sz != 32)
	{
		printf2(TAG_ERR, "nrfpriv export fail 0x%04x\n",ret);
	}

	//Compare privKeyBuff with UserPrivKey
	ret = SaSi_PalMemCmp(privKeyBuffCompare, privkey, 32);

	if (ret != SA_SILIB_RET_OK){
		printf2(TAG_ERR, " SaSi_PalMemCmp failed \n");
	}

	printf1(TAG_U2F,"privkey: "); dump_hex1(TAG_RED, privkey, 32);
	printf1(TAG_U2F,"privKeyBuffCompare: "); dump_hex1(TAG_RED, privKeyBuffCompare, 32);
	/*******/

	sz = 65;
	ret = CRYS_ECPKI_ExportPublKey(&nrfpub, CRYS_EC_PointUncompressed , pubkey1, &sz);
	if (ret != 0 || sz != 65)
	{
		printf2(TAG_ERR, "pubkey export fail 0x%04x\n",ret);
		exit(1);
	}
	if (pubkey1[0] != 0x04)
	{
		printf2(TAG_ERR, "pubkey uncompressed export fail 0x%02x\n",(int)pubkey1[0]);
		exit(1);
	}
	memmove(pubkey, pubkey1+1 , 64);
}

Parents
  • Hi,

    I see from the implementation that 1 is added to the last byte. I cannot comment on it though as the code is not written by Nordic. (I do not immediately see any other issues with what you are doing, but if you would like to avide hacks like this, then you could use code from another crypto library to derive the public key from the private key, even though using CryptoCell for other crypto operations.)

  • Thank you Einar for suggesting the use of other crypto libraries.

    Originally I wanted to use only CryptoCell to speed up operations and to avoid the include of many libraries to keep my build minimal. Can I achieve hardware acceleration also with other libraries?

    Also, can I find the source code of CRYS_ECPKI_GenKeyPair() somewhere? In this way I could verify why 1 is added to the last byte of the input private key before the public key is derived.

    Thank you.

  • Hi,

    pier said:
    Originally I wanted to use only CryptoCell to speed up operations and to avoid the include of many libraries to keep my build minimal. Can I achieve hardware acceleration also with other libraries?

    No, you will not get HW acceleration with other libraries. But how often do you do this operation?

    pier said:
    Also, can I find the source code of CRYS_ECPKI_GenKeyPair() somewhere? In this way I could verify why 1 is added to the last byte of the input private key before the public key is derived.

    The nrf_cc310 library/driver is currently not available in source code. It has many similarities with the cryptocell-312-runtime though, so you could look there and make some assumptions.

Reply
  • Hi,

    pier said:
    Originally I wanted to use only CryptoCell to speed up operations and to avoid the include of many libraries to keep my build minimal. Can I achieve hardware acceleration also with other libraries?

    No, you will not get HW acceleration with other libraries. But how often do you do this operation?

    pier said:
    Also, can I find the source code of CRYS_ECPKI_GenKeyPair() somewhere? In this way I could verify why 1 is added to the last byte of the input private key before the public key is derived.

    The nrf_cc310 library/driver is currently not available in source code. It has many similarities with the cryptocell-312-runtime though, so you could look there and make some assumptions.

Children
  • Hi Einar,

    Thanks for the answer.

    No, you will not get HW acceleration with other libraries. But how often do you do this operation?

    I only have an approximate answer to this question because I haven't done any requirements analysis yet. I'm developing a FIDO2 authenticator. I believe that I would need to derive the public key:

    1. At power up
    2. Every time I create new credentials
    3. Every time I set or change a PIN (this as for current implementation of Solo and could be avoided with some optimization)

    Possibly HW acceleration is not tat necessary to derive the public key for a FIDO2 authenticator, but I would need to investigate more on this.

    The nrf_cc310 library/driver is currently not available in source code. It has many similarities with the cryptocell-312-runtime though, so you could look there and make some assumptions.

    This is a really good tip, thank you for the link, I did not know the CryptoCell-312 code was available. From a quick look it seems that these lines of code might have something to do with the addition of 1 to last byte. I should investigate further to be sure though.

Related