简体   繁体   中英

create a rsa256 jwt with encode private key by java

I am trying to create an access token for line API below is my private key
{
"alg": "RS256",
"d": "TC4Ij......wqSQIQ",
"dp": "nJg12KiRo...nc02GdK-d8",
"dq": "UzRtJ.....HA70",
"e": "AQAB",
"ext": true,
"key_ops": [
"sign"
],
"kty": "RSA",
"n": "rj_fXZ.....kuNDvOOHimw",
"p": "70k5HA_wTnmAEm.....z4pG79DZ5U",
"qi": "7j7gzQq....NfS7B8HRiC4"
}

I wanted to create a token by the the key with payload and header using the code below

String token = null;
        byte[] privateKey = ResourceUtil.readStr("line_key/privatekey-dev.json", StandardCharsets.UTF_8).getBytes();
        // ペイロードの設定
        Map<String, Object> payloadClaims = new HashMap<>();
        // line channel id
        payloadClaims.put("iss", "XXXXXXX");
        payloadClaims.put("sub", "XXXXXXX");
        payloadClaims.put("aud", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
        payloadClaims.put("exp", new Date(System.currentTimeMillis() + 60 * 30));
        payloadClaims.put("token_exp", 60 * 60 * 24 * 30);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privateKey);
            RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec);
            //Algorithm algorithm = Algorithm.RSA256(null, privKey);
            token = Jwts.builder()
                    .setHeaderParam("typ", "JWT")
                    .setHeaderParam("alg", "RS256")
                    .setHeaderParam("kid", "XXXXXXX").setClaims(payloadClaims)
                    .signWith(SignatureAlgorithm.RS256, privKey) 
                    .compact();
        } catch (Exception e) {
            log.error(e.getMessage());
        }

Since the private the not encoded so I didnt use Base64 to decode it.
But it always showed
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
Even if I use Base64 to decode the private key read from the json file it didnt work.

byte[] keyContentAsBytes = Base64.getMimeDecoder().decode(privateKey);

Can any body tell me how to solve this issue.
Thanks

PS: jwt can be generated by python with

key = RSAAlgorithm.from_jwk(privateKey)
JWT = jwt.encode(payload, key, algorithm="RS256", headers=headers, json_encoder=None)

First, because you are re-inventing the date-arithmetic wheel, your token will only be valid for 1.8 seconds. I doubt that's what you intended. Use higher level APIs from java.time instead of magic numbers and obsolete types from java.util so that your code states the intent clearly.

You don't have a PKCS-#8–encoded key spec, so you can't use PKCS8EncodedKeySpec . For some reason I can't fathom, JWK ignored existing standards like PKCS #8 and invented a new format with a bloated yet still opaque JSON encoding.

If you really need to convert the private key yourself, you can get the parameters from the JWK and create a RSAPrivateCrtKeySpec . I say "really," because I'd be surprised if the library you are using doesn't have some means to load a PrivateKey from a JWK representation.

Here is the mapping between JWK RSA private key members and Java's RSAPrivateCrtKeySpec properties.

JWK member RSAPrivateCrtKeySpec property
n modulus
e publicExponent
d privateExponent
p primeP
q primeQ
dp primeExponentP
dq primeExponentQ
qi crtCoefficient

Base-64 decode each value in the JWK, then create a BigInteger with the resulting magnitude, specifying the sign is positive: new BigInteger(+1, magnitude) . Instantiate a RSAPrivateCrtKeySpec and use that with your KeyFactory in place of the PCKS8EncodedKeySpec .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM