我希望在两个平台之间执行ECDH以获得共享密钥。我打算使用一条命名曲线(该曲线尚未确定)。流程看起来像这样:
使用bouncycastle,最简洁的方法是什么?
我见过的几乎所有例子(如下所示:https://gist.github.com/wuyongzheng/0e2ed6d8a075153efcd3)都说明了达到共享秘密的过程,但似乎都没有考虑到实际序列化曲线/启动信息的过程点(G)到" Bob"以及如何在Bob的一侧使用该数据来重建曲线并生成相应的键。您需要向Bob发送哪些数据?
答案 0 :(得分:2)
我相信我找到了一种相对简洁的方式来展示问题/解决方案。我最初错过了命名曲线包含一个共同起点的事实,因此如果你有一个商定的曲线,就不需要序列化那些数据。
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
答案 1 :(得分:1)
您不一定需要发送曲线,您可以提前修复它。作为一个重要的例子,使用ECDSA而不是ECDH的比特币指定secp256k1。
但是,答案中的代码使用了Java PublicKey.getEncoded()
和PrivateKey.getEncoded()
返回的编码,这些编码是' X.509' (更准确地说是X.509中的SubjectPublicKeyInfo
结构)和' PKCS8'分别;看到javadoc。这些都是ASN.1编码,其中包含一个 AlgorithmIdentifier
包含参数,用于ECC定义曲线由ASN.1 OBJECT IDENTIFIER aka OID或基础字段的详细规范, Weierstrass曲线方程,基点,阶和辅因子的系数。在实践中,每个人都使用具有OID的标准命名曲线。这就是为什么在所有键打印输出中从偏移量2开始的21个字节是相同的;它是一个ASN.1 SEQUENCE,包含算法的OID(id-ecPublicKey)和所选曲线的OID(prime256v1)。
其他方案也是可能的。 TLS ECDHE发送曲线细节或一个小整数,标识rfc4492中定义的标准曲线,后者几乎总是使用; static-ECDH使用X.509证书,因此使用X.509格式。 SSH ECDH ephemeral或ECMQV发送包含名称或OID的字符串,请参阅rfc5656。 CMS和S / MIME使用包含AlgorithmIdentifier
和OID格式namedCurve
参数的ASN.1结构,请参阅rfc 5753。