2

I am trying to use the Google.Apis.PlayIntegrity.v1 namespace of the Google Client API library for .NET to decode an integrity token, as recommended in the Play Integrity API documentation.

However, it is unclear from the library documentation how to do this. It seems that the decoded token payload is supposed to be returned from a DecodeIntegrityTokenResponse object, yet I can't find any method that returns this type.

I would expect that this type would be returned from DecodeIntegrityToken(DecodeIntegrityTokenRequest, String) but this method actually returns another DecodeIntegrityTokenRequest, which doesn't help at all.

Is anyone successfully using this library to decode the token?

References:

Attempted Code:

String integrityToken = "...token...";

String serviceAccountEmail = "...service account email...";

var certificate = new X509Certificate2("...key.p12...", "...secret...");

ServiceAccountCredential credential = new ServiceAccountCredential(
     new ServiceAccountCredential.Initializer(serviceAccountEmail)
     {
             Scopes = new[] { PlayIntegrityService.Scope.Playintegrity }
     }.FromCertificate(certificate));

// Create the service.
var service = new PlayIntegrityService(new BaseClientService.Initializer()
{
        HttpClientInitializer = credential,
        ApplicationName = "Play Integrity API Sample",
});

DecodeIntegrityTokenRequest request = new     DecodeIntegrityTokenRequest();
request.IntegrityToken = integrityToken;
DecodeIntegrityTokenResponse response = service.V1.DecodeIntegrityToken(request, "...package name...");

Error CS0029 Cannot implicitly convert type 'Google.Apis.PlayIntegrity.v1.V1Resource.DecodeIntegrityTokenRequest' to 'Google.Apis.PlayIntegrity.v1.Data.DecodeIntegrityTokenResponse'

Sarah Elan
  • 2,465
  • 1
  • 23
  • 45

3 Answers3

2

You should rely on your ide to tell you what types these objects are

Your code says that the method DecodeIntegrityToken should return a DecodeIntegrityTokenResponse. You are declaring it as such instead of using var and allowing the compiler to figure it out for you.

DecodeIntegrityTokenResponse response = service.V1.DecodeIntegrityToken(request, "...package name...");

Your problem is that this method actually returns a DecodeIntegrityTokenRequest.

enter image description here

To get a DecodeIntegrityTokenResponse you need to execute the request

var request = service.V1.DecodeIntegrityToken(requestBody, "...package name...");
var result = request.Execute();

Full code cleanup

using System.Security.Cryptography.X509Certificates;
using Google.Apis.Auth.OAuth2;
using Google.Apis.PlayIntegrity.v1;
using Google.Apis.PlayIntegrity.v1.Data;
using Google.Apis.Services;

Console.WriteLine("Hello, World!");


var integrityToken = "...token...";

var serviceAccountEmail = "...service account email...";
var pathToCert = "...key.p12...";
var certPassword = "...secret...";
var packageName = "...package name...";

var certificate = new X509Certificate2(pathToCert, certPassword);

var credential = new ServiceAccountCredential(
    new ServiceAccountCredential.Initializer(serviceAccountEmail)
    {
        Scopes = new[] { PlayIntegrityService.Scope.Playintegrity }
    }.FromCertificate(certificate));

// Create the service.
var service = new PlayIntegrityService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = "Play Integrity API Sample",
});

var requestBody = new DecodeIntegrityTokenRequest
{
    IntegrityToken = integrityToken
};
var request = service.V1.DecodeIntegrityToken(requestBody, packageName);

var result = request.Execute();
Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
0

I have written a sample application to decrypt and verify the play integrity in C# using their own keys offline.

The official documentation doesn't have a C# code sample.

The sample application contains code for both .net framework and dotnet core.

Once you clone the applciation, search for //TODO and update with appropriate values.

CSharp.PlayIntegrity.Decoder

Rudresha Parameshappa
  • 3,826
  • 3
  • 25
  • 39
0

You can decode the attestation statement locally in the following way. I am using Jose.jwt to make the code simpler here.

var decryptionKey = Convert.FromBase64String("<DECRYPTION KEY>");
var verificationKey = Convert.FromBase64String("<VERIFICATION KEY>");
var signedAttestationStatement = "<ATTESTATION STATEMENT>";

var ecDsa = ECDsa.Create();
ecDsa.ImportSubjectPublicKeyInfo(new ReadOnlySpan<byte>(verificationKey), out _);

var decrypted = Jose.JWT.Decode(signedAttestationStatement, decryptionKey);
var payload = Jose.JWT.Decode(decrypted, ecDsa);
Dishan Philips
  • 266
  • 3
  • 2