JWT, как мы можем использовать одинаковые пары ключей RSA для Java и NodeJS - PullRequest
0 голосов
/ 09 ноября 2019

Я пытаюсь понять Jason Web Token с парами открытого ключа и закрытого ключа RSA. Я сгенерировал пары ключей RSA, используя эти сайты - https://travistidwell.com/jsencrypt/demo/, и сохранил их в двух разных файлах - закрытый ключ "my_key" имеет вид

-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgFrSlpibGae4QZjcQp20b9+go22JF9WHJU4TLfdwJbumIgHlukD9
S/W7Dr1j4AXtJ0yJopdnf0bY4294SjjMO4DFHrLDEAB8ZeZkMhfyparYWKHECV5e
szvR6dIHGeDc1CoJolAsPmpO+0qfK4LfkesmLu+diIy9I+B2KJAAka6hAgMBAAEC
gYAlsQuqnYOSJVej1pUW2dEr34CzbpejmAiVVERZUgN20sV+QBaB7hzeCBlf49kO
3JLYoq4FY4BgqJYKpsM2uxteIC8dLJdayyNze1mnPiPW3wLR2bzedOJdjcY0H3Ju
M7lZlk9NVnBI7PNXw4hanifCGY2XPKyrOwrqrMgFsC382QJBAKlKAErRU9N8LZgq
TNAhMTaTPvpZuK4LqqV8RCqPFuNz1tVsO/cjGHfrU3R1pM619K6xCUjvwYvXL0MM
6vm/CKsCQQCJV6/bFuc4L+Uyik0Q+zaRz3fKi5h/AWoN1vmBcXQ01F5GtTAlZDc6
lk/rBk4M69k899I95ReMlIfc68S51P3jAkAp5eLEoaI5iVZPfsicClr/wtmnZGVM
zh5h7quATQHBMX5OPAdrVwhLRbbV7/fmISp5wd8mahBg59UOpzfQr/MZAkAtgC9y
lhPkOXnlVIxTo+ZgSCuXnsfWy9Em5KGkkMG+/tx88GoS+TCS6Flxs5UIEtrVqASv
HMbAfDTGrBVwu2+hAkAnrAHRhFlC8O9zAhoFkWcaYeFu+y1pBcF3pzFfQBpn6uK8
Xd0Ln+eMNaYl6lAECG36jtUvnKLkyfWMHzqdkERj
-----END RSA PRIVATE KEY----- 

открытый ключ "my_key.pub" как

-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgFrSlpibGae4QZjcQp20b9+go22J
F9WHJU4TLfdwJbumIgHlukD9S/W7Dr1j4AXtJ0yJopdnf0bY4294SjjMO4DFHrLD
EAB8ZeZkMhfyparYWKHECV5eszvR6dIHGeDc1CoJolAsPmpO+0qfK4LfkesmLu+d
iIy9I+B2KJAAka6hAgMBAAE=
-----END PUBLIC KEY-----

Когда я использую этот ключ в NodeJS как -

var fs = require('fs');
var JWT = require('jsonwebtoken');

var privateKey = fs.readFileSync('./my_key', 'utf8');
var publicKey = fs.readFileSync('./my_key.pub', 'utf8');

var jwtOptions = {

    issuer : 'Chittaranjan Sardar',
    subject: 'JWT Cross Platforms',
    audience: 'https://github.com/crsardar',
    expiresIn: '5m',
    algorithm: "RS256"
};


let token = JWT.sign({user: 'CRSARDAR'}, privateKey, jwtOptions);
console.log("generated token = " + token);

var verifyResult = JWT.verify(token, publicKey, jwtOptions);
console.log("Verification has passed : " + JSON.stringify(verifyResult));

Работает нормально.

Но когда я пытаюсь использовать в Java,следующим образом -

package com.crsardar.handson.java.springboot.jwt.controller;

import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class JWTJavaWithPublicPrivateKey
{

    public static void main(String[] args)
    {
        System.out.println("generating keys");
        Map<String, Object> rsaKeys = null;

        try
        {
            rsaKeys = getRSAKeys();
        }
        catch (Exception e)
        {

            e.printStackTrace();
        }
        PublicKey publicKey = (PublicKey) rsaKeys.get("public");
        PrivateKey privateKey = (PrivateKey) rsaKeys.get("private");

        System.out.println("generated keys");

        String token = generateToken(privateKey);
        System.out.println("Generated Token:\n" + token);

        verifyToken(token, publicKey);
    }

    public static String generateToken(PrivateKey privateKey)
    {
        String token = null;
        try
        {
            Instant now = Instant.now();
            Instant after = now.plus(Duration.ofMinutes(1));
            Date date = Date.from(after);

            Claims claims = Jwts.claims();
            claims.put("user", "CRSARDAR");
            claims.put("issuer", "Chittaranjan Sardar");
            claims.put("subject", "JWT Cross Platforms");
            claims.put("audience", "https://github.com/crsardar");
            claims.put("created", new Date());

            JwtBuilder jwtBuilder = Jwts.builder();
            jwtBuilder.setClaims(claims);
            jwtBuilder.setExpiration(date);
            jwtBuilder.signWith(SignatureAlgorithm.RS512, privateKey);

            token = jwtBuilder.compact();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return token;
    }

    // verify and get claims using public key

    private static Claims verifyToken(String token, PublicKey publicKey)
    {
        Claims claims;
        try
        {
            JwtParser jwtParser = Jwts.parser();
            jwtParser.setSigningKey(publicKey);
            Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
            claims = claimsJws.getBody();

            System.out.println("verifyToken : issuer = " + claims.get("issuer"));
        }
        catch (Exception e)
        {

            claims = null;
        }
        return claims;
    }

    private static Map<String, Object> getRSAKeys() throws Exception
    {

        Map<String, Object> keys = new HashMap();
        PrivateKey privateKey = getPrivateKey();
        PublicKey publicKey = getPublicKey();
        keys.put("private", privateKey);
        keys.put("public", publicKey);
        return keys;
    }

    private static PrivateKey getPrivateKey() throws Exception
    {
        ClassLoader classLoader = JWTJavaWithPublicPrivateKey.class.getClassLoader();
        URL resource = classLoader.getResource("my_key");
        File file = new File(resource.getFile());
        byte[] keyBytes = Files.readAllBytes(Paths.get(file.toURI()));

        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }

    private static PublicKey getPublicKey() throws Exception
    {
        ClassLoader classLoader = JWTJavaWithPublicPrivateKey.class.getClassLoader();
        URL resource = classLoader.getResource("my_key.pub");
        File file = new File(resource.getFile());
        byte[] keyBytes = Files.readAllBytes(Paths.get(file.toURI()));

        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
    }
}

Это дает мне следующие ошибки -

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
    at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
    at com.crsardar.handson.java.springboot.jwt.controller.JWTJavaWithPublicPrivateKey.getPrivateKey(JWTJavaWithPublicPrivateKey.java:126)
    at com.crsardar.handson.java.springboot.jwt.controller.JWTJavaWithPublicPrivateKey.getRSAKeys(JWTJavaWithPublicPrivateKey.java:110)
    at com.crsardar.handson.java.springboot.jwt.controller.JWTJavaWithPublicPrivateKey.main(JWTJavaWithPublicPrivateKey.java:35)
Caused by: java.security.InvalidKeyException: invalid key format
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:331)
    at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:357)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
    at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
...