[英]Java Bouncy Castle : Invalid point encoding 0x45
我正在使用bouncy castle
庫在java
中加載公鑰,但總是收到錯誤Invalid point encoding 0x45
。
公鑰是在客戶端使用 C# CNG API 生成的。
Java方法一:
public PublicKey loadPublicKey(String encodedPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] keybytes = java.util.Base64.getDecoder().decode(encodedPublicKey);
Security.addProvider(new BouncyCastleProvider());
ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("P-256");
ECPublicKeySpec keySpec = new ECPublicKeySpec(params.getCurve().decodePoint(keybytes), params);
return new BCECPublicKey("ECDH", keySpec, BouncyCastleProvider.CONFIGURATION);
}
方法二
public PublicKey loadPublicKey(String pKey) throws Exception {
byte[] keybytes = java.util.Base64.getDecoder().decode(pKey);
Security.addProvider(new BouncyCastleProvider());
ECParameterSpec params = ECNamedCurveTable.getParameterSpec("P-256");
ECPublicKeySpec pubKey = new ECPublicKeySpec(params.getCurve().decodePoint(keybytes), params);
KeyFactory kf = KeyFactory.getInstance("ECDH", "BC");
return kf.generatePublic(pubKey);
}
例外
java.lang.IllegalArgumentException: Invalid point encoding 0x45
at org.bouncycastle.math.ec.ECCurve.decodePoint(ECCurve.java:443)
下面的方法來創建公鑰
public static (byte[] publicKey, byte[] privateKey) CreateKeyPair()
{
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(
// need to do this to be able to export private key
CngKey.Create(
CngAlgorithm.ECDiffieHellmanP256,
null,
new CngKeyCreationParameters
{ ExportPolicy = CngExportPolicies.AllowPlaintextExport })))
{
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha256;
// export both private and public keys and return
var pr = cng.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
var pub = cng.PublicKey.ToByteArray();
return (pub, pr);
}
}
生成RUNLMSAAAAHddHI6TOEDG/Ka7naBbLQH0u/DSFfbKJI2w0WSoxrmFkwKm1tktz4wD0rqnwkZp8FwdHJ+8OVrTcpDMmxrwvS6
我在 java 收到的密鑰是72 bytes
。 但我認為bouncy castle java
支持64 bytes
的密鑰。
我也在調查這個但沒有得到任何幫助
C# 代碼將公鑰導出為 Base64 編碼的EccPublicBlob
,其格式在問題中給出的鏈接中描述:
前 4 個字節 0x45434B31 以小端順序表示曲線 P-256 的公共 ECDH 密鑰,接下來的 4 個字節以小端順序表示密鑰長度(以字節為單位)(0x20000000 = 32),其余是曲線 P-256 的 x 和 y 坐標EC點即公鑰,每個32字節。
令人驚訝的是,在您發布的密鑰中,第二個 4 個字節是 0x20000001,但 x 和 y 坐標各為 32 個字節。 這里可能存在復制/粘貼錯誤。 無論如何,使用發布的 C# 代碼,我無法在第二個 4 字節中重現值不是 0x20000000 的鍵。
Java/BC 不直接支持導入EccPublicBlob
(這是 MS 專有的),但它確實支持導入未壓縮的公鑰。 這會在 x 和 y 坐標連接並且 0x04 用作前綴時產生。 然后可以使用 Java/BC 進行導入,如下所示:
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.ECPointUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
...
public static PublicKey getPubKeyFromCurve(byte[] uncompRawPubKey, String curveName) throws Exception {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveName);
ECNamedCurveSpec params = new ECNamedCurveSpec(spec.getName(), spec.getCurve(), spec.getG(), spec.getN());
ECPoint point = ECPointUtil.decodePoint(params.getCurve(), uncompRawPubKey);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
KeyFactory kf = KeyFactory.getInstance("ECDH", new BouncyCastleProvider());
ECPublicKey pubKey = (ECPublicKey) kf.generatePublic(pubKeySpec);
return pubKey;
}
測試(假設EccPublicBlob
是 Base64 編碼的,就像發布的一樣):
import java.util.Base64;
...
String publicKeyBlob = "RUNLMSAAAAAFzw4IGY4N8PKVt0MGF38SAKU5ixJhptVUdrWzuPhFDOcj/2k4SlGRN1RpRMbar9Iu7Uvcx7Vtm8Wa0HSzWJdE";
byte[] rawPublic = new byte[65];
rawPublic[0] = 0x04;
System.arraycopy(Base64.getDecoder().decode(publicKeyBlob), 8, rawPublic, 1, 64);
PublicKey pub = getPubKeyFromCurve(rawPublic, "P-256");
System.out.println(Base64.getEncoder().encodeToString(pub.getEncoded())); // MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBc8OCBmODfDylbdDBhd/EgClOYsSYabVVHa1s7j4RQznI/9pOEpRkTdUaUTG2q/SLu1L3Me1bZvFmtB0s1iXRA==
該測試導入EccPublicBlob
並將其導出為 X.509/SPKI 格式的 Base64 編碼的 DER 密鑰。 這可以使用 ASN.1 解析器讀取,例如https://lapo.it/asn1js/ ,從而得到驗證。
請注意,C# 還支持其他格式的導出。 但是,這取決於版本。 例如,從 .NET Core 3.0 開始,有方法ExportSubjectPublicKeyInfo()
以 X.509/SPKI 格式導出公鑰,DER 編碼。 這種格式和編碼可以使用X509EncodedKeySpec
直接導入 Java(即使沒有 BouncyCastle)。
在其他版本的 C# 中,可以使用 BouncyCastle for C# 進行導出,它也支持 X.509/SPKI 格式。
由於您沒有發布您的 .NET 版本,因此尚不清楚您有哪些具體的替代方案。
請記住,P-256 的 ECDH 密鑰也可以通過以下方式更簡單地創建:
ECDiffieHellmanCng cng = new ECDiffieHellmanCng(ECCurve.NamedCurves.nistP256)
或跨平台
ECDiffieHellman ecdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.