use*_*206 10 java cryptography digital-signature public-key ecdsa
我有一个原始(r,s)格式的ECDSA NIST P-256公钥.似乎没有简单的方法将它加载到实现java.security.interfaces.ECPublicKey的对象中.
加载64字节公钥的最简洁方法是什么,以便可以用来检查签名?
Maa*_*wes 11
如果我们这样做,这个答案将会很艰难ECPublicKeySpec.所以让我们作弊:
private static byte[] P256_HEAD = Base64.getDecoder().decode("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE");
/**
* Converts an uncompressed secp256r1 / P-256 public point to the EC public key it is representing.
* @param w a 64 byte uncompressed EC point consisting of just a 256-bit X and Y
* @return an <code>ECPublicKey</code> that the point represents
*/
public static ECPublicKey generateP256PublicKeyFromFlatW(byte[] w) throws InvalidKeySpecException {
byte[] encodedKey = new byte[P256_HEAD.length + w.length];
System.arraycopy(P256_HEAD, 0, encodedKey, 0, P256_HEAD.length);
System.arraycopy(w, 0, encodedKey, P256_HEAD.length, w.length);
KeyFactory eckf;
try {
eckf = KeyFactory.getInstance("EC");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("EC key factory not present in runtime");
}
X509EncodedKeySpec ecpks = new X509EncodedKeySpec(encodedKey);
return (ECPublicKey) eckf.generatePublic(ecpks);
}
Run Code Online (Sandbox Code Playgroud)
用法:
ECPublicKey key = generateP256PublicKeyFromFlatW(w);
System.out.println(key);
Run Code Online (Sandbox Code Playgroud)
我使用以下方法生成头部:
/**
* Converts an uncompressed secp256r1 / P-256 public point to the EC public key it is representing.
* @param w a 64 byte uncompressed EC point starting with <code>04</code>
* @return an <code>ECPublicKey</code> that the point represents
*/
public static ECPublicKey generateP256PublicKeyFromUncompressedW(byte[] w) throws InvalidKeySpecException {
if (w[0] != 0x04) {
throw new InvalidKeySpecException("w is not an uncompressed key");
}
return generateP256PublicKeyFromFlatW(Arrays.copyOfRange(w, 1, w.length));
}
Run Code Online (Sandbox Code Playgroud)
叫做:
private static byte[] createHeadForNamedCurve(String name, int size)
throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException, IOException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec m = new ECGenParameterSpec(name);
kpg.initialize(m);
KeyPair kp = kpg.generateKeyPair();
byte[] encoded = kp.getPublic().getEncoded();
return Arrays.copyOf(encoded, encoded.length - 2 * (size / Byte.SIZE));
}
Run Code Online (Sandbox Code Playgroud)
这背后的想法是创建一个X509编码密钥,它最终以公共点X509EncodedKeySpec结束(之前的字节包含指定曲线的OID的ASN.1 DER编码和结构开销,以字节w表示结尾)未压缩点).然后我们04用你的结尾替换"随机"点,generateP256PublicKeyFromFlatW我们再次解码它.
EC功能需要Java 7,Base 64编码器/解码器需要Java 8,没有额外的库和东西.请注意,这实际上会在打印时将公钥显示为命名曲线,而其他解决方案则不会这样做.
加载 64 字节公钥以便用于检查签名的最简洁方法是什么?
我能召集的最干净的!也应该与其他曲线一起工作..
注意:仅限于 SunJCE 提供程序或 Android API 26+(可能有更多提供此功能的提供程序,我目前不知道它们。
public static ECPublicKey rawToEncodedECPublicKey(String curveName, byte[] rawBytes) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidParameterSpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
byte[] x = Arrays.copyOfRange(rawBytes, 0, rawBytes.length/2);
byte[] y = Arrays.copyOfRange(rawBytes, rawBytes.length/2, rawBytes.length);
ECPoint w = new ECPoint(new BigInteger(1,x), new BigInteger(1,y));
return (ECPublicKey) kf.generatePublic(new ECPublicKeySpec(w, ecParameterSpecForCurve(curveName)));
}
public static ECParameterSpec ecParameterSpecForCurve(String curveName) throws NoSuchAlgorithmException, InvalidParameterSpecException {
AlgorithmParameters params = AlgorithmParameters.getInstance("EC");
params.init(new ECGenParameterSpec(curveName));
return params.getParameterSpec(ECParameterSpec.class);
}
Run Code Online (Sandbox Code Playgroud)
Java确实使加密技术走了很长的路。
从给定的EC点创建公钥的过程:
ECPoint根据给定的坐标构造一个对象。ECParameterSpec根据曲线信息构造对象。ECPublicKeySpec根据您ECPoint和您的ECParameterSpec对象构造一个对象。KeyFactory.generatePublic()您的ECPublicKeySpec对象以检索PublicKey对象。PublicKey转换ECPublicKey为。下面的例子:
// Setup for P-256 curve params
BigInteger p256_p = new BigInteger("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16);
BigInteger p256_a = new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16);
BigInteger p256_b = new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16);
byte[] p256_seed = {
(byte) 0xc4, (byte) 0x9d, (byte) 0x36, (byte) 0x08,
(byte) 0x86, (byte) 0xe7, (byte) 0x04, (byte) 0x93,
(byte) 0x6a, (byte) 0x66, (byte) 0x78, (byte) 0xe1,
(byte) 0x13, (byte) 0x9d, (byte) 0x26, (byte) 0xb7,
(byte) 0x81, (byte) 0x9f, (byte) 0x7e, (byte) 0x90
};
BigInteger p256_xg = new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16);
BigInteger p256_yg = new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16);
BigInteger p256_n = new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16);
// Construct prime field
ECFieldFp p256_field = new ECFieldFp(p256_p);
// Construct curve from parameters
EllipticCurve p256 = new EllipticCurve(p256_field, p256_a, p256_b, p256_seed);
// Construct base point for curve
ECPoint p256_base = new ECPoint(p256_xg, p256_yg);
// Construct curve parameter specifications object
ECParameterSpec p256spec = new ECParameterSpec(p256, p256_base, p256_n, 1); // Co-factor 1 for prime curves
// ------------------------------------------------------------- //
// Construct EC point from "raw" public key
ECPoint point = new ECPoint(r, s); // r, s is of type BigInteger
// Create a EC public key specification object from point and curve
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, p256spec);
// Retrieve EC KeyFactory
KeyFactory ECFactory = KeyFactory.getInstance("EC");
// Generate public key via KeyFactory
PublicKey pubKey = ECFactory.generatePublic(pubKeySpec);
ECPublicKey ECPubKey = (ECPublicKey) pubKey;
Run Code Online (Sandbox Code Playgroud)
出于性能原因,一次生成ECParameterSpec(也许在静态初始化程序块中)可能会有所帮助。
注意:可能有一种更简单的方法来生成ECParameterSpec对象(例如,通过命名曲线),但是到目前为止,我仅发现ECGenParameterSpec具有此功能。请在评论中让我知道是否有较不痛苦的方法。
为了避免上述麻烦,请在X.509下对EC密钥进行编码,这将完全描述密钥,并使加载更加容易。
在Java中,使用ECPublicKey,您需要做的就是调用ECPublicKey.getEncoded()并将字节数组传递/保存到接下来需要键的位置。然后可以通过以下方式重建X.509编码的密钥:
// Retrieve EC KeyFactory
KeyFactory ECFactory = KeyFactory.getInstance("EC");
// Generate public key via KeyFactory
PublicKey pubKey = ECFactory.generatePublic(new X509EncodedKeySpec(data));
ECPublicKey ECPubKey = (ECPublicKey) pubKey;
Run Code Online (Sandbox Code Playgroud)
其中“数据”是编码的字节数组。
在 Bouncycastle 的帮助下,这对我有用:
ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
ECNamedCurveSpec params = new ECNamedCurveSpec("secp256r1", spec.getCurve(), spec.getG(), spec.getN());
ECPoint publicPoint = ECPointUtil.decodePoint(params.getCurve(), publicKeyByteArray);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(publicPoint, params);
PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6105 次 |
| 最近记录: |