问题使用生成的密钥和 JKS 签署 JWT

问题描述 投票:0回答:0

我希望实现已接受的答案,即生成我自己的 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 格式?或者是否有任何其他建议能够使用已生成密钥的格式解决我的问题?

非常感谢

java jwt rsa auth0 jks
© www.soinside.com 2019 - 2024. All rights reserved.