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

LESC_DEBUG_MODE define in ble_app_multirole_lesc, nRF5 SDK 15.0.0

Device: nRF52832

SDK: nRF5 SDK 15.0.0

SoftDevice 6.0.0

Hello. I'm using using the ble_app_multirole_lesc example with nRF5 SDK 15.0.0. I'm trying to debug using my sniffer, and want to use the debug private key. The following define exists in the main.c code which seems like it should set the private key to the debug key:

#define LESC_DEBUG_MODE 1 /**< Set to 1 to use LESC debug keys, allows you to use a sniffer to inspect traffic. */

The problem, though, is that this define doesn't appear to do anything. The LESC_DEBUG_MODE symbol is not used anywhere else in the code. I went back to the 14.2.0 SDK and found some code in the sample application that made use of the LESC_DEBUG_MODE flag:

#if LESC_DEBUG_MODE

/**@brief Bluetooth SIG debug mode Private Key */
#error Generated private key is not supported.
__ALIGN(4) static const ble_gap_lesc_p256_sk_t m_lesc_private_key =
{{
0xbd,0x1a,0x3c,0xcd,0xa6,0xb8,0x99,0x58,0x99,0xb7,0x40,0xeb,0x7b,0x60,0xff,0x4a,
0x50,0x3f,0x10,0xd2,0xe3,0xb3,0xc9,0x74,0x38,0x5f,0xc5,0xa3,0xd4,0xf6,0x49,0x3f
}};

#else

#endif

Unfortunately, even with the above code I don't quite understand how the debug key works because the m_lesc_private_key structure is not actually used anywhere. I would think that 

In any case, what I really need is to use the private key with SDK 15.0.0, not 14.2.0. From my understanding of the code I would have though that the code related to the debug private key would need to be in ble_lesc.c rather than in the application code (since the key generation and management are handled by that module rather than the application).

Could you please provide guidance for using the debug key?

Thanks.

  • Hi,

    It is correct that we have removed the debug key from SDK 15.0. The reason why we have removed the debug key is that we don’t want customers enabling and using the debug key by accident in their end-products. Using the debug key, and using a sniffer to monitor the encrypted connection is mostly done for very specific testing, and generally not something developers need to do. The define LESC_DEBUG_MODE is not used in SDK 15.0 , and will be removed completely in the next version of the SDK.

    From my understanding of the code I would have though that the code related to the debug private key would need to be in ble_lesc.c rather than in the application code (since the key generation and management are handled by that module rather than the application).

    That is correct. The correct place to override, and use the debug key would be in the function ble_lesc_ecc_keypair_generate_and_set(), where you would not use the auto generated key from nrf_crypto_ecc_key_pair_generate(), but instead use the static debug key.

  • So... what to do if you need to sniff encrypted BLE traffic (LESC)? Note that I'm taking to Daniel Velleux and Patyush about this, and the advise seems to be tinker with the SDK to hack it in. Sigh.

    The suggesting is to start with adding the following to nrf_ble_lesc.c:

    __ALIGN(4) static const ble_gap_lesc_p256_sk_t m_lesc_private_key = {{
        0xbd,0x1a,0x3c,0xcd,0xa6,0xb8,0x99,0x58,0x99,0xb7,0x40,0xeb,0x7b,0x60,0xff,0x4a,
        0x50,0x3f,0x10,0xd2,0xe3,0xb3,0xc9,0x74,0x38,0x5f,0xc5,0xa3,0xd4,0xf6,0x49,0x3f
    }};
    

    Note that we're currently calling nrf_ble_lesc_request_handler(), which I assume generates the keys and v16 of the SDK. I can't find ble_lesc_ecc_keypair_generate_and_set() in my project. Is the above advise stale, or am I missing something?

    Other suggestions/next steps are welcome.

  • One way to accomplish this in SDK16/17 is to return the debug key instead of generating a random one. In the case of the Oberon backend that can be done in oberon_backend_ecc.c:

    ret_code_t nrf_crypto_backend_oberon_ecc_secp256r1_rng(uint8_t data[32])
    
    {
    
    #if NRF_MODULE_ENABLED(NRF_CRYPTO_RNG)
    
    #ifdef DEBUG
    
    static const uint8_t LESC_DEBUG_KEY[32] =
    
    {
    
          0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50,
    
          0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd
    
    };
    
     
    
        for (int i=0; i < sizeof(LESC_DEBUG_KEY); i++)
    
        {
    
          data[i] = LESC_DEBUG_KEY[i];
    
        }
    
     
    
        return NRF_SUCCESS;
    
    #else
    
        static const uint8_t min_value[32] =
    
        {
    
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    
        };
    
        static const uint8_t max_value[32] =
    
        {
    
            0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    
            0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x50,
    
        };
    
     
    
        return nrf_crypto_rng_vector_generate_in_range(data, min_value, max_value, 32);
    
    #endif
    
    #else
    
        return NRF_ERROR_CRYPTO_FEATURE_UNAVAILABLE;
    
    #endif
    
    }

    Note that the byte order is reversed compared to m_lesc_private_key in the original question above.

  • Using the debug key, and using a sniffer to monitor the encrypted connection is mostly done for very specific testing, and generally not something developers need to do.

    If you need to diagnose any kind of Bluetooth issue with a sniffer, it is something you need to do!

    To build on Daniel's answer, to do this only for the lesc key (not all generated keys) and regardless of backend, modify the following function in nrf_ble_lesc.c:

    ret_code_t nrf_ble_lesc_keypair_generate(void)
    {
        ret_code_t err_code;
        size_t     public_len = NRF_CRYPTO_ECC_SECP256R1_RAW_PUBLIC_KEY_SIZE;
    
        // Check if any DH computation is pending
        for (uint32_t i = 0; i < ARRAY_SIZE(m_peer_keys); i++)
        {
            if (m_peer_keys[i].is_valid)
            {
                return NRF_ERROR_BUSY;
            }
        }
    
        // Update flag to indicate that there is no valid private key.
        m_keypair_generated       = false;
        m_lesc_oobd_own_generated = false;
    
    #if defined(DEBUG) && LESC_DEBUG_MODE
    #warning "Compiling with ECC debug key"
        UNUSED_VARIABLE(m_keygen_context);
        NRF_LOG_WARNING("Using debug ECC key pair");
        static const uint8_t LESC_DEBUG_KEY[32] = {
                0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3, 0xd2, 0x10, 0x3f, 0x50,
                0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99, 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd
        };
    
        err_code = nrf_crypto_ecc_private_key_from_raw(&g_nrf_crypto_ecc_secp256r1_curve_info, &m_private_key, LESC_DEBUG_KEY, sizeof(LESC_DEBUG_KEY));
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("nrf_crypto_ecc_private_key_from_raw() returned error 0x%x.", err_code);
            return err_code;
        }
        nrf_crypto_ecc_public_key_calculate_context_t calc_context;
        err_code = nrf_crypto_ecc_public_key_calculate(&calc_context, &m_private_key, &m_public_key);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("nrf_crypto_ecc_public_key_calculate() returned error 0x%x.", err_code);
            return err_code;
        }
    #else
        NRF_LOG_DEBUG("Generating ECC key pair");
        err_code = nrf_crypto_ecc_key_pair_generate(&m_keygen_context,
                                                    &g_nrf_crypto_ecc_secp256r1_curve_info,
                                                    &m_private_key,
                                                    &m_public_key);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("nrf_crypto_ecc_key_pair_generate() returned error 0x%x.", err_code);
            return err_code;
        }
    #endif
    
    
    
        // Convert to a raw type.
        err_code = nrf_crypto_ecc_public_key_to_raw(&m_public_key,
                                                    m_lesc_public_key.pk,
                                                    &public_len);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("nrf_crypto_ecc_public_key_to_raw() returned error 0x%x.", err_code);
            return err_code;
        }
    
        // Invert the raw type to little-endian (required for BLE).
        err_code = nrf_crypto_ecc_byte_order_invert(&g_nrf_crypto_ecc_secp256r1_curve_info,
                                                    m_lesc_public_key.pk,
                                                    m_lesc_public_key.pk,
                                                    NRF_CRYPTO_ECC_SECP256R1_RAW_PUBLIC_KEY_SIZE);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("nrf_crypto_ecc_byte_order_invert() returned error 0x%x.", err_code);
        }
        else
        {
            // Set the flag to indicate that there is a valid ECDH key pair generated.
            m_keypair_generated = true;
        }
    
        return err_code;
    }

Related