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签名算法,其验证依赖特定参数配置,问题通常出在默认参数不匹配上:
- 显式指定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) }
确认密钥对一致性
确保验证用的公钥与jwt.io生成PS512 JWT时使用的私钥完全对应,公钥格式(PEM)无错误或截断。验证BouncyCastle加载优先级
虽然代码中替换了BC提供者,但Android系统可能仍优先使用内置提供者。在签名验证时显式指定BC提供者,确保使用BC的PSS实现。
内容的提问来源于stack exchange,提问作者artkoenig
相关产品推荐
相关产品推荐

