当前位置: 首页 > 知识库问答 >
问题:

无法从Java BouncyCastle ECDH中的MbedTLS读取公钥

潘弘博
2023-03-14

我正在尝试使用BouncyCastle在运行mbedTLS和Java的嵌入式设备之间进行ECDH。当我比较生成的密钥长度时,我得到了由mbedTLS制作的66字节密钥和由BC制作的65字节密钥。附加伪代码:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
kpg.initialize(256);
KeyPair localKp = kpg.generateKey();

ASN1Sequence sequence = DERSequence.getInstance(localKp.getPublic().getEncoded());
DERBitString subjectPublicKey = (DERBitString) sequence.getObjectAt(1);
byte[] encodedLocalPublicKey = subjectPublicKey.getBytes();
// encodedLocalPublicKey.length -> 65

MbedTLS:

mbedtls_ecdh_context ecdh;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_context entropy;
const char pers[] = "ecdh";

mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
mbedtls_ecdh_init(&ecdh);

int ret = 0;
if((ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                               (const unsigned char *) pers,
                               sizeof pers )) != 0) {
    mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
}

ret = mbedtls_ecp_group_load(&ecdh.grp, MBEDTLS_ECP_DP_SECP256R1);
if (ret != 0) {
    mbedtls_printf( " failed\n  ! mbedtls_ecp_group_load returned %d\n", ret );
}

size_t olen;
unsigned char buf[1024];
ret = mbedtls_ecdh_make_public(&ecdh, &olen, buf, sizeof(buf), mbedtls_ctr_drbg_random, &ctr_drbg);
// ret is 0, olen is 66

当我将MbedTLS密钥加载到Java中时,它会抛出java.lang.IllegalArgumentException:无效的点编码0x41:

byte[] publicKeyBytes = ... FROM MbedTLS
log.info("Public key length: {}", publicKeyBytes.length); // Shows 66
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("P-256");
ECPoint point = ecSpec.getCurve().decodePoint(publicKeyBytes); // This line throws

我尝试在Java和MbedTLS之间做ECDH Java。两个测试都成功了,但是它们无法跨平台交换。

我做错了什么?很抱歉,可能是显而易见的问题,但我正在努力处理它。我将感激任何帮助。

谢谢你。

共有1个答案

顾俊楚
2023-03-14

mbedtls_ecdh_make_public的API留档:

该函数生成一个公钥,并将其作为TLS ClientKeyExchange有效负载导出。

这是TLS特有的功能。从例如RFC 8442,我们看到椭圆曲线点的编码是:

struct {
    opaque point <1..2^8-1>;
} ECPoint;

这需要对TLS表示语言有一定的了解,但最终它相当于:TLS在常规点编码的开头添加了一个额外的(无符号)字节,该字节将包含余数的长度。

在您的示例中,可以看到mbedtls输出66个字节。第一个字节包含值65,这是输出其余部分的长度,最后的65个字节的格式与BC使用的格式相同。您需要提取最后65个字节,或者以某种方式忽略第一个字节。

P、 在Java中生成密钥对的方法非常脆弱,因为您只指定了大小,而不是精确的曲线。对于256位,BC确实默认为P-256,但这不是必需的行为,其他提供者(或某些未来的BC版本)可能会选择其他曲线。最好显式生成P-256密钥对。我还建议使用更清晰的代码来获取Java版本中的公钥编码:

byte[] spkiEnc = localKp.getPublic().getEncoded();
SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(spkiEnc);
byte[] encodedLocalPublicKey = spki.getPublicKeyData().getOctets();
 类似资料:
  • 问题内容: 这是我的代码: OpenSSL能够通过命令行解码X509证书,因此我知道它是有效的证书。但是Java似乎并不喜欢它。 无论有没有尾随的\ n,我都已经厌倦了。 有任何想法吗? 问题答案: - 更新 正如评论中提到的那样,OP解决方案唯一的问题是OP 使用的是密钥,而不是证书。 这是 无需Base64转换 的代码 , 因为它本身可以读取PEM文件(它会查找块本身以知道它正在读取PEM文件

  • 我有一个问题做npm启动,这似乎是一个bug与css-loader但我不能修复它。 我读过这篇文章,但我不能让它工作:https://github.com/reactjsresources/react-webpack-babel/issues/197 我还修改了webpack.config.js,添加了: 和: 如果有人能帮忙请... 谢谢.

  • 我有以下前缀: 有办法 在intellij中,idea工作正常,但启动jar时出现错误: JAVA尼奥。文件NoSuchFileException:文件:/app。罐子/BOOT-INF/classes/模板/请求订单/未标记/请求订单未标记。pdf

  • 我有一个包含两部分的简单程序:一个Spring5服务器,其中一个endpoint返回Mono 当我浏览到http://localhost:8080/rand返回一个双精度值。但是,当我使用客户机时,检索到的值始终为null(响应状态为200)。 我错过了什么?

  • 问题内容: 大家好(这是我的第一个问题,请不要太粗鲁)。我是编码初学者,并且在Android Studio中遇到了此错误:“ Gradle项目同步失败”,错误为“错误:无法从/ Users / sgrumo / Downloads / gvr-android-sdk- master读取packageName /samples/sdk-treasurehunt/src/main/AndroidMan