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

如何在 Java 中序列化和使用 ECDH 参数

魏安宁
2023-03-14

我希望在两个平台之间执行ECDH以导出共享密钥。我计划使用命名曲线(该曲线尚未确定)。该流看起来像这样:

  • Alice挑了一条曲线
  • Alice为她的曲线生成一个随机密钥对
  • Alice序列化了一些关于她的曲线的数据
  • Alice将她的公钥和曲线数据发送给Bob
  • Bob用Alice的数据初始化一条曲线
  • Bob根据Alice的数据创建密钥对
  • Bob执行ECDH派生共享秘密
  • Bob用他的公钥回应Alice
  • Alice执行ECDH导出共享秘密

使用弹力城堡,实现此目的的最干净方法是什么?

我见过的几乎所有例子(比如这个:https://gist.github.com/wuyongzheng/0e2ed6d8a075153efcd3)都说明了到达共享秘密的过程,但似乎没有一个因素将曲线/起点(G)的信息实际序列化为“Bob”,以及如何在Bob一侧使用这些数据来重建曲线并生成相应的密钥。您需要向 Bob 发送哪些数据?

共有2个答案

宦书
2023-03-14

您不一定需要发送曲线,您可以提前修复它。作为一个重要的例子,使用ECDSA而不是ECDH的比特币指定了secp256k1。

但是,您答案中的代码使用了Java < code > public key . get encoded()和< code > private key . get encoded()返回的编码,它们分别是“X.509”(更准确地说是X.509中的< code > SubjectPublicKeyInfo 结构)和“pkcs 8”;请参见javadoc。这两种编码都是ASN.1编码,包括< code>AlgorithmIdentifier,其中包含用于ECC的参数,这些参数通过ASN.1对象标识符(又名OID)或基础字段的详细规范、Weierstrass曲线方程的系数、基点、阶数和余因子来定义曲线。实际上,每个人都使用具有oid的标准命名曲线。这就是为什么所有键打印输出中从偏移量2开始的21个字节是相同的;它是一个ASN.1序列,包含算法的OID(id-ecPublicKey)和所选曲线的OID(prime 256 v1)。

其他方案也是可能的。TLS ECDHE发送曲线详细信息或一个小整数,该整数标识rfc4492中定义的标准曲线,后者几乎总是使用;静态ECDH使用X.509证书,因此是X.509格式。SSHECDH临时或ECMQV发送一个包含名称或OID的字符串,请参见rfc5656。CMS和因此S/MIME使用ASN.1结构,其中包含<代码>算法标识符和OID-form<代码>namedCurve参数,请参见rfc 5753。

谢阳曜
2023-03-14

我相信我找到了一种相对简洁的方式来演示这个问题/解决方案。我最初忽略了一个事实,即命名曲线包含一个公共起点,因此如果您有一条商定的曲线,则无需序列化该数据。

Security.addProvider(new BouncyCastleProvider());

// Alice sets up the exchange
KeyPairGenerator aliceKeyGen = KeyPairGenerator.getInstance("ECDH", "BC");
aliceKeyGen.initialize(new ECGenParameterSpec("prime256v1"), new SecureRandom());

KeyPair alicePair = aliceKeyGen.generateKeyPair();
ECPublicKey alicePub = (ECPublicKey)alicePair.getPublic();
ECPrivateKey alicePvt = (ECPrivateKey)alicePair.getPrivate();

byte[] alicePubEncoded = alicePub.getEncoded();
byte[] alicePvtEncoded = alicePvt.getEncoded();

System.out.println("Alice public: " + DatatypeConverter.printHexBinary(alicePubEncoded));
System.out.println("Alice private: " + DatatypeConverter.printHexBinary(alicePvtEncoded));


// POST hex(alicePubEncoded)

// Bob receives Alice's public key

KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey remoteAlicePub = kf.generatePublic(new X509EncodedKeySpec(alicePubEncoded));

KeyPairGenerator bobKeyGen = KeyPairGenerator.getInstance("ECDH", "BC");
bobKeyGen.initialize(new ECGenParameterSpec("prime256v1"), new SecureRandom());

KeyPair bobPair = bobKeyGen.generateKeyPair();
ECPublicKey bobPub = (ECPublicKey)bobPair.getPublic();
ECPrivateKey bobPvt = (ECPrivateKey)bobPair.getPrivate();

byte[] bobPubEncoded = bobPub.getEncoded();
byte[] bobPvtEncoded = bobPvt.getEncoded();

System.out.println("Bob public: " + DatatypeConverter.printHexBinary(bobPubEncoded));
System.out.println("Bob private: " + DatatypeConverter.printHexBinary(bobPvtEncoded));

KeyAgreement bobKeyAgree = KeyAgreement.getInstance("ECDH");
bobKeyAgree.init(bobPvt);
bobKeyAgree.doPhase(remoteAlicePub, true);

System.out.println("Bob secret: " + DatatypeConverter.printHexBinary(bobKeyAgree.generateSecret()));


// RESPOND hex(bobPubEncoded)

// Alice derives secret

KeyFactory aliceKf = KeyFactory.getInstance("EC");
PublicKey remoteBobPub = aliceKf.generatePublic(new X509EncodedKeySpec(bobPubEncoded));

KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("ECDH");
aliceKeyAgree.init(alicePvt);
aliceKeyAgree.doPhase(remoteBobPub, true);

System.out.println("Alice secret: " + DatatypeConverter.printHexBinary(aliceKeyAgree.generateSecret()));

在第一次运行时,这产生了:

Alice public: 3059301306072A8648CE3D020106082A8648CE3D03010703420004D8FF8DAB9683C7D6C798FE381775AE3BCC25260E2B270C57584F684BFBF59A73221480040E70993F2F4DEBE25A19E772896F5C98DFAE6865C31830BBD876E8DF
Alice private: 308193020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420A08DEC852618FA6BF0CA8B67DFFCC72AA39BE7402978CA456F73660337837DE1A00A06082A8648CE3D030107A14403420004D8FF8DAB9683C7D6C798FE381775AE3BCC25260E2B270C57584F684BFBF59A73221480040E70993F2F4DEBE25A19E772896F5C98DFAE6865C31830BBD876E8DF
Bob public: 3059301306072A8648CE3D020106082A8648CE3D03010703420004E4343FD573F117446925BBFE0DEF591098AA300066AB4F51DC2736736C8CE18BA72EA67AE4D0D6DD5E22007BA45BAA9DCE473002D17D6A29207AA15A1E97C596
Bob private: 308193020100301306072A8648CE3D020106082A8648CE3D030107047930770201010420D272E7BD59F7EA2AA3710910073AFE58082BC460B347A3782981CCCABA452538A00A06082A8648CE3D030107A14403420004E4343FD573F117446925BBFE0DEF591098AA300066AB4F51DC2736736C8CE18BA72EA67AE4D0D6DD5E22007BA45BAA9DCE473002D17D6A29207AA15A1E97C596
Bob secret: B65B4C8A1C797B867CE39F26DC97A0241A407FC79CF0D3CBA061A4A907CF3E1B
Alice secret: B65B4C8A1C797B867CE39F26DC97A0241A407FC79CF0D3CBA061A4A907CF3E1B
 类似资料:
  • 我有一个kdtree,其节点由以下字段组成:公共静态类节点实现可序列化{ 其中DataPoint定义: 公共静态类DataPoint实现可序列化{公共可比X;公共可比Y;公共可比Z; 我想序列化树,存储在文件中并在回答范围查询时反序列化。我对这个概念od序列化的理解并不好。从我收集的任何内容中,我编写了以下函数,但不起作用。有人能帮忙吗?

  • 我试图在Angular2中使用http参数序列化器。我谷歌了很多,但是例子只适用于angular1,如下所示。如何在templateUrl中注入$http参数序列化器 在Angular2中使用它的语法是什么?

  • 问题内容: 如何序列化未实现Serializable的对象?我不能将其标记为Serializable,因为该类来自第3方库。 问题答案: 您不能序列化未实现的类,但可以将其包装在可以实现的类中。为此,您应该在包装器类上实现和,以便可以以自定义方式序列化其对象。 首先,使您的非序列化字段。 在中,首先调用流以存储所有非瞬态字段,然后调用其他方法来序列化不可序列化对象的各个属性。 在中,首先调用流以读

  • 问题内容: 我想深入克隆一个列表。为此,我们有一种方法 所以现在要克隆我的列表,我应该先将其转换为可序列化的。是否可以将列表转换为可序列化列表? 问题答案: 已实施的所有标准实施。 因此,即使它本身不是的子类型,也可以安全地将列表强制转换为,只要您知道它是诸如或的标准实现之一。 如果不确定,请先复制列表(使用),然后知道它是可序列化的。

  • 问题内容: 我意识到这有点不稳定,但是我想使用Jersey客户端使用Java序列化作为“编组” 将Spring Integration发送到Jersey服务器。是否对此具有内置或贡献支持,还是我必须编写自己的MessageBodyReader / Writer?我试图在客户端请求的类型设置到两个“应用程序/ x-java的序列化对象”,并和它只是提供了常用的: 谷歌和泽西岛用户指南都对这一主题感到

  • 问题内容: 我已经开始在我的第一个android应用程序上进行工作,并且具有处理多层图像的应用程序。我能够将项目文件的平面版本导出为PNG,但我希望能够保存分层图像以供以后编辑(包括应用于某些层的任何选项,例如基于文本的层)。 无论如何,我已经确保需要写入文件的类是“可序列化的”,但是由于android.graphics.Bitmap不可序列化这一事实而遇到了一些障碍。以下代码实质上将位图作为PN