java 如何使用PKCS#8 PrivateKeyInfo签署JWT

nbnkbykc  于 2023-01-11  发布在  Java
关注(0)|答案(1)|浏览(172)

我不知道如何使用PKCS#8密钥对JWT进行签名。该密钥与以下密钥类似:

-----BEGIN PRIVATE KEY-----
MIGTAgEAMBNGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgtbN7M/7webqa1i3k
3UiwERpWUIoRj6nebM7yRyFphVWgCgYIKoHihj0DAQehRANCAAQl6Z+2bWXLgxJC
J2It6UNYSuxios4A1A6/7/7hNs0y3Yus53q6RD1snvMU5yTBewrRALyDz/8MNADm
eN7dRD41
-----END PRIVATE KEY-----

在此SO答案中解释了该密钥:https://stackoverflow.com/a/54981397/1051180
我需要使用com.nimbusds库。我认为这应该是可行的,但找不到方法。我找到的最接近的答案是:https://stackoverflow.com/a/57437626/1051180
我设法用io.jsonwebtoken库对它进行了签名:

String token = Jwts.builder().signWith(getPrivateKey(), SignatureAlgorithm.ES256).compact();

private static PrivateKey getPrivateKey() {
    PrivateKey key = null;
    try (var pemParser = new PEMParser(privateKeyReader)) {
        var keyInfo = (PrivateKeyInfo) pemParser.readObject();
        key = new JcaPEMKeyConverter().getPrivateKey(keyInfo);      
    }
    return key;
}

背景:我在一个.p8文件中获得了密钥。我使用它来签署JWT,JWT用于在登录Apple期间针对Apple服务器进行身份验证。

zour9fqk

zour9fqk1#

由于我手头没有苹果提供的私钥,我尝试使用以下命令自己生成一个:

openssl ecparam -name prime256v1 -genkey -noout -out key.p8

下面的代码可以使用这样的PEM文件来签署一个令牌:

// load PEM as String from "key.p8" resource
String p8key;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try (InputStream is = cl.getResourceAsStream("key2.p8");
     InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
     BufferedReader r = new BufferedReader(isr)) {
   p8key = r.lines().collect(Collectors.joining("\n"));
}

// Load ECKey from the PEM
ECKey ecJWK = (ECKey) ECKey.parseFromPEMEncodedObjects(p8key);

// Create the EC signer
JWSSigner signer = new ECDSASigner(ecJWK);

// Create the JWS object with a payload
JWSObject jwsObject = new JWSObject(
        new JWSHeader.Builder(JWSAlgorithm.ES256).keyID(ecJWK.getKeyID()).build(),
        new Payload("Elliptic cure"));

// Compute the EC signature
jwsObject.sign(signer);

// Serialize the JWS to compact form
String jwtToken = jwsObject.serialize();

// print the generated token
System.out.println(jwtToken);

显然,苹果提供的PKCS#8文件中没有包含公钥。因此,上述创建ECDSASigner的方法失败,并出现"Missing PEM-encoded public key to construct JWK"异常。下面的代码从此类PEM文件中加载私钥,并创建可用于签署令牌的ECDSASigner示例。

JWSSigner signer = new ECDSASigner(loadECPrivateKey("key.p8"));

private static final Provider BC = new BouncyCastleProvider();

private ECPrivateKey loadECPrivateKey(String resource) throws Exception {
  ClassLoader cl = Thread.currentThread().getContextClassLoader();
  try (InputStream is = cl.getResourceAsStream(resource);
       InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
       BufferedReader r = new BufferedReader(isr)) {

    // strip header and footer, decode from base64, then load the key
    String text = r.lines()
        .filter(s -> s.length() > 0 && !s.startsWith("---"))
        .collect(Collectors.joining());
    byte[] bytes = Base64.getDecoder().decode(text);

    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
    KeyFactory factory = KeyFactory.getInstance("EC", BC);
    return (ECPrivateKey)factory.generatePrivate(spec);
  }
}

相关问题