Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to generate firmware's hash.

Hello Everyone, 

I am a beginner

I am working on a project which requires authentication of the firmware , for this purpose i want to generate the hash of the firmware .

So while searching i cam across this function--> nrf_crypto_hash_calculate()  which uses source address and length, can anyone help me were i can find my firmware start and size of it,

nrf_crypto_hash_calculate(&hash_context,
&g_nrf_crypto_hash_sha256_info,
(uint8_t*)src_addr,
data_len,
m_fw_hash,
&hash_len);


Parents
  • Hi,

    You can use the CODE_START and CODE_SIZE symbols defined in components\libraries\util\app_util.h for this purpose.

    Best regards,
    Jørgen

  • Hii, so i was trying to run the function like this     
                nrf_crypto_hash_calculate(&hash_context, &g_nrf_crypto_hash_sha256_info,  (uint8_t*)CODE_START,
                              CODE_SIZE, firmware_hash, &hash_len);

     but its going into SaSi_HalWaitInterrupt after nrf_crypto_hash_update and not coming back , i think the issue is CODE_START is uint32_t pointer , and also CODE_SIZE will change for
    uint8_t expected by nrf_crypto_hash_calculate() or is there anything i am missing.

    what do you suggest.

    Thanks and Regard,
    Andhakanoon
                                                                                    

  • Hi,

    It looks similar to how we do it in our DFU bootloader for verification of hash of received image, but you may try to store the values of the symbols into uint32_t variables before passing to the function:

    // Function to check the hash received in the init command against the received firmware.
    // little_endian specifies the endianness of @p p_hash.
    static bool nrf_dfu_validation_hash_ok(uint8_t const * p_hash, uint32_t src_addr, uint32_t data_len, bool little_endian)
    {
        ret_code_t err_code;
        bool       result   = true;
        uint8_t    hash_be[NRF_CRYPTO_HASH_SIZE_SHA256];
        size_t     hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
        nrf_crypto_hash_context_t hash_context = {0};
    
        crypto_init();
    
        if (little_endian)
        {
            // Convert to hash to big-endian format for use in nrf_crypto.
            nrf_crypto_internal_swap_endian(hash_be,
                                            p_hash,
                                            NRF_CRYPTO_HASH_SIZE_SHA256);
            p_hash = hash_be;
        }
    
        NRF_LOG_DEBUG("Hash verification. start address: 0x%x, size: 0x%x",
                      src_addr,
                      data_len);
    
        err_code = nrf_crypto_hash_calculate(&hash_context,
                                             &g_nrf_crypto_hash_sha256_info,
                                             (uint8_t*)src_addr,
                                             data_len,
                                             m_fw_hash,
                                             &hash_len);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Could not run hash verification (err_code 0x%x).", err_code);
            result = false;
        }
        else if (memcmp(m_fw_hash, p_hash, NRF_CRYPTO_HASH_SIZE_SHA256) != 0)
        {
            NRF_LOG_WARNING("Hash verification failed.");
            NRF_LOG_DEBUG("Expected FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(p_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_DEBUG("Actual FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(m_fw_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_FLUSH();
    
            result = false;
        }
    
        return result;
    }

    Have you initialized the crypto library correctly before calling the hash-function?

    Best regards.
    Jørgen

Reply
  • Hi,

    It looks similar to how we do it in our DFU bootloader for verification of hash of received image, but you may try to store the values of the symbols into uint32_t variables before passing to the function:

    // Function to check the hash received in the init command against the received firmware.
    // little_endian specifies the endianness of @p p_hash.
    static bool nrf_dfu_validation_hash_ok(uint8_t const * p_hash, uint32_t src_addr, uint32_t data_len, bool little_endian)
    {
        ret_code_t err_code;
        bool       result   = true;
        uint8_t    hash_be[NRF_CRYPTO_HASH_SIZE_SHA256];
        size_t     hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
        nrf_crypto_hash_context_t hash_context = {0};
    
        crypto_init();
    
        if (little_endian)
        {
            // Convert to hash to big-endian format for use in nrf_crypto.
            nrf_crypto_internal_swap_endian(hash_be,
                                            p_hash,
                                            NRF_CRYPTO_HASH_SIZE_SHA256);
            p_hash = hash_be;
        }
    
        NRF_LOG_DEBUG("Hash verification. start address: 0x%x, size: 0x%x",
                      src_addr,
                      data_len);
    
        err_code = nrf_crypto_hash_calculate(&hash_context,
                                             &g_nrf_crypto_hash_sha256_info,
                                             (uint8_t*)src_addr,
                                             data_len,
                                             m_fw_hash,
                                             &hash_len);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Could not run hash verification (err_code 0x%x).", err_code);
            result = false;
        }
        else if (memcmp(m_fw_hash, p_hash, NRF_CRYPTO_HASH_SIZE_SHA256) != 0)
        {
            NRF_LOG_WARNING("Hash verification failed.");
            NRF_LOG_DEBUG("Expected FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(p_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_DEBUG("Actual FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(m_fw_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_FLUSH();
    
            result = false;
        }
    
        return result;
    }

    Have you initialized the crypto library correctly before calling the hash-function?

    Best regards.
    Jørgen

Children
  •  size_t hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
            nrf_crypto_hash_context_t hash_context = {0};
    
           // uint32_t src_addr = CODE_START, data_len = CODE_SIZE;
    
            crypto_init();
            
            ret_code_t err_code;
            err_code = nrf_crypto_hash_calculate(&hash_context,
                             &g_nrf_crypto_hash_sha256_info,
                             (uint8_t*)challenge_no,
                             32,
                             temp1,
                             &hash_len);
           
            sha256_Raw(&challenge_no,32,temp2);
    

    I tried to check if nrf_crypto_hash work or not for that i passed random no to it and also to sha256_Raw .     After running both temp1 and temp2 value is equal , so don't think there's a issue in the initialization or working of it                                                                                          
                                                                                                                                                                    Thanks and Regard,
    Andhakanoon                                                                                                                                                                            

  • Are you checking all error return codes from the functions?

    andhakanoon said:
    but its going into SaSi_HalWaitInterrupt after nrf_crypto_hash_update and not coming back

    Does it enter SaSi_HalWaitInterrupt inside or after nrf_crypto_hash_update? This function is inside the CC310 library, so I'm not sure where that is called from. I cannot see any calls to it in our SDK (v17.0.2).

  • Does it enter SaSi_HalWaitInterrupt inside or after nrf_crypto_hash_update?

     its enters Sasi_HalWaitInterrupt insed nrf_crypto_hash_update , also nrf_crypto_hash_calculate works properly if data_len is less , but when i try to give large length it goes into Sasi_HalWaitInterrupt , Also i tried another hash_calculate function from another library and it is working , So is there anyway to crosscheck the hash generated .
    .

    thank you for helping and replying to my queries , very much appreciated                                                                                                                                                                           

  • Looks like the CC310 does not support hashing directly from Flash, so you need to copy pieces of the FW to RAM before hashing.

    I was able to correctly calculate the SHA256 Hash using the following code in the nrf_crypto_hash example:

    // Initialize the hash context
    err_code = nrf_crypto_hash_init(&hash_context, &g_nrf_crypto_hash_sha256_info);
    APP_ERROR_CHECK(err_code);
    
    // Run the update function (this can be run multiples of time if the data is accessible
    // in smaller chunks, e.g. when received on-air.
    uint32_t fw_start_addr = CODE_START;
    uint32_t fw_size = CODE_SIZE;
    uint32_t fw_piece_size = 0x1000;
    static uint8_t fw_piece[0x1000];
    NRF_LOG_INFO("FW Start address: %x", fw_start_addr);
    NRF_LOG_INFO("FW size: %x", fw_size);
    NRF_LOG_INFO("Hash piece size: %x", fw_piece_size);
    for(int fw_hash_start_addr = fw_start_addr; fw_hash_start_addr < (fw_start_addr + fw_size); fw_hash_start_addr+=fw_piece_size)
    {
        if((fw_hash_start_addr + fw_piece_size) > (fw_start_addr + fw_size))
        {
            fw_piece_size = fw_size - fw_hash_start_addr;
        }
        memcpy(fw_piece, (uint8_t *)(fw_start_addr+fw_hash_start_addr), fw_piece_size);
        err_code = nrf_crypto_hash_update(&hash_context, fw_piece, fw_piece_size);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("Current last hashed address: %x", fw_hash_start_addr + fw_piece_size);
    }
    // Run the finalize when all data has been fed to the update function.
    // this gives you the result
    err_code = nrf_crypto_hash_finalize(&hash_context, m_digest, &digest_len);
    APP_ERROR_CHECK(err_code);

    Note that I have not tested this with a lot of FW sizes or start addresses, so there may be some edge-cases that are not handled.

  • Thank you for your help and co-ordination and also sharing your code with few modification that worked for me.

    void fw_hash_calculate(uint8_t * m_digest){
    
        size_t hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
                nrf_crypto_hash_context_t hash_context = {0};
        // Initialize the hash context
        ret_code_t err_code = nrf_crypto_hash_init(&hash_context, &g_nrf_crypto_hash_sha256_info);
        APP_ERROR_CHECK(err_code);
    
        // Run the update function (this can be run multiples of time if the data is accessible
        // in smaller chunks, e.g. when received on-air.
        uint32_t fw_start_addr = CODE_START;
        uint32_t fw_size = CODE_SIZE;
        uint32_t fw_piece_size = 32;
        uint32_t end = CODE_END;
        static uint8_t fw_piece[32];
        printf("FW Start address: %x\n", fw_start_addr);
        printf("FW size: %x\n", fw_size);
        printf("FW end: %x\n", end);
        printf("Hash piece size: %x\n", fw_piece_size);
        for(int fw_hash_start_addr = fw_start_addr; fw_hash_start_addr < (fw_start_addr + fw_size); fw_hash_start_addr+=fw_piece_size)
        {
            if((fw_hash_start_addr + fw_piece_size) > (fw_start_addr + fw_size))
            {
                fw_piece_size = fw_start_addr + fw_size - fw_hash_start_addr;
            }
            memcpy(fw_piece, (uint8_t *)(fw_hash_start_addr), fw_piece_size);
            err_code = nrf_crypto_hash_update(&hash_context, fw_piece, fw_piece_size);
            APP_ERROR_CHECK(err_code);
            printf("Current last hashed address: %x\n", fw_hash_start_addr + fw_piece_size);
        }
        // Run the finalize when all data has been fed to the update function.
        // this gives you the result
    
        err_code = nrf_crypto_hash_finalize(&hash_context, m_digest, &hash_len);
        APP_ERROR_CHECK(err_code);
    }

Related