You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端PS512算法JWT验证失败问题求助

PS512算法JWT验证失败排查

问题背景

使用jwt.io生成RS512和PS512算法的默认JWT,在Android应用中通过公钥验证时,RS512验证正常,但PS512抛出签名不匹配异常:

io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

当前配置与代码

Gradle依赖

libs.versions.toml配置:

jsonwebtoken-api = { group = "io.jsonwebtoken", name = "jjwt-api", version = "0.12.6" }
jsonwebtoken-impl = { group = "io.jsonwebtoken", name = "jjwt-impl", version = "0.12.6" }
jsonwebtoken-json = { group = "io.jsonwebtoken", name = "jjwt-jackson", version = "0.12.6" }
bouncycastle-prov = { group = "org.bouncycastle", name = "bcprov-jdk15to18", version = "1.78.1" }
bouncycastle-bcpkix = { group = "org.bouncycastle", name = "bcpkix-jdk15to18", version = "1.78.1" }

模块build.gradle配置:

implementation(libs.jsonwebtoken.api)
runtimeOnly(libs.jsonwebtoken.impl)
runtimeOnly(libs.jsonwebtoken.json) {
    exclude(group = "org.json", module = "json")
}
implementation(libs.bouncycastle.prov)
implementation(libs.bouncycastle.bcpkix)

安全提供者替换

companion object {
    init {
        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
        Security.addProvider(BouncyCastleProvider())
    }
}

公钥读取

val publicKey:String = "..."
private fun stringToPublicKey(): PublicKey {
    val parser = PEMParser(StringReader(publicKey))
    val converter = JcaPEMKeyConverter()
    val publicKeyInfo: SubjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(parser.readObject())
    return (converter.getPublicKey(publicKeyInfo) as RSAPublicKey)
}

验证代码

val jwtPS512 = "..."
try {
    val parser = Jwts.parser().verifyWith(stringToPublicKey()).build()
    val test = parser.parse(jwtPS512)
    Log.i("", "$test")
} catch (e: Throwable) {
    Log.e("", "", e)
}

排查与解决方案

PS512属于RSA-PSS签名算法,其验证依赖特定参数配置,问题通常出在默认参数不匹配上:

  1. 显式指定PS512算法及匹配参数
    JJWT默认的PS512验证参数可能与jwt.io生成时的参数不一致(jwt.io默认使用与哈希长度相同的盐长度:SHA-512对应64字节盐)。需要在解析器中明确指定算法并配置匹配的PSS参数:
val jwtPS512 = "..."
try {
    val publicKey = stringToPublicKey()
    // 配置符合jwt.io默认设置的PSS参数
    val pssSpec = PSSParameterSpec(
        "SHA-512",
        "MGF1",
        MGF1ParameterSpec.SHA512,
        64, // 盐长度与SHA-512哈希长度一致(512位=64字节)
        1 // TrailerField值,jwt.io默认使用1
    )
    val validator = JcaSignatureValidator(SignatureAlgorithm.PS512, publicKey)
        .setParameter(pssSpec)
        .setProvider(BouncyCastleProvider.PROVIDER_NAME)
    
    val parser = Jwts.parser()
        .setSignatureValidator(validator)
        .build()
    
    val test = parser.parse(jwtPS512)
    Log.i("", "$test")
} catch (e: Throwable) {
    Log.e("", "", e)
}
  1. 确认密钥对一致性
    确保验证用的公钥与jwt.io生成PS512 JWT时使用的私钥完全对应,公钥格式(PEM)无错误或截断。

  2. 验证BouncyCastle加载优先级
    虽然代码中替换了BC提供者,但Android系统可能仍优先使用内置提供者。在签名验证时显式指定BC提供者,确保使用BC的PSS实现。

内容的提问来源于stack exchange,提问作者artkoenig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:13:11