我知道EC公钥的曲线名称(secp256k1
)以及X
和Y
坐标。
如何从中org.bouncycastle.jce.interfaces.ECPublicKey
制作出来?
我已阅读https://stackoverflow.com/a/29355749/5453873但其中的代码使用的是java.security...
而不是org.bouncycastle...
,而ECPublicKey是org.bouncycastle...
中的一个接口,而不是一个可实例化的类。
答案 0 :(得分:7)
这将生成JCE / JCA中使用的EC公钥。 Bouncy Castle提供商可以直接使用这些软件密钥。否则,Bouncy仅用于生成生成公钥所需的参数。
package nl.owlstead.stackoverflow;
import static java.nio.charset.StandardCharsets.US_ASCII;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import javax.crypto.Cipher;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.util.encoders.Hex;
public class ECPublicKeyFactory {
public static void main(String[] args) throws Exception {
String name = "secp256r1";
Security.addProvider(new BouncyCastleProvider());
// === NOT PART OF THE CODE, JUST GETTING TEST VECTOR ===
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(name);
kpg.initialize(ecGenParameterSpec);
ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic();
byte[] x = key.getW().getAffineX().toByteArray();
byte[] y = key.getW().getAffineY().toByteArray();
// === here the magic happens ===
KeyFactory eckf = KeyFactory.getInstance("EC");
ECPoint point = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(name);
ECParameterSpec spec = new ECNamedCurveSpec(name, parameterSpec.getCurve(), parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH(), parameterSpec.getSeed());
ECPublicKey ecPublicKey = (ECPublicKey) eckf.generatePublic(new ECPublicKeySpec(point, spec));
System.out.println(ecPublicKey.getClass().getName());
// === test 123 ===
Cipher ecies = Cipher.getInstance("ECIESwithAES", "BC");
ecies.init(Cipher.ENCRYPT_MODE, ecPublicKey);
byte[] ct = ecies.doFinal("owlstead".getBytes(US_ASCII));
System.out.println(Hex.toHexString(ct));
}
}
最初我认为需要一个Bouncy Castle特定密钥,因此以下代码生成了Bouncy Castle轻量级API中使用的EC公钥。
package nl.owlstead.stackoverflow;
import java.math.BigInteger;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
public class BC_EC_KeyCreator {
public static void main(String[] args) throws Exception {
String name = "secp256r1";
// === NOT PART OF THE CODE, JUST GETTING TEST VECTOR ===
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
kpg.initialize(new ECGenParameterSpec(name));
ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic();
byte[] x = key.getW().getAffineX().toByteArray();
byte[] y = key.getW().getAffineY().toByteArray();
// assumes that x and y are (unsigned) big endian encoded
BigInteger xbi = new BigInteger(1, x);
BigInteger ybi = new BigInteger(1, y);
X9ECParameters x9 = ECNamedCurveTable.getByName(name);
ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
ECCurve curve = x9.getCurve();
ECPoint point = curve.createPoint(xbi, ybi);
ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid,
x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(point, dParams);
System.out.println(pubKey);
// some additional encoding tricks
byte[] compressed = point.getEncoded(true);
System.out.println(Hex.toHexString(compressed));
byte[] uncompressed = point.getEncoded(false);
System.out.println(Hex.toHexString(uncompressed));
}
}
这非常棘手,因为我不想包含任何特定于JCE的代码,X9ECParameters
不是ECDomainParameters
的子类。所以我使用了从Bouncy Castle代码库中其他地方复制的ECNamedDomainParameters
转换。
答案 1 :(得分:2)
在下面的代码中,encoded
包含0x04
后跟32个字节的X,然后是32个字节的Y.
或者,它可以包含0x02
或0x03
(取决于Y的符号),后跟32个字节的X.
public static ECPublicKey decodeKey(byte[] encoded) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException{
ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
ECCurve curve = params.getCurve();
java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());
java.security.spec.ECPoint point = ECPointUtil.decodePoint(ellipticCurve, encoded);
java.security.spec.ECParameterSpec params2 =EC5Util.convertSpec(ellipticCurve, params);
java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
return (ECPublicKey) fact.generatePublic(keySpec);
}
答案 2 :(得分:1)
不使用 KeyFactory
的 Thomas 答案的简短变体是:
public static ECPublicKey decodeKey(byte[] encoded) {
ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
ECPublicKeySpec keySpec = new ECPublicKeySpec(params.getCurve().decodePoint(encoded), params);
return new BCECPublicKey("ECDSA", keySpec, BouncyCastleProvider.CONFIGURATION);
}
我假设 encoded
是由 BCECPublicKey.getQ().getEncoded(bool)
获得的,即它是一个字节 0x2-0x4
,后跟 secp256k1
上公共点的一两个仿射坐标。>
答案 3 :(得分:0)
ECUtil已提供
ECPublicKeyParameters bcecPublicKey =(ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(kp.getPublic());
ECPrivateKeyParameters bcecPrivateKey = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(kp.getPrivate());