在 Java 中打印椭圆曲线 ASCII-Armor 键
Printing Elliptic Curve ASCII-Armor keys in Java
我正在尝试使用 ES256_P-256 椭圆曲线密钥读取 JSON Web 密钥 (JWK),并在 Java 中将它们打印为装甲 ASCII。理想情况下,我想在没有任何第三方库的情况下执行此操作,但我在使用 bouncycastle 和本机 Java 库时遇到了问题。不确定我做错了什么。这是 JWK:
{
"kty": "EC",
"d": "STNVdgaTJ7Lc7dpFShEPFVgYusUKzbYmb6492BknZFI",
"use": "sig",
"crv": "P-256",
"kid": "1234",
"x": "TrMA2sZ9CaNS3TWZRpjlLg1GB-AdAItozKSJe-83yHg",
"y": "oeBo61jYweaEbIiMLF8r-ndDuQG73WmL2sGyqqUt8b4",
"alg": "ES256"
}
和代码
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import org.junit.Test;
public class KeyGenerator {
@Test
public void testGenerateECKey() {
try {
final Decoder decoder = Base64.getUrlDecoder();
final Encoder encoder = Base64.getUrlEncoder();
final byte[] secret = decoder
.decode("STNVdgaTJ7Lc7dpFShEPFVgYusUKzbYmb6492BknZFI");
final byte[] x_coord = decoder
.decode("TrMA2sZ9CaNS3TWZRpjlLg1GB-AdAItozKSJe-83yHg");
final byte[] y_coord = decoder
.decode("oeBo61jYweaEbIiMLF8r-ndDuQG73WmL2sGyqqUt8b4");
final BigInteger d = new BigInteger(1, secret);
final BigInteger x = new BigInteger(1, x_coord);
final BigInteger y = new BigInteger(1, y_coord);
final AlgorithmParameters parameters = AlgorithmParameters
.getInstance("EC");
parameters.init(new ECGenParameterSpec("secp256r1"));
final ECParameterSpec ecParameterSpec = parameters
.getParameterSpec(ECParameterSpec.class);
final KeyFactory keyFactory = KeyFactory.getInstance("EC");
final ECPoint ecPoint = new ECPoint(x, y);
final ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint,
ecParameterSpec);
final ECPublicKey publicKey = (ECPublicKey) keyFactory
.generatePublic(keySpec);
final ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d,
ecParameterSpec);
final ECPrivateKey privateKey = (ECPrivateKey) keyFactory
.generatePrivate(ecPrivateKeySpec);
final KeyPair keyPair = new KeyPair(publicKey, privateKey);
// final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
// keyPair.getPublic().getEncoded());
// final PKCS8EncodedKeySpec pKCS8EncodedKeySpec = new
// PKCS8EncodedKeySpec(
// keyPair.getPrivate().getEncoded());
System.out.println("-----BEGIN PUBLIC KEY-----");
System.out.println(keyPair.getPublic().getEncoded());
System.out.println("-----END PUBLIC KEY-----");
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(keyPair.getPrivate().getEncoded());
System.out.println("-----END PRIVATE KEY-----");
} catch (final NoSuchAlgorithmException | InvalidKeySpecException
| InvalidParameterSpecException ex) {
ex.printStackTrace();
}
}
}
正在输出:
-----BEGIN PUBLIC KEY-----
[B@34340fab
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
[B@2aafb23c
-----END PRIVATE KEY-----
为什么 PEM 密钥这么小?我做错了什么?
[B@34340fab
是字节数组 toString
方法的结果,您在尝试打印数组时隐式调用该方法。
PrivateKey::getEncoded
和 PublicKey::getEncoded
将 return byte
数组表示这些键的 DER 格式。如果你想获得 PEM 格式,只需使用 base64 对结果字节数组进行编码并添加 PEM header/footer :
String publicKeyBase64 = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKeyBase64 = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
System.out.println("-----BEGIN PUBLIC KEY-----");
System.out.println(publicKeyBase64);
System.out.println("-----END PUBLIC KEY-----");
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(privateKeyBase64);
System.out.println("-----END PRIVATE KEY-----");
我正在尝试使用 ES256_P-256 椭圆曲线密钥读取 JSON Web 密钥 (JWK),并在 Java 中将它们打印为装甲 ASCII。理想情况下,我想在没有任何第三方库的情况下执行此操作,但我在使用 bouncycastle 和本机 Java 库时遇到了问题。不确定我做错了什么。这是 JWK:
{
"kty": "EC",
"d": "STNVdgaTJ7Lc7dpFShEPFVgYusUKzbYmb6492BknZFI",
"use": "sig",
"crv": "P-256",
"kid": "1234",
"x": "TrMA2sZ9CaNS3TWZRpjlLg1GB-AdAItozKSJe-83yHg",
"y": "oeBo61jYweaEbIiMLF8r-ndDuQG73WmL2sGyqqUt8b4",
"alg": "ES256"
}
和代码
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import org.junit.Test;
public class KeyGenerator {
@Test
public void testGenerateECKey() {
try {
final Decoder decoder = Base64.getUrlDecoder();
final Encoder encoder = Base64.getUrlEncoder();
final byte[] secret = decoder
.decode("STNVdgaTJ7Lc7dpFShEPFVgYusUKzbYmb6492BknZFI");
final byte[] x_coord = decoder
.decode("TrMA2sZ9CaNS3TWZRpjlLg1GB-AdAItozKSJe-83yHg");
final byte[] y_coord = decoder
.decode("oeBo61jYweaEbIiMLF8r-ndDuQG73WmL2sGyqqUt8b4");
final BigInteger d = new BigInteger(1, secret);
final BigInteger x = new BigInteger(1, x_coord);
final BigInteger y = new BigInteger(1, y_coord);
final AlgorithmParameters parameters = AlgorithmParameters
.getInstance("EC");
parameters.init(new ECGenParameterSpec("secp256r1"));
final ECParameterSpec ecParameterSpec = parameters
.getParameterSpec(ECParameterSpec.class);
final KeyFactory keyFactory = KeyFactory.getInstance("EC");
final ECPoint ecPoint = new ECPoint(x, y);
final ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint,
ecParameterSpec);
final ECPublicKey publicKey = (ECPublicKey) keyFactory
.generatePublic(keySpec);
final ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d,
ecParameterSpec);
final ECPrivateKey privateKey = (ECPrivateKey) keyFactory
.generatePrivate(ecPrivateKeySpec);
final KeyPair keyPair = new KeyPair(publicKey, privateKey);
// final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
// keyPair.getPublic().getEncoded());
// final PKCS8EncodedKeySpec pKCS8EncodedKeySpec = new
// PKCS8EncodedKeySpec(
// keyPair.getPrivate().getEncoded());
System.out.println("-----BEGIN PUBLIC KEY-----");
System.out.println(keyPair.getPublic().getEncoded());
System.out.println("-----END PUBLIC KEY-----");
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(keyPair.getPrivate().getEncoded());
System.out.println("-----END PRIVATE KEY-----");
} catch (final NoSuchAlgorithmException | InvalidKeySpecException
| InvalidParameterSpecException ex) {
ex.printStackTrace();
}
}
}
正在输出:
-----BEGIN PUBLIC KEY-----
[B@34340fab
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
[B@2aafb23c
-----END PRIVATE KEY-----
为什么 PEM 密钥这么小?我做错了什么?
[B@34340fab
是字节数组 toString
方法的结果,您在尝试打印数组时隐式调用该方法。
PrivateKey::getEncoded
和 PublicKey::getEncoded
将 return byte
数组表示这些键的 DER 格式。如果你想获得 PEM 格式,只需使用 base64 对结果字节数组进行编码并添加 PEM header/footer :
String publicKeyBase64 = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKeyBase64 = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
System.out.println("-----BEGIN PUBLIC KEY-----");
System.out.println(publicKeyBase64);
System.out.println("-----END PUBLIC KEY-----");
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out.println(privateKeyBase64);
System.out.println("-----END PRIVATE KEY-----");