如何解码SafetyNet JWS响应?

时间:2017-12-07 08:37:40

标签: android base64 jwt jjwt

我正在调查Google在我的Android应用程序中提供的SafetyNet。

首先,我简单地调用了SafetyNet证明API,Base64对部件进行了解码,如Google提供的示例所示。

rm

我按如下方式提取JWS部分: -

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);
                }
            }
        });

我使用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
解码签名部分时

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

然后我转到使用JWT库来解码令牌。

首先我尝试了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)

我试过的代码是

group: 'com.auth0.android', name: 'jwtdecode', version: '1.1.1'

始终因以下错误而失败

 final JWT jwt = new JWT(jwsResult);

这个异常似乎是由于Auth0库无法解析头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) 格式引起的,这种格式很奇怪,因为JWS规范清楚地表明该值由JSON aray表示: -

4.1.6.  "x5c" (X.509 Certificate Chain) Header

但是,如果我将相同的jws结果字符串复制并粘贴到纯java项目中并使用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. 并使用此代码: -

compile 'com.auth0:java-jwt:3.3.0'

Jws令牌已成功解码。

我的Android应用程序中出现了什么问题,导致auth0 android jwt库停止工作?

然后我在我的Android应用程序中尝试了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); } 库。

执行此代码时: -

'io.jsonwebtoken:jjwt:0.9.0'

它失败了: -

Jwts.parser().parse(jwsResult).getBody();

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

当我按如下方式传递时:

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.parser().setSigningKey<API KEY>.parse(jwsResult).getBody();

解码和使用从SafetyNet获得的Jws结果证明API调用的正确方法是什么?

我在此问题Base64: java.lang.IllegalArgumentException: Illegal character

中发现了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) 问题的修复程序

在解码之前简单地替换jws标记中的字符

java.lang.IllegalArgumentException: bad base-64

1 个答案:

答案 0 :(得分:2)

我发现这个库不仅可以完成它在Android上运行良好的工作。

// 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