我有一个原始(r,s)格式的ECDSA NIST P-256公钥.似乎没有简单的方法将其加载到实现
java.security.interfaces.EcpublicKey的对象中.
加载64字节公钥的最干净的方法是什么,以便它可以用来检查签名?
解决方法
如果我们使用EcpublicKeySpec这样做,这个答案将会变得很困难.所以让我们做一点:
private static byte[] P256_HEAD = Base64.getDecoder().decode("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE"); public static EcpublicKey convertP256Key(byte[] w) throws InvalidKeySpecException { byte[] encodedKey = new byte[P256_HEAD.length + w.length]; System.arraycopy(P256_HEAD,encodedKey,P256_HEAD.length); System.arraycopy(w,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); }
用法:
EcpublicKey key = convertP256Key(w); System.out.println(key);
我用头脑使用:
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)); }
来自:
String name = "NIST P-256"; int size = 256; byte[] head = createHeadForNamedCurve(name,size); System.out.println(Base64.getEncoder().encodeToString(head));
这样做的想法是创建一个X509编码的密钥,最终以公共点w结尾(包含命名曲线的OID的ASN.1 DER编码和结构开销的字节,以字节04结尾)表示未压缩点).然后我们用w替换最后的“随机”点w,然后再次解码.
Java 7需要EC 7功能和Java 8 for Base 64编码器/解码器,不需要额外的库和东西.请注意,打印时,实际上会将公钥显示为命名曲线,其他解决方案将不会执行.