如何通过BearSSL将RSA公钥传输至同型号客户端开发板?
问题描述
两块集成BearSSL的同型号开发板,已通过br_rsa_i15_keygen生成RSA密钥对,需要将公钥传输到另一块开发板。最初的传输代码直接读取br_rsa_public_key的n数组转换为char后发送,但传输失败。添加调试代码后发现,n数组的数据会持续变化,猜测是BearSSL的时序攻击防护导致。
最初的传输代码:
bool trans_pk(WiFiClient &client, br_rsa_public_key &t_pk) { char t_pkn[t_pk.nlen] = {0}; for (int i = 0; i < t_pk.nlen; i++) { t_pkn[i] = (char)t_pk.n[i]; } // Socket传输函数 // transfer_sock(WiFiClient &client, const char *data, uint8_t dsize) transfer_sock(client, t_pkn, t_pk.nlen); // e部分的代码和n部分一致,仅变量名不同 return true; }
调试代码(发现n数组数据变化):
for (int i = 0; i < t_pk.nlen; i++) { Serial.printf("%02x ", t_pk.n[i]); } Serial.printf("\n"); delay(1000); for (int i = 0; i < t_pk.nlen; i++) { Serial.printf("%02x ", t_pk.n[i]); } Serial.printf("\n");
解决方案
问题根源
你看到的n数组变化是正常现象:br_rsa_i15_keygen生成的是蒙哥马利形式的RSA公钥,BearSSL为了防范时序攻击,会对该公钥结构中的n做动态盲化(每次操作前后添加/移除随机小偏移),所以直接读取内存中的n数组会得到变化的值,但这不是真正的公钥模数。
正确的传输步骤
需要先将蒙哥马利形式的公钥转换为标准RSA公钥格式,得到固定的n(模数)和e(公钥指数),再进行传输:
- 转换公钥格式
使用BearSSL提供的br_rsa_i15_pub_to_rsa函数,将蒙哥马利公钥转换为标准RSA公钥:
#include <bearssl_rsa.h> bool trans_pk(WiFiClient &client, br_rsa_i15_public_key &t_pk) { // 定义标准RSA公钥结构,分配存储n和e的缓冲区 br_rsa_public_key standard_pk; uint8_t n_buf[BR_RSA_I15_MAX_NLEN]; // 根据你的密钥长度调整,比如2048位密钥对应256字节 uint8_t e_buf[4]; // 公钥指数e通常是65537,占4字节 // 初始化标准公钥结构 standard_pk.n = n_buf; standard_pk.nlen = t_pk.nlen; standard_pk.e = e_buf; // 执行格式转换,返回e的长度 standard_pk.elen = br_rsa_i15_pub_to_rsa(&t_pk, &standard_pk); if (standard_pk.elen == 0) { // 转换失败,处理错误 return false; } // 直接传输标准公钥的n(无需转char,强制类型转换即可) transfer_sock(client, (const char*)standard_pk.n, standard_pk.nlen); // 传输标准公钥的e transfer_sock(client, (const char*)standard_pk.e, standard_pk.elen); return true; }
- 接收方处理
接收方收到n和e的字节后,组装成br_rsa_public_key结构即可使用;如果需要转换为蒙哥马利形式以适配BearSSL的快速运算接口,可以调用br_rsa_i15_pub_from_rsa函数完成转换。
额外注意事项
- 避免使用
char存储公钥字节:char可能是有符号类型,会导致0x80及以上的字节被错误转换,直接使用uint8_t数组或强制转换为const char*传输即可。 - BearSSL的大整数采用大端字节序,传输和接收时保持字节顺序一致即可,无需额外调整。
内容的提问来源于stack exchange,提问作者ysPan
相关产品推荐
相关产品推荐

