Проверка подписи JWT с помощью открытого ключа ECDSA — ошибка расшифровки байтов подписи

#java #jwt #bouncycastle #ecdsa

#java #jwt #bouncycastle #ecdsa

Вопрос:

мне нужна помощь для проверки подписи jwt с помощью открытого ключа ECDSA. Я считываю ключ из файла .pem с помощью bouncy castle и использую jjwt для проверки. Я получаю сообщение об ошибке при проверке подписи.

 Security.addProvider(new BouncyCastleProvider());
String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJtc2kiOiI5NzE1NTA5ODc2NTUiLCJmZWEiOiJzaWdudXAtZGF0YSIsImlzcyI6IkNEUCIsImV4cCI6MTU1NDU2NjMzNiwiaWF0IjoxNTU0MzkzNTM2LCJzaWQiOiIwNDI0MDMwMDg5NzI4MTg3QG5haS5lcGMubW5jMTMwLm1jYzMxMC4zZ3BwbmV0d29yay5vcmcifQ.RwxoGmFd1_dQPeGN-0gnWIW79xXvGHoyJKBbCKajgO75UooceS6tskxwqViEuP1gZD66UE8Bd2L0FaeI2aS_IA";
PemReader pemReader = new PemReader(new FileReader("/publickey.pem"));
X509EncodedKeySpec spec = new X509EncodedKeySpec(pemReader.readPemObject().getContent());
KeyFactory kf = KeyFactory.getInstance("ECDSA","BC");
PublicKey publicKey = kf.generatePublic(spec);
Jws<Claims> claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(jwt);
  

Я получаю исключение подписи с: невозможно проверить подпись эллиптической кривой с помощью настроенного ECPublicKey. ошибка декодирования байтов подписи.

Комментарии:

1. Была ли строка jwt не зашифрована закрытым ключом, который соответствует открытому ключу? Опубликуйте закрытый ключ вместе с исходным токеном jwt, чтобы люди могли проверить, что вы делаете. Возможно, клиентский код / команда также для вашего шифрования.

2. У меня есть только открытый ключ. Что вы имеете в виду под исходным jwt?

3. Если я понимаю, что здесь происходит, ваша строка jwt подписывается клиентом с помощью закрытого ключа. Проверка подписи с помощью открытого ключа, который соответствует закрытому ключу, покажет две вещи: 1) исходный jwt действителен и 2) проверка того, что владелец закрытого ключа отправил запрос. Ошибка указывает на одну из двух вещей: подпись создана неправильно с помощью закрытого ключа или открытый ключ, который у вас есть, не соответствует используемому закрытому ключу. Я не думаю, что здесь достаточно информации, чтобы помочь вам (возможно, я ошибаюсь!)

4. Возможно даже, что клиент не использовал тот же алгоритм эллиптической кривой для подписи…

Ответ №1:

Это также будет работать без упоминания какого-либо алгоритма.

 public boolean isTokenValid(String token) {
    try {
        String certificate = "GET_YOUR_PUBLIC_CERTIFICATE_HERE"; //Either from REST call or reading from a cert file.
        getPublicKeyAndParseToken(token, certificate);
        return true;
    } catch (IOException e) {
        log.error("", e);
    } catch (Exception e) {
        log.error("", e);
        log.error("JWT Not-Verified");
    }
    return false;
}

private void getPublicKeyAndParseToken(String token, String certificate) throws IOException, CertificateException {
    log.debug("Certificate:: "   certificate); //Only for debugging purpose
    InputStream is = new ByteArrayInputStream(certificate.getBytes(StandardCharsets.UTF_8));
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Certificate cert = cf.generateCertificate(is);
    PublicKey publicKey = cert.getPublicKey();

    Jws parsedClaimsJws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    log.debug("Header:: "   parsedClaimsJws.getHeader()); //Only for debugging purpose
    log.debug("Body:: "   parsedClaimsJws.getBody()); //Only for debugging purpose
}
  

Не забудьте использовать версию ‘0.9.x’ библиотеки jjwt. У меня есть зависимость ниже в моем build.gradle:

 compile('io.jsonwebtoken:jjwt:0.9.1')
  

Ответ №2:

Обнаружена проблема, я использовал старую библиотеку jjwt (0.6). Изменен на 0.9 с тем же кодом, и он работает, как ожидалось.

Спасибо