gpt4 book ai didi

Java ECC 编码 key 太大

转载 作者:行者123 更新时间:2023-11-30 07:45:45 24 4
gpt4 key购买 nike

我是 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();

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

最佳答案

ECC 公钥在语义上是曲线上的一个点;如果您指定的曲线是隐含的,则 X9.62 格式的点要么是 67 个八位位组(Java 字节)(如果压缩),要么是 133 个八位位组(如果未压缩),绝不会是任何其他长度。

如果您的意思是 java.security.PublicKey.getEncoded() ,它始终采用 Java 所谓的“X.509”编码,实际上是 ASN.1 结构 SubjectPublicKeyInfo (SPKI) 在 X.509 中定义,更方便地在 rfc5280 sec 4.1 中提供,编码为 DER。对于未压缩或压缩的情况,该曲线上的 ECC 公钥准确地说是 90 或 158 个八位字节,并且 Java 提供者(至少目前)生成未压缩的形式(尽管他们可以解析压缩的形式) .

听起来您可能需要 X9.62 压缩格式,正如我所说,它是 67 字节(不是 65 或 66)。如果是这样,您无法在标准 Java API 中控制点压缩,但 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(boolean compressed)它会产生你显然想要的东西。


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

  • 为此曲线和点构造一个 ASN.1/DER 编码的SubjectPublicKeyInfo 结构(Java 称之为“X.509”格式),将其放入 X509EncodedKeySpec 中,然后运行它一个合适的KeyFactory。可以使用标准 SunEC 提供程序(假设为 j7+,而不是 RedHat 版本)或 BC 提供程序。手动构建像 SPKI 这样的 ASN.1 编码通常很困难,但在这种特定情况下也不错;或者如果您有 BC,您可以使用其 ASN.1 功能

  • 直接调用 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
}

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

关于Java ECC 编码 key 太大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51347513/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com