使用ECDSA公钥验证JWT签名 - 解码签名字节时出错

3

我需要一些帮助来使用ECDSA公钥验证JWT签名。 我正在使用Bouncy Castle从.pem文件中读取密钥,并使用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无法验证椭圆曲线签名。解码签名字节时出现错误。


JWT字符串是否未使用与公钥匹配的私钥进行加密?请将私钥与原始JWT令牌一起发布,以便人们可以验证您的操作。也许还需要客户端代码/命令来进行加密。 - Kieveli
我只有公钥。你所说的原始jwt是什么意思? - Spermato
如果我理解这里发生的事情,你的jwt字符串是由客户端通过私钥签名的。通过公钥验证签名,与私钥匹配,将揭示两件事:1)原始jwt有效,2)验证私钥所有者发送请求。错误指示两件事之一:签名未通过私钥正确创建,或您拥有的公钥与使用的私钥不匹配。我认为这里还没有足够的信息来帮助你(也许我错了!) - Kieveli
甚至可能客户端在签名时没有使用相同的椭圆曲线算法... - Kieveli
2个回答

5

不提及任何算法也可以正常工作。

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')

1
发现问题,我使用的是旧版jjwt库(0.6)。更改为0.9版本,使用相同的代码,结果符合预期。
谢谢。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接