我希望实现已接受的答案,即生成我自己的 RSA 密钥对以在单元测试中使用。我编写了以下方法来创建密钥对:
private void generateKeyPair(String targetDir) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey pub = keyPair.getPublic();
PrivateKey pvt = keyPair.getPrivate();
String outFile = targetDir + "testKey";
OutputStream out = new FileOutputStream(outFile + ".key");
out.write(pvt.getEncoded());
out.close();
out = new FileOutputStream(outFile + ".pub");
out.write(pub.getEncoded());
out.close();
}
目前,我正在将其写到项目中的
target
目录中。然后我使用以下代码生成 JWKS 文件给定先前生成的私钥:
private void createJwk(String kid, String use, String targetDir) {
JSONObject json = new JSONObject();
try {
//byte[] keyBytes = Files.readAllBytes(Paths.get("./private_key.der"));
byte[] keyBytes = Files.readAllBytes(Paths.get(targetDir + "testKey.key"));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(spec);
RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) privateKey;
BigInteger mod = rsaPrivateKey.getModulus();
BigInteger pubExp = rsaPrivateKey.getPublicExponent();
BigInteger prvExp = rsaPrivateKey.getPrivateExponent();
BigInteger primeP = rsaPrivateKey.getPrimeP();
BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP();
BigInteger primeQ = rsaPrivateKey.getPrimeQ();
BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ();
BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient();
java.util.Base64.Encoder encoder = java.util.Base64.getUrlEncoder().withoutPadding();
String n = encoder.encodeToString(mod.toByteArray());
String e = encoder.encodeToString(pubExp.toByteArray());
String d = encoder.encodeToString(prvExp.toByteArray());
String p = encoder.encodeToString(primeP.toByteArray());
String q = encoder.encodeToString(primeQ.toByteArray());
String dp = encoder.encodeToString(primeExponentP.toByteArray());
String dq = encoder.encodeToString(primeExponentQ.toByteArray());
String qi = encoder.encodeToString(crtCoefficient.toByteArray());
json.put("n", n);
json.put("e", e);
json.put("d", d);
json.put("p", p);
json.put("q", q);
json.put("dp", dp);
json.put("dq", dq);
json.put("qi", qi);
json.put("alg", "RS256");
json.put("kty", "RSA");
json.put("kid", kid);
json.put("use", use);
try (FileWriter file = new FileWriter(targetDir + "jwks.json")) {
file.write(json.toJSONString());
file.flush();
} catch (IOException exp) {
exp.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
我面临的问题是创建 JWT 并对其进行签名。我正在使用 Auth0 库来实现 JWT:
RSAKeyProvider keyProvider = rsaUtils.getRSAKeyProvider(keyPath);
Date exp;
try {
Algorithm algo = Algorithm.RSA256(keyProvider);
Calendar c = Calendar.getInstance();
c.setTime(issuedAt);
c.add(Calendar.MONTH, ttl);
exp = c.getTime();
String token = JWT.create()
.withIssuer(issuer)
.withAudience(audience)
.withSubject(subject)
.withIssuedAt(issuedAt)
.withExpiresAt(exp)
.withJWTId(jwtId)
.withArrayClaim("products", someProducts)
.sign(algo);
...
}
在上面,
keyPath
的值是指包含先前生成的密钥的target
目录。在深入研究代码时,尝试从 JWKS 检索私钥时失败了,这发生在调用 sign(algo)
时,如上面的代码所示。有问题的代码位于com.auth0.jwt.algorithms.RSAAlgorithm
类:
public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGenerationException {
try {
RSAPrivateKey privateKey = (RSAPrivateKey)this.keyProvider.getPrivateKey(); // here it is null
if (privateKey == null) {
throw new IllegalStateException("The given Private Key is null.");
} else {
return this.crypto.createSignatureFor(this.getDescription(), privateKey, headerBytes, payloadBytes);
}
} catch (SignatureException | InvalidKeyException | IllegalStateException | NoSuchAlgorithmException var4) {
throw new SignatureGenerationException(this, var4);
}
}
很想知道这是否可以通过编程方式解决。让我印象深刻的一件事是生成的密钥可能格式不正确。我在网上看到需要采用 .DER 格式而非 JKS 格式的密钥,以便它们能够从中正确生成 JWKS.json 文件。如果是这样,我怎样才能以编程方式修改原始密钥生成代码以使其成为.DER 格式?或者是否有任何其他建议能够使用已生成密钥的格式解决我的问题?
非常感谢