mbedtls_ecdh_compute_shared生成全0x00共享密钥问题排查
在32位微控制器上使用mbedtls实现ECDH时,导入对方公钥X、Y坐标后调用mbedtls_ecdh_compute_shared得到的共享密钥全为0x00,key_size=32,相关代码如下:
//Initialize the Static ECDH context and retrieve the static public key mbedtls_ecdh_init(&ECDH_Context_Static); mbedtls_ecp_group_load(&ECDH_Context_Static.grp, ElipticCurveID); mbedtls_ecdh_gen_public(&ECDH_Context_Static.grp, &ECDH_Context_Static.d, &ECDH_Context_Static.Q, mbedtls_ctr_drbg_random, &DRBG_Context); mbedtls_mpi_write_binary(&ECDH_Context_Static.Q.X, StaticPublicKey_X, key_size); //Write to char array from ECDH context -> copy out static public key mbedtls_mpi_write_binary(&ECDH_Context_Static.Q.Y, StaticPublicKey_Y, key_size); //Generate a Static shared secret using local Static private key and Host's Static public key success = mbedtls_mpi_read_binary(&ECDH_Context_Static.Qp.X, HostStaticPublicKey_X, key_size); //Read to ECDH context from char array -> load in Host's public key success = mbedtls_mpi_read_binary(&ECDH_Context_Static.Qp.Y, HostStaticPublicKey_Y, key_size); success = mbedtls_ecdh_compute_shared(&ECDH_Context_Static.grp, &ECDH_Context_Static.z, &ECDH_Context_Static.Qp, &ECDH_Context_Static.d, NULL, NULL); success = mbedtls_mpi_write_binary(&ECDH_Context_Static.z, StaticSecret, key_size); //Write to char array from ECDH context -> copy out static shared secret
问题原因与修复方案
未初始化对方公钥点的Z坐标
mbedtls的mbedtls_ecp_point结构包含X、Y、Z三个MPI变量,默认初始化后Z的值为0。在仿射坐标体系下,有效的公钥点Z必须设为1。如果Z保持0,计算时会直接导致共享密钥为0。
修复:导入X、Y坐标后,添加一行代码设置Z为1:mbedtls_mpi_set_int(&ECDH_Context_Static.Qp.Z, 1);未验证对方公钥的有效性
直接导入X、Y坐标就执行计算,无法确认该点是否在所选椭圆曲线上,也无法排除无穷远点等无效情况,这类无效点会导致计算结果异常。
修复:导入公钥后调用mbedtls_ecp_check_pubkey验证合法性:success = mbedtls_ecp_check_pubkey(&ECDH_Context_Static.grp, &ECDH_Context_Static.Qp); if(success != 0) { // 公钥无效,执行错误处理逻辑 }未检查API调用的返回值
代码中虽然用success变量接收了API返回值,但未判断是否成功。如果mbedtls_mpi_read_binary等步骤失败(比如输入数据长度不匹配、数值超出曲线范围),后续计算必然出错。
修复:每一步API调用后都检查返回值,非0则立即处理错误,避免继续执行无效逻辑。MPI写入的字节序与长度需匹配场景
mbedtls_mpi_write_binary按大端序写入数据,若你的场景需要小端序,应改用mbedtls_mpi_write_binary_le。同时可通过mbedtls_mpi_size(&ECDH_Context_Static.z)获取共享密钥的实际长度,确保写入StaticSecret时的长度符合预期。
内容的提问来源于stack exchange,提问作者russ

