当前位置: 首页 > 知识库问答 >
问题:

Java ECC 编码密钥太大

岑炯
2023-03-14

我是EC加密的新手,对它有一些困难。我正在使用Java8和BouncyCatle提供程序。我现在的问题是:当我使用以下代码生成EC密钥对时:

    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个答案

阎裕
2023-03-14

下面的代码(从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=

许高峻
2023-03-14

ECC公钥在语义上是曲线上的一个点;如果隐含了您命名的曲线,则 X9.62 格式的点在压缩时为 67 个八位字节(Java 字节),如果未压缩,则为 133 个八位字节,从不包含任何其他长度。

如果您的意思是<code>java.security.PublicKey。getEncoded()这始终是Java所谓的“X.509”编码,实际上是ASN。1.X.509中定义的结构<code>SubjectPublicKeyInfo</code>(SPKI),rfc5280第4.1节中更方便地提供,编码为DER。这种格式的曲线上的ECC公钥是90或158个八位字节,对于未压缩或压缩,Java提供程序(至少目前)生成未压缩形式(尽管它们可以解析压缩)。

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

对于您的其他但不是(还没有?)官方问题,要从编码点(压缩或未压缩)重新创建PublicKey对象,您有两个或三个选项,具体取决于您的计数方式:

>

  • 构建ASN。1/DER编码的SubjectPublicKeyInfo结构(Java称之为“X.509”格式)用于该曲线和点,将其放入<code>X509EncodedKeySpec

    直接调用BC例程,以执行EC 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[] encodedpoint = ku.getQ().getEncoded(true/*compressed*/);
        
        { // 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 /*hdr[0x15]*/ -1 != encodedpoint.length ) throw new Exception ("BAD COMPRESSED POINT FOR secp521r1!");
            byte[] spki = Arrays.copyOf(hdr,90); System.arraycopy(encodedpoint,0, spki,0x17, 0x43);
            PublicKey k2 = KeyFactory.getInstance("EC" /*,provider?*/).generatePublic(new X509EncodedKeySpec(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(encodedpoint));
            byte[] spki = new DERSequence(vec).getEncoded();
            PublicKey k2 = KeyFactory.getInstance("EC" /*,provider*/).generatePublic(new X509EncodedKeySpec(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);
            /*ECParameterSpec ecSpec = EC5Util.convertToSpec(params, curve);*/
            ECPoint point = curve.decodePoint(encodedpoint).normalize();
            ECPublicKeyParameters kparams = new ECPublicKeyParameters(point, ECUtil.getDomainParameters(configuration, params));
            PublicKey k2 = new BCECPublicKey ("EC"/* or "ECDH" etc*/, kparams, configuration);
            Signature.getInstance("ECDSA").initVerify(k2); // sanity check
        }
    

    在Java中加载原始的64字节长的ECDSA公钥,该公钥用于P256未压缩。

  •  类似资料:
    • 问题内容: 我是EC加密的新手,对此有些挣扎。我正在使用Java 8和BouncyCatle提供程序。现在的问题是:当我使用以下代码生成EC-KeyPair时: 并尝试获取公用密钥的字节数组以将其发送给其他人,编码密钥的长度为158个字节,格式为X.509。但是我期望X9.62格式和65到66字节之间的密钥大小。为什么公钥这么大,我如何用期望的密钥大小对其进行编码?(我期望密钥的大小,因为我期望密

    • 我用过这个命令 生成密钥库。它工作正常,但从我读到的内容来看,这个命令还应该提示您输入密钥密码(而不是存储密码)?我从来没有收到过这样的提示。我能跑 查看密钥库的内容。钥匙似乎就在那里。。。正确的别名在那里。在哪里获取/设置特定别名的密码? 我有一个key.properties在Android目录 在build.gradle我有: 当我试图生成一个发布版本时,我得到了 我想它可能与keyPassw

    • 问题内容: 我正在通过SSL连接到数据库Google Cloud SQL。我使用codeigniter 3.0进行了此操作,尽管mysqli驱动程序进行了一些修改以允许此功能。 几个月来一直运作良好。但是,它 刚刚 开始返回此警告: 我认为这是主要问题,但我不知道那是什么意思。我已经搜索了Diffie- Hellman密钥交换以及“密钥太小”消息,但是运气不高。 这是否表明服务器上的密钥已被篡改?

    • 问题内容: 我无法在上创建索引。 MySQL: 问题答案:

    • 问题内容: 当我执行以下命令时: 我收到此错误消息: 有关column1和column2的信息: 我认为只需要21个字节,而只需要501个字节。因此,总字节数是522,少于767。那么为什么收到错误消息? 问题答案: 在MySQL版本5.6(及更早版本)中,InnoDB表的前缀限制为767个字节。MyISAM表的长度为1,000字节。在MySQL 5.7及更高版本中,此限制已增加到3072字节。

    • 问题内容: 我目前有一个密钥库,其中只有我应该知道的特定密码。现在,我需要将对该密钥库的访问权授予其他人,因此我想: 1)更改密码,以便我可以与他人共享该密码并让他们签名 2)创建一个不同的密码并允许他们使用它进行签名。 这可能吗?以及-如果是-怎么样? 问题答案: 密钥库只有一个密码。您可以使用keytool进行更改: 要更改密钥的密码: