Java 如何制作弹力城堡公钥
我知道EC公钥的曲线名称(Java 如何制作弹力城堡公钥,java,cryptography,bouncycastle,Java,Cryptography,Bouncycastle,我知道EC公钥的曲线名称(secp256k1)和X和Y坐标 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.Sec
secp256k1
)和X
和Y
坐标
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));
}
}
如何从它们中生成org.bouncycastle.jce.interfaces.ECPublicKey
我读过,但是那里的代码使用java.security…
而不是org.bouncycastle…
,ECPublicKey是org.bouncycastle…
中的一个接口,而不是一个可实例化的类。使用Bouncy Castle生成ECPublicKey
这将生成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和PublicKeyParameters
最初我认为需要一个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
的转换。在下面的代码中,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);
}
已提供ECUtil
ECPublicKeyParameters bcecPublicKey =(ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(kp.getPublic());
ECPrivateKeyParameters bcecPrivateKey = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(kp.getPrivate());
Thomas答案的一个较短的变体(不使用
KeyFactory
)是:
公共静态ECPublicKey解码密钥(字节[]编码){
ECNamedCurveParameterSpec params=ECNamedCurveTable.getParameterSpec(“secp256k1”);
ECPublicKeySpec keySpec=新的ECPublicKeySpec(params.getCurve().decodePoint(encoded),params);
返回新的BCECPublicKey(“ECDSA”、keySpec、BouncyCastleProvider.CONFIGURATION);
}
我假设
encoded
是通过BCECPublicKey.getQ().getEncoded(bool)
获得的,也就是说,它是一个字节0x2-0x4
,后跟secp256k1
上公共点的一个或两个仿射坐标,你真的需要使用org.bouncycastle.*类吗?我希望您能够更好地尝试将JCEAPI与BC一起用作提供者。或者,如果您不介意对BC的直接依赖,那么如果您直接使用轻量级(即非JCE)API,事情可能会更简单。@PeterDettman bouncycastle有一个非JCE API吗?我正在使用BC的ECIES——这是否意味着我应该坚持使用JCE API?请不要忘记指出语言/运行时(Java)以及其他标记,如加密。没有那么多人关注。谢谢你的工作。使用bcpkix-jdk15on-152.jar和bcprov-jdk15on-152.jarorg.bouncycastle.jce.ECNameCurveTable
没有方法getByName
或getOID
,因此代码不会编译。org.bouncycastle.crypto.params.ECPublicKeyParameters
不是org.bouncycastle.jce.interfaces.ECPublicKey
,这就是我认为我需要在“ECIESwithAES”javax.crypto.Cipher
上调用的init
。谢谢你的工作-我还没有足够的代表投票支持你的答案,但我会的。我找到了一种更简单的方法来满足我的需要。@MaartenBodewes我接受了你的答案,因为它更普遍地有用。