Java ECC编码的密钥太大

时间:2018-07-15 10:32:42

标签: java cryptography bouncycastle ecdsa

我是EC加密的新手,对此有些挣扎。 我正在使用Java 8和BouncyCatle提供程序。 我现在的问题是: 当我使用以下代码生成EC-KeyPair时:

    ECGenParameterSpec spec = new ECGenParameterSpec("secp521r1");
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
    kpg.initialize(spec, new SecureRandom());
    return kpg.generateKeyPair();

并尝试获取公共密钥的字节数组以将其发送给其他人,编码密钥的长度为158个字节,格式为X.509。但是我期望X9.62格式和65到66字节之间的密钥大小。 为什么公共密钥这么大,我如何用期望的密钥大小对其进行编码? (我期望密钥大小,因为我期望密钥的长度为521位)

2 个答案:

答案 0 :(得分:3)

ECC公钥在语义上是曲线上的一个点;如果隐含您所命名的曲线,则X9.62格式的点如果经过压缩,则为67个八位位组(Java字节),如果未经压缩,则为133个八位位组,永远没有其他长度。

如果您的意思是java.security.PublicKey.getEncoded()始终是Java所谓的“ X.509”编码,则实际上是X.509中定义的ASN.1结构SubjectPublicKeyInfo(SPKI),可以在以下位置更方便地使用rfc5280 sec 4.1,编码为DER。该曲线上的这种格式的ECC公钥准确地是90或158个八位位组,适用于未压缩或已压缩的状态,并且Java提供程序(至少当前)产生了未压缩的形式(尽管它们可以 parse 压缩) 。

听起来您可能想要X9.62压缩格式,正如我所说的,它是67字节(不是65或66)。如果是这样,您将无法在标准Java API中控制点压缩,但是考虑到BC提供程序创建了关键对象,BouncyCastle实现类确实支持它。 首先将keypair.getPublicKey()投射到(corr) org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey(在1.47为org.bouncycastle.jce.provider.JCEECPublicKey之前),然后getQ()返回一个{ (超载)getEncoded(boolean compressed),它会产生您显然想要的东西。


对于您的另一个但还不是正式的问题,要从编码点(压缩与否)重新创建org.bouncycastle.math.ec.ECPoint对象,您可以根据计数方式有两个或三个选项:

  • 为此曲线和点构造一个ASN.1 / DER编码的SubjectPublicKeyInfo结构(Java称为“ X.509”格式),将其放在PublicKey中,并通过适当的{ {1}}。可以使用标准的SunEC提供程序(假定为j7 +,而不是RedHat限制版本)或BC提供程序。手动构造像SPKI这样的ASN.1编码通常很困难,但在这种情况下还不错。或假设您拥有BC,则可以使用其ASN.1功能

  • 直接调用BC例程以完成EC KeyFactory 对于上述输入所做的操作

创建点然后再使用这三种方式的示例代码:

X509EncodedKeySpec

相关的Loading raw 64-byte long ECDSA public key in Java是未压缩的P256。

答案 1 :(得分:0)

下面的代码(从BouncyCastle修改而来)可以与任何公钥(不仅是secp521r1)一起使用


import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
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.asymmetric.util.KeyUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.math.ec.ECCurve;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.Security;
import java.security.spec.ECParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class TestCompressionEncoded {

    static X962Parameters getDomainParametersFromName(ECParameterSpec ecSpec, boolean compress) {
        X962Parameters x962Param;
        if (ecSpec instanceof ECNamedCurveSpec) {
            ASN1ObjectIdentifier var3 = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
            if (var3 == null) {
                var3 = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
            }

            x962Param = new X962Parameters(var3);
        } else if (ecSpec == null) {
            x962Param = new X962Parameters(DERNull.INSTANCE);
        } else {
            ECCurve var5 = EC5Util.convertCurve(ecSpec.getCurve());
            X9ECParameters var4 = new X9ECParameters(var5, new X9ECPoint(EC5Util.convertPoint(var5, ecSpec.getGenerator()), compress), ecSpec.getOrder(), BigInteger.valueOf((long)ecSpec.getCofactor()), ecSpec.getCurve().getSeed());
            x962Param = new X962Parameters(var4);
        }
        return x962Param;
    }

    static byte[] encodeKeyWithCompression(BCECPublicKey x) throws Exception {
        AlgorithmIdentifier var1 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, getDomainParametersFromName(x.getParams(), true));
        byte[] var2 = x.getQ().getEncoded(true);
        return KeyUtil.getEncodedSubjectPublicKeyInfo(var1, var2);
    }

    public static void main(String...args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        String publicKey = "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELPqrW2JAXKTbjfh9M3X3b85Uje7T0r2gu7qKPmmyagGFnfckwVFpKg10+S2ttJYVUB4q+kPpnJg/YHV5xMnSLA==";
        KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
        BCECPublicKey bcePubKey = (BCECPublicKey) fact.generatePublic(new X509EncodedKeySpec( Base64.getDecoder().decode(publicKey)));

        System.out.println("Uncompressed encoded value: " + publicKey);
        System.out.println("Compressed encoded value: " + Base64.getEncoder().encodeToString(encodeKeyWithCompression(bcePubKey)));
    }
}

输出(对于prime256v1)

Uncompressed encoded value: MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELPqrW2JAXKTbjfh9M3X3b85Uje7T0r2gu7qKPmmyagGFnfckwVFpKg10+S2ttJYVUB4q+kPpnJg/YHV5xMnSLA==
Compressed encoded value: MDYwEAYHKoZIzj0CAQYFK4EEAAoDIgACLPqrW2JAXKTbjfh9M3X3b85Uje7T0r2gu7qKPmmyagE=