【问题标题】:Unable to verify RSA signature using configured PublicKey. Signature length not correct: got 255 but was expecting 256无法使用配置的 PublicKey 验证 RSA 签名。签名长度不正确:得到 255 但预期为 256
【发布时间】:2019-07-08 17:21:05
【问题描述】:

我正在尝试学习如何使用 RSA 公私密钥对来签署 JWT。

我使用openssl 生成了密钥对。

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

openssl rsa -pubout -in private_key.pem -out public_key.pem

我正在设置如下环境变量

export PRIVATE_KEY_DEMO=`cat private_key.pem`

export PUBLIC_KEY_DEMO=`cat public_key.pem`

我有以下创建 PrivateKeyPublicKey 的函数

public PrivateKey getPrivateKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, URISyntaxException {
    String key = env.getProperty("PRIVATE_KEY_DEMO");
    key = key.replace("-----BEGIN PRIVATE KEY-----", "")
         .replace("-----END PRIVATE KEY-----", "")
         .replace("\n", "");

    byte[] keyBytes = Base64.getMimeDecoder().decode(key);

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

private PublicKey getPublicKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, URISyntaxException {

    String key = env.getProperty("PUBLIC_KEY_DEMO");
    key = key.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLICKEY-----", "").replace("\n", "");
    byte[] keyBytes = Base64.getMimeDecoder().decode(key);

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

我能够获得JWT 令牌,但是我无法生成PublicKey 下面是异常堆栈:

java.security.SignatureException: Signature length not correct: got 255 but was expecting 256
    at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:189) ~[na:1.8.0_191]
    at java.security.Signature$Delegate.engineVerify(Signature.java:1222) ~[na:1.8.0_191]
    at java.security.Signature.verify(Signature.java:655) ~[na:1.8.0_191]
    at io.jsonwebtoken.impl.crypto.RsaSignatureValidator.doVerify(RsaSignatureValidator.java:63) ~[jjwt-0.9.1.jar:0.9.1]
    at io.jsonwebtoken.impl.crypto.RsaSignatureValidator.isValid(RsaSignatureValidator.java:47) ~[jjwt-0.9.1.jar:0.9.1]
    at io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator.isValid(DefaultJwtSignatureValidator.java:47) ~[jjwt-0.9.1.jar:0.9.1]
    at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:351) ~[jjwt-0.9.1.jar:0.9.1]

请让我知道我做错了什么以及是否可以以更好的方式实施。


编辑

以下是我用来生成/验证 JWT 的方法。

public String generateToken()
        throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, URISyntaxException {

    PrivateKey privateKey = this.getPrivateKey();

    Date date = new Date();
    date.setTime(date.getTime() + 60 * 60 * 1000);
    String jws;

    jws = Jwts.builder()
                .setAudience("jws-consumers")
                .setIssuer("jws-issuer")
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "RS256")
                .setExpiration(date)
                .setIssuedAt(new Date())
                .setSubject("nish")
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    return jws;
}

public Object validateToken(String token) throws ExpiredJwtException, MalformedJwtException, SignatureException,
        IllegalArgumentException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, URISyntaxException {
    return Jwts.parser()
            .setSigningKey(getPublicKey())
            .parse(token)
            .getBody();
}

这里是生成的 JWT 示例

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJqd3MtY29uc3VtZXJzIiwiaXNzIjoiandzLWlzc3VlciIsImV4cCI6MTU1MDE2NDc0NCwiaWF0IjoxNTUwMTYxMTQ0LCJzdWIiOiJuaXNoIn0.EbNzMIUc4HE6CwIDyURdYF-tE4z7rzM9_GbHpB-TlRror9HRO5bmGgXR7x9HOazmL3cTUPMd46s7QJ9cU_HIJYQu9pYIQzu3V2WZf0zpFevtFxBbGDU_UCM1fbdsgSrd8APSKt_mXbJGdzIA8L7O6gBnpvNowgEuNHYgMiRwL89GrT17c31WwIWSRfRubn-bYU62pd5wm5pMArvGBYi6f6EAoIdYsK-nlhKjOIsxjGigjYAohoooV_xv36_q5_8Iaxppl2yroxCeYCy6Jp9po3bjoLVu3k9vkD_-yUGoXr9e-LCktSS4Ndxq4KCVRI_Cf5Ix_ImcZrqFZLdb4UWGmA

GitHub

【问题讨论】:

  • 由于问题是您传递给verify() 方法的签名太短,因此您应该发布代码。您如何处理sign() 操作和verify() 之间的字节数组?
  • 我正在运行两个项目:我在第一个项目和第二个项目中签署 JWT 令牌,我正在验证它。
  • 这不相关。显示用于解码 JWT 并将签名传递给 verify() 方法的代码。提供一个失败的示例 JWT。
  • 感谢@erickson 的回复。我已经编辑了我的问题。
  • 太棒了。我可以看到示例 JWT 中的签名具有正确的长度,所以问题出在解析和验证方面,而不是生成。您需要显示该代码才能走得更远。

标签: java spring-boot jwt rsa


【解决方案1】:

如果有人遇到同样的问题,我通过关注example 解决了这个问题。

我使用here 显示的命令生成了我的public/private 键。

并更改了以下几行(使用 PRIVATE 而不是 PUBLIC 作为PRIVATE 键)

key = key.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLICKEY-----", "").replace("\n", "");

key = key.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");

它发挥了魔力,并且工作得非常好。

【讨论】:

    猜你喜欢
    • 2019-02-19
    • 2021-09-02
    • 1970-01-01
    • 2018-02-23
    • 1970-01-01
    • 2017-07-30
    • 2019-05-25
    • 2012-01-16
    • 2017-05-08
    相关资源
    最近更新 更多