首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何解码SafetyNet JWS响应?

如何解码SafetyNet JWS响应?
EN

Stack Overflow用户
提问于 2017-12-07 16:37:40
回答 1查看 2.8K关注 0票数 1

我正在调查谷歌在我的安卓应用程序中提供的SafetyNet。

首先,我简单地调用了Google,然后Base64按照SafetyNet提供的示例对这些部分进行了解码。

代码语言:javascript
复制
SafetyNet.getClient(this).attest(NONCE, <API KEY>)
        .addOnSuccessListener(this, new OnSuccessListener<SafetyNetApi.AttestationResponse>() {
            @Override
            public void onSuccess(final SafetyNetApi.AttestationResponse attestationResponse) {
                initialDataExtraction(attestationResponse.getJwsResult());
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull final Exception exception) {
                if (exception instanceof ApiException) {
                    final ApiException apiException = (ApiException) exception;
                    Log.e(TAG, "onFailure: " + apiException.getMessage() + " " + apiException.getStatusCode());
                } else {
                    Log.e(TAG, "Error: ", exception);
                }
            }
        });

我提取JWS部分如下:

代码语言:javascript
复制
private byte[] initialDataExtraction(final String jwsResult) {

    final String[] jwsResultParts = jwsResult.split("[.]");
    if (jwsResultParts.length == 3) {
        final byte[] header = Base64.decode(jwsResultParts[0], Base64.NO_WRAP);
        final byte[] data = Base64.decode(jwsResultParts[1], Base64.NO_WRAP);
        final byte[] signature = Base64.decode(jwsResultParts[2], Base64.NO_WRAP);

        Log.d(TAG, "initialDataExtraction: header = " + new String(header, UTF_8));
        Log.d(TAG, "initialDataExtraction: data = " + new String(data, UTF_8));
        Log.d(TAG, "initialDataExtraction: signature = " + new String(signature, UTF_8));

        return data;
    } else {
        Log.e(TAG, "initialDataExtraction: Failure: Illegal JWS signature format. The JWS consists of " + jwsResultParts.length + " parts instead of 3.");
        return null;
    }
}

我使用android.util.Base64对这些部分进行解码,大多数情况下解码都可以正常完成。

偶尔我会收到这样的异常:

代码语言:javascript
复制
java.lang.IllegalArgumentException: bad base-64
 at android.util.Base64.decode(Base64.java:161)
 at android.util.Base64.decode(Base64.java:136)
 at android.util.Base64.decode(Base64.java:118)

当解码签名部分时。

在解码以查看此间歇性错误时,我做错了什么?

然后,我开始使用JWT库来解码令牌。

首先,我尝试了group: 'com.auth0.android', name: 'jwtdecode', version: '1.1.1'

我尝试的代码是

代码语言:javascript
复制
 final JWT jwt = new JWT(jwsResult);

它总是失败,并显示以下错误

代码语言:javascript
复制
com.auth0.android.jwt.DecodeException: The token's payload had an invalid JSON format.
at com.auth0.android.jwt.JWT.parseJson(JWT.java:235)
at com.auth0.android.jwt.JWT.decode(JWT.java:203)
at com.auth0.android.jwt.JWT.<init>(JWT.java:40)
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 23 path $.
at com.google.gson.Gson.fromJson(Gson.java:899)
at com.google.gson.Gson.fromJson(Gson.java:852)
at com.google.gson.Gson.fromJson(Gson.java:801)

这个异常似乎是由于Auth0库无法解析标头4.1.6. "x5c" (X.509 Certificate Chain) Header格式引起的,这很奇怪,因为JWS Spec清楚地说明了值是由JSON aray表示的:-

代码语言:javascript
复制
The "x5c" (X.509 Certificate Chain) Header Parameter contains the
   X.509 public key certificate or certificate chain [RFC5280]
   corresponding to the key used to digitally sign the JWS.  The
   certificate or certificate chain is represented as a JSON array of
   certificate value strings. 

但是,如果我将相同的jws结果字符串复制并粘贴到一个纯java项目中,并使用compile 'com.auth0:java-jwt:3.3.0'并使用以下代码:

代码语言:javascript
复制
String token = "<JWS TOKEN>";
        try {
            final DecodedJWT jwt = JWT.decode(token);
            System.out.println("Header = " + jwt.getHeader());
            System.out.println("Payload = " + jwt.getPayload());
            System.out.println("Signature = " + jwt.getSignature());
                } catch (JWTDecodeException exception){
           throw new RuntimeException(exception);
        }

成功解码Jws令牌。

我在我的安卓应用程序中做错了什么,导致auth0 Android jwt库无法正常工作?

然后,我在我的Android应用程序中尝试了'io.jsonwebtoken:jjwt:0.9.0'库。

当我执行这段代码时:

代码语言:javascript
复制
Jwts.parser().parse(jwsResult).getBody();

它会失败,错误为:-

代码语言:javascript
复制
java.lang.IllegalArgumentException: A signing key must be specified if the specified JWT is digitally signed.
 at io.jsonwebtoken.lang.Assert.notNull(Assert.java:85)
 at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:331)

我需要传递给Jwts的签名密钥是什么?我唯一的密钥是保存在Google API控制台中的API密钥,这是我应该使用的密钥吗?

当我按如下方式传递它时:

代码语言:javascript
复制
Jwts.parser().setSigningKey<API KEY>.parse(jwsResult).getBody();

此操作失败,出现以下错误:-

代码语言:javascript
复制
java.lang.IllegalArgumentException: Key bytes can only be specified for HMAC signatures. Please specify a PublicKey or PrivateKey instance.
at io.jsonwebtoken.lang.Assert.isTrue(Assert.java:38)
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:324)

解码和使用从SafetyNet attest API调用收到的Jws结果的正确方法是什么?

我从这个问题Base64: java.lang.IllegalArgumentException: Illegal character中找到了java.lang.IllegalArgumentException: bad base-64问题的修复

在解码之前,只需替换jws token中的字符

代码语言:javascript
复制
token.replace('-', '+').replace('_', '/')
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-08 16:44:38

我发现这个库不仅做得很好,而且在Android上也运行得很好。

代码语言:javascript
复制
// https://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt
implementation group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '5.1'


    try {
        final JWSObject jwsObject = JWSObject.parse(jwsResult);
        System.out.println("header = " + jwsObject.getHeader());
        System.out.println("header = " + jwsObject.getHeader().getX509CertChain());
        System.out.println("payload = " + jwsObject.getPayload().toJSONObject());
        System.out.println("signature = " + jwsObject.getSignature());
        System.out.println("signature = " + jwsObject.getSignature().decodeToString());
    } catch (ParseException e) {
        e.printStackTrace();
    }

这里提供了一些很好的例子:

https://connect2id.com/products/nimbus-jose-jwt/examples

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47690811

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档