public static async Task <bool> ValidateWithGoogle(this SafetyNetApiAttestationResponse result, string validationApiKey) { const string url = "https://www.googleapis.com/androidcheck/v1/attestations/verify?key="; var http = new HttpClient(); var jsonReq = "{ \"signedAttestation\": \"" + result.JwsResult + "\" }"; var content = new StringContent(jsonReq, Encoding.Default, "application/json"); var response = await http.PostAsync(url + validationApiKey, content); response.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(); JsonDocument doc = await JsonDocument.ParseAsync(stream); JsonElement root = doc.RootElement; if (root.TryGetProperty("isValidSignature", out var signature)) { return(signature.GetBoolean()); } else { return(false); } }
public static async Task <bool> ValidateWithGoogle(this SafetyNetApiAttestationResponse result, string validationApiKey) { const string url = "https://www.googleapis.com/androidcheck/v1/attestations/verify?key="; var http = new HttpClient(); var jsonReq = "{ \"signedAttestation\": \"" + result.JwsResult + "\" }"; var content = new StringContent(jsonReq, Encoding.Default, "application/json"); var response = await http.PostAsync(url + validationApiKey, content); var data = await response.Content.ReadAsStringAsync(); response.EnsureSuccessStatusCode(); var json = JsonObject.Parse(data); if (json.ContainsKey("isValidSignature")) { return(json ["isValidSignature"].ToString().Trim('"').Equals("true")); } return(false); }
public static string DecodeJwsResult(this SafetyNetApiAttestationResponse result, byte[] originalNonce) { return(JWT.JsonWebToken.Decode(result.JwsResult, originalNonce)); }
protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); buttonCheck = FindViewById <Button> (Resource.Id.buttonCheck); buttonVerify = FindViewById <Button> (Resource.Id.buttonVerify); buttonVerify.Enabled = false; googleApiClient = new GoogleApiClient.Builder(this) .EnableAutoManage(this, this) .AddApi(SafetyNetClass.API) .Build(); buttonCheck.Click += async delegate { var api = SafetyNetClass.GetClient(this); var nonce = Nonce.Generate(); // Should be at least 16 bytes in length. var r = await api.AttestAsync(nonce, DEVELOPERS_CONSOLE_API_KEY); if (r != null && !string.IsNullOrEmpty(r.JwsResult)) { // Store for future verification with google servers attestationResponse = r; // Get the JSON from the JWS result by decoding var decodedResult = r.DecodeJwsResult(nonce); string error = null; // Try and verify the body of the response if (VerifyAttestResponse(decodedResult, nonce, out error)) { Toast.MakeText(this, "Compatibility Passed!", ToastLength.Long).Show(); buttonVerify.Enabled = true; } else { Toast.MakeText(this, "Compatibility Failed: " + error, ToastLength.Long).Show(); } } else { // Error Toast.MakeText(this, "Failed to Check Compatibility", ToastLength.Long).Show(); } }; buttonVerify.Click += async delegate { // Validate the JWS response with Google to ensure it came from them var valid = await attestationResponse.ValidateWithGoogle(DEVELOPERS_CONSOLE_API_KEY); if (valid) { Toast.MakeText(this, "Successfully validated response with Google!", ToastLength.Short).Show(); } else { Toast.MakeText(this, "Failed response validation with Google!", ToastLength.Short).Show(); } }; }