Java 7 требуется для функциональности EC и Java 8 для кодировщика / декодера Base 64, никаких дополнительных библиотек - просто Java. Обратите внимание, что при распечатке открытый ключ будет отображаться в виде именованной кривой, чего не будет делать большинство других решений. Если у вас установлена последняя версия среды выполнения, этот другой ответ более понятен.
Этот ответ будет трудным, если мы сделаем это с помощью ECPublicKeySpec
. Так что давайте немного обманем и вместо этого используем X509EncodedKeySpec
:
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);
}
Использование:
ECPublicKey key = generateP256PublicKeyFromFlatW(w);
System.out.println(key);
Идея заключается в создании временного ключа в кодировке X509, который благополучно заканчивается публичной точкой w
в конце. Байты до этого содержат кодировку ASN.1 DER OID названной кривой и структурные служебные данные, заканчивающиеся байтом 04
, указывающим несжатую точку. Вот пример, что к структуре внешнего вида, используя значение 1 и 2 для 32-байтовых X и Ю.
32-байтовые значения X и Y несжатых значений точек удалены для создания заголовка. Это работает только потому, что размер точки статический - ее положение в конце определяется только размером кривой.
Теперь все, что требуется от функции generateP256PublicKeyFromFlatW
, - это добавить полученную общедоступную точку w
в заголовок и пропустить ее через декодер, реализованный для X509EncodedKeySpec
.
В приведенном выше коде используется необработанная несжатая общедоступная точка EC - всего 32 байта X и Y - без индикатора несжатой точки со значением 04
. Конечно, легко поддерживать и 65-байтовые сжатые точки:
/**
* 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));
}
Наконец, я сгенерировал постоянное значение заголовка P256_HEAD
в базе 64, используя:
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));
person
Maarten Bodewes
schedule
27.05.2015