ECC公钥在语义上是曲线上的一个点;如果隐含了您命名的曲线,则X9.62格式的点如果经过压缩,则为67个八位位组(Java字节),如果为未压缩,则为133个八位位组,从没有其他长度。
如果您的意思
java.security.PublicKey.getEnpred()始终是Java所谓的“
X.509”编码,则实际上是
SubjectPublicKeyInfoX.509中定义的ASN.1结构(SPKI),并且更方便地在rfc5280 sec
4.1中使用DER编码。对于这种格式,曲线上的ECC公钥准确地是90或158个八位位组,用于未压缩或已压缩,并且Java提供程序(至少当前)生成未压缩的形式(尽管它们可以
解析 压缩的形式)。
听起来您可能想要X9.62压缩格式,正如我所说的,它是67字节(不是65或66)。如果是这样,您将无法在标准Java
API中控制点压缩,但是考虑到BC提供程序创建了关键对象,BouncyCastle实现类确实支持它。首先将
keypair.getPublicKey()其
强制转换 为
(corr)
org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey(在1.47
was之前
org.bouncycastle.jce.provider.JCEECPublicKey),然后
getQ()返回一个
org.bouncycastle.math.ec.ECPoint包含(重载)的
getEnpred(booleancompressed),它会产生您显然想要的内容。
对于您的另一个但还不是正式的问题,
PublicKey要从编码点(压缩与否)重新创建对象,您可以根据计算方式有两个或三个选项:
为此曲线和点构造一个ASN.1 / DER编码的SubjectPublicKeyInfo结构(Java称为“ X.509”格式),将其放入
X509EnpredKeySpec
并通过适当的运行KeyFactory
。可以使用标准的SunEC提供程序(假定为j7 +,而不是RedHat限制版本)或BC提供程序。通常很难手动构造像SPKI这样的ASN.1编码,但在这种情况下还不错。或如果您拥有BC,则可以使用其ASN.1功能直接致电BC程序做什么欧共体的KeyFactory 将 针对上述输入做
创建点然后使用这三种方式的示例代码:
// as needed in addition to standard java.security and javax.xml import org.bouncycastle.asn1.ASN1EncodableVector;import org.bouncycastle.asn1.DERBitString;import org.bouncycastle.asn1.DERSequence;import org.bouncycastle.asn1.sec.SECObjectIdentifiers;import org.bouncycastle.asn1.x509.AlgorithmIdentifier;import org.bouncycastle.asn1.x9.X962Parameters;import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;import org.bouncycastle.crypto.params.ECPublicKeyParameters;import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.math.ec.ECCurve;import org.bouncycastle.math.ec.ECPoint; KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); kpg.initialize(new ECGenParameterSpec("secp521r1")); org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey ku = (org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey)kpg.generateKeyPair().getPublic(); byte[] enpredpoint = ku.getQ().getEnpred(true); { // construct SPKI by hand, this curve only byte[] hdr = DatatypeConverter.parseHexBinary("3058301006072a8648ce3d020106052b81040023034400"); // could also write out byte[] hdr = {0x30,0x58,0x30,0x10... but items with 0x80 set need casts if( 0x44 -1 != enpredpoint.length ) throw new Exception ("BAD COMPRESSED POINT FOR secp521r1!"); byte[] spki = Arrays.copyOf(hdr,90); System.arraycopy(enpredpoint,0, spki,0x17, 0x43); PublicKey k2 = KeyFactory.getInstance("EC" ).generatePublic(new X509EnpredKeySpec(spki)); Signature.getInstance("ECDSA").initVerify(k2); // sanity check } { // construct SPKI with BC AlgorithmIdentifier algid = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey,SECObjectIdentifiers.secp521r1); ASN1EncodableVector vec = new ASN1EncodableVector(); vec.add(algid); vec.add(new DERBitString(enpredpoint)); byte[] spki = new DERSequence(vec).getEnpred(); PublicKey k2 = KeyFactory.getInstance("EC" ).generatePublic(new X509EnpredKeySpec(spki)); Signature.getInstance("ECDSA").initVerify(k2); // sanity check } { // call BC directly ProviderConfiguration configuration = BouncyCastleProvider.CONFIGURATION; X962Parameters params = X962Parameters.getInstance(org.bouncycastle.asn1.sec.SECObjectIdentifiers.secp521r1); ECCurve curve = EC5Util.getCurve(configuration, params); ECPoint point = curve.deprePoint(enpredpoint).normalize(); ECPublicKeyParameters kparams = new ECPublicKeyParameters(point, ECUtil.getDomainParameters(configuration, params)); PublicKey k2 = new BCECPublicKey ("EC", kparams, configuration); Signature.getInstance("ECDSA").initVerify(k2); // sanity check }相关信息在Java中加载未经压缩的P256
原始64字节长的ECDSA公共密钥。



