从 (RSA) PublicKey 手动创建 JWK

Manually create JWK from (RSA) PublicKey

我需要将 RSA 公钥转换为有效的 JWK。特别是 JWK 的值“n”和“e”是我正在努力解决的问题。在 https://www.rfc-editor.org/rfc/rfc7517#page-25

查看示例 JWK 时,编码似乎不正确

目前我的代码基本上是这样的:

private Map<String, Object> generateJWK(PublicKey publicKey){

    RSAPublicKey rsa = (RSAPublicKey) publicKey;

    Map<String, Object> values = new HashMap<>();

    values.put("kty", rsa.getAlgorithm()); // getAlgorithm() returns kty not algorithm
    values.put("kid", "someuniqueid");
    values.put("n", Base64.encode(rsa.getModulus().toString()));
    values.put("e", Base64.encode(rsa.getPublicExponent().toString()));
    values.put("alg", "RS256");
    values.put("use", "sig");

    return values;
}

但是输出似乎没有正确编码或类似的东西,e 例如看起来像这样:NjU1Mzc=

n 不包括 -_+ 等特殊字符。 :

jMzk1MNT0xTk2NED1xzzgNyQ00IykADzMAM0c0wz0M0MONj2z5TgNzI3yAM0OONYzzMjzwNzDxgAzxDxzMMAjTwNNDYMINMgNQDOEAkIM2jMQzkjUTDUYONNg1A00Tw1Nx4YEzAzjUT1MTNMjDjMM1MNNAjyTMIzxNADDINQANwT5yTDEMjEzNz2z2gOgjDDDNyNDjTzz43ETOYMI35gDjE00MYYM2DzDjDgww53Mwz0ME1NMgOM3MIzYTzMwzOMIQU5MjOzUjMNQNNg50U5NIDNzw2DMMOggNcQQM21TI5NMzDTN5Mj123O33MNNMkyNTNONxMM5wMMc04jTgAUE3MM1zMg4NNMT4MNDMM5yTO2j4jNDEMy1yNANNAzOIEUDzNwzExwTIkNjUjkN54Uz0DT5x0zM51k2MxYkx0zMNzxMkDUDTTQN3gAYODATQDDwMDMjMMcONjxMNTYMT5kgxNkMjNMQU0jzMEwIIMzTzUD4MgYDkDNzcAzN0TN4yNTz11DMxDUjDM2MyDMy4DEINMwT22QxjNNEzNDATy1OM1NNDxYgz5TxDkj3gQ32kIwNNkDO3xczDAENcTMNO0MOjTDwE3g11wNUcgNTwQk30kjjNNzTz4jTj4OOjQNYzMzcMjTQMkyzNNNUQOTOMMkMMMNzwNxDOEkg4xADIT4DNxMz2TENT4yN4z2I2zjyMU3DTOEQN4MIQjNDMU5Y11QkccwMNI0kNzyNjMMN4NMTTNMzMwxMjjDzgAANO1zwjYIEUjM1ADgDNjxTITMNNkIYxzyzzEEDMzDzNjzM4NjNNjc3ITTD0T5jzN=

我假设值 n 和 e 都没有正确编码吗? 我应该如何将 PublicKey 转换为 JWK? (不能使用第 3 方库)

JWK 使用与 base64 略有不同的 base64url 编码。此外,不要对 BigInteger 值使用 toString() 方法。直接获取数据作为字节数组

改变

Base64.encode(rsa.getModulus().toString())
Base64.encode(rsa.getPublicExponent().toString())

Base64.getUrlEncoder().encodeToString(rsa.getModulus().toByteArray())
Base64.getUrlEncoder().encodeToString(rsa.getPublicExponent().toByteArray())
    /***************************SENDER'S END ***********************************/
     
    JwtClaims claims = new JwtClaims();
    claims.setAudience("Admins");
    claims.setExpirationTimeMinutesInTheFuture(10); //10 minutes from now
    claims.setGeneratedJwtId();
    claims.setIssuer("CA");
    claims.setIssuedAtToNow();
    claims.setNotBeforeMinutesInThePast(2);
    claims.setSubject("100bytesAdmin");
    
    claims.setClaim("email", "gmail");
    claims.setClaim("Country", "India");
    List<String> hobbies = Arrays.asList("Blogging", "Playing cards", "Games");
    claims.setStringListClaim("hobbies", hobbies);
    System.out.println(claims.toJson());
    
    //Corresponding public key is hosted in com.one00bytes.jwt.restws.jwk.RestjwkWS
    //which exposes http://localhost:7001/jwkrestws/resources/jwks/sign
    String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCIpUzDyYitMLzTbgUBe4W5+d"
            + "1f+xM2oA+Q2REP3M9arqeudZYhV9+LmGDzBIwnrPn0ReNa2jYIxBw0StECikHSOJiOuw168K1qUpFaH9Lgcg"
            + "QG5+4MQzFCa+6z4CaOMuqRvkK9NCZiMQmMSfrYsGyq7h3A67H53QFlCty226zQNrQTInjdwezv1G+2sUE7f+C"
            + "BUynWKFBbpswNwkdfMZFsooYlbFQ9ORSbTCQOslPBm62gI2P4EyW57InHwAsTSkVYN3pm4iaI8IBygTW7+vGX"
            + "J+oOyhQrufK2OqGSeeAtbBsRINb7qsVvic8cyesKrRui4E5HUx6EmXJO6JhGtKPNAgMBAAECggEAMck4TOVy3"
            + "NczFT2yqTWeJYJ6O+w4teBfi4DrDIKBMiMMiS3ig0eG9U+RkzmG7zXA5FVKXuG+ajc5p3vS50AEd1mTi/1vDe"
            + "n+5QwsVU/e/1PLT9DVFLaujerRT8xNf+XhPTS7EECd84y2U9zofmbZUPXs9UtqzwTM60mn3R/wuPOMQ/uWiQZz"
            + "uq4xwLvNUN10z1VvXvEpcKBrxwTtH3EAAbg92DvMOJp23YscxAeRgtiZHyAOirFAKhyv0O3e/stTXpWD1/RpsU"
            + "iGB9gYa3vBwZHEhnDIwSr+fPDfD4mtb1LFzQdjnODXQaRH/NFojui/AZLsZMiKvLs6ubVv00VeaQKBgQDRXnZS"
            + "ir/r9Qcxx5vXGBRLFaDsxJeBs7PDY/ibaXJnH9iIHSKkmUS0wQuiD8c+gHxuTPqBIbOn7TNvgn1c+z3JS8NpjC"
            + "C6PS/lsK1UZS8HV2R2t0Nd/YxL0TBz92vTfCq5imGjQ7w85lvJPDYJZ3OZ/PYYzcTGTatQZ/52T4/qiwKBgQCn"
            + "FGSBXJ/2HiO21lgOjQ7vUeYDpFqpSMoujs5HwYiJPSeoNw6xgGrT2wCxLZg8GntXr7Ey1KjsFZ4r/GyZwm0UnJ"
            + "9EfkshJM+Oo2ZOnRqjUzd+1S+JJul9jfglJywv49Xr39k0Ztp7usflqLoTrjtk7vK+R7FM/JCFYmYz+CjuBwKB"
            + "gBv/gdsv6tJnBftGMjTlZ3FTBx4ifBBAM73hVJGT3FSmEZLCMqvIQ0PYvPGDIqXdEMa/TJCQLTI7qjEzRgh1IK"
            + "IWm581ufqtzAXvRn6OuWdF7I1jnIKpMWXCJ7SaVbUGWcBOHRh0KmwKciPLBX7kcrUY+t/+RF4wbMRn48N2iExZ"
            + "AoGBAIq+Pm/GEPd6M8Ii4GDE9j/5zH39v2OQFITxBY9EwTLl28auYb84mn1vAXYgHKjcfMxmE0nYmqXhlcWFCl"
            + "HsyFQzc3aXQaA2Rz11pwFlKLez5QOn2J+V9pLSj9uaWfEyy3PiISaIuqnAgzrNEChDqQK6Ak3MjwkVOpXpDmHdk"
            + "2+FAoGAYwsS+SwmVqFiAb01nhkDKvKql/+RsdzKdyrrEobolDtUMswHm6ENteUkLbUZoe9uUhFLMGdGmiIhyEqI"
            + "gwjk9H1p75Sha3rJU4ir5W4Oszn9LI01BjWJ/tMBBCuqas/4BHovPpXPbt63jSU06XY9NOSkz2OYqXOzZgTPyjgOpec=";
    BASE64Decoder b64d = new BASE64Decoder();
    byte[] clear = b64d.decodeBuffer(privateKey);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey priv = fact.generatePrivate(keySpec);
    
    //SIGNING
    JsonWebSignature jws = new JsonWebSignature();
    jws.setKey(priv);
    jws.setPayload(claims.toJson());
    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    String signedJwt = jws.getCompactSerialization();
    System.out.println("Signed ::" + signedJwt);
    
    
    /***************************RECEIVER'S END ***********************************/ 

    //Class com.one00bytes.jwt.restws.jwk.RestjwkWS has to be hosted in a web server 
    //and which exposes a REST endpoint where corresponding public key is served
    //Signing or decryption keys are accessed from URL: http://localhost:7001/jwkrestws/resources/jwks/keys 

    HttpsJwks https_jwks = new HttpsJwks("https://localhost:8081/sso-auth-server/json/jwks1");
    //Can retrieve list of keys
    List<JsonWebKey> jwks_list = https_jwks.getJsonWebKeys();
    BASE64Encoder b64e = new BASE64Encoder();
    for(JsonWebKey jwk : jwks_list ){
        System.out.println(jwk.toJson());
        System.out.println(b64e.encode(jwk.getPublicKey().getEncoded()));
    }
    JwksVerificationKeyResolver jwks_resolver = new JwksVerificationKeyResolver(jwks_list);

    JwtConsumer consumer = new JwtConsumerBuilder()
                            .setExpectedAudience("Admins")
                            .setExpectedIssuer("CA")
                            .setVerificationKeyResolver(jwks_resolver)
                            .setRequireSubject()
                            .build();
    JwtClaims receivedClaims = consumer.processToClaims(signedJwt);
    System.out.println("SUCESS :: JWT Validation" + receivedClaims);

@GetMapping("/json/jwks1") public Map publicKey() 抛出异常 {

    String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiKVMw8mIrTC8024F"
            + "AXuFufndX/sTNqAPkNkRD9zPWq6nrnWWIVffi5hg8wSMJ6z59EXjWto2CMQcNErRAo"
            + "pB0jiYjrsNevCtalKRWh/S4HIEBufuDEMxQmvus+AmjjLqkb5CvTQmYjEJjEn62LBs"
            + "qu4dwOux+d0BZQrcttus0Da0EyJ43cHs79RvtrFBO3/ggVMp1ihQW6bMDcJHXzGRbK"
            + "KGJWxUPTkUm0wkDrJTwZutoCNj+BMlueyJx8ALE0pFWDd6ZuImiPCAcoE1u/rxlyfq"
            + "DsoUK7nytjqhknngLWwbESDW+6rFb4nPHMnrCq0bouBOR1MehJlyTuiYRrSjzQIDAQAB";
    //BASE64Decoder b64d = new BASE64Decoder();
    
    
    byte[] data = Base64.getDecoder().decode(pubKey);
    X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey publicKey = fact.generatePublic(spec);
    
    //Preparing public key for signature purpose
    RsaJsonWebKey sign_jwk = new RsaJsonWebKey((RSAPublicKey) publicKey);
    sign_jwk.setAlgorithm("RSA");
    sign_jwk.setUse("sig");
    sign_jwk.setKeyId("123452");
    
    JsonWebKeySet jwks = new JsonWebKeySet(sign_jwk);
    
    
    JSONParser parser = new JSONParser();
    JSONObject json = null;
    try {
         json = (JSONObject) parser.parse(jwks.toJson());
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    return json;
    
    /* SAMPLE CODE TO GENERATE KEYS AND EXPOSED FOR SIGNING AND ENCRYPTION
      
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(2048);
    KeyPair kp = kpg.genKeyPair();
    RsaJsonWebKey enc_jwk = new RsaJsonWebKey((RSAPublicKey) kp.getPublic());
    enc_jwk.setAlgorithm("RSA");
    enc_jwk.setPrivateKey(kp.getPrivate());
    enc_jwk.setUse("enc");
    enc_jwk.setKeyId("123451");
    
    kp = kpg.genKeyPair();
    RsaJsonWebKey sign_jwk = new RsaJsonWebKey((RSAPublicKey) kp.getPublic());
    sign_jwk.setAlgorithm("RSA");
    sign_jwk.setPrivateKey(kp.getPrivate());
    sign_jwk.setUse("sign");
    sign_jwk.setKeyId("123452");
    
    JsonWebKeySet jwks = new JsonWebKeySet(enc_jwk,sign_jwk);*/
}