1

我遇到了谷歌安全网 api 证明响应的问题。即使我向“client.AttestAsync()”方法提供了安全网客户端、nonce 和 apikey,它也不会返回 SafetyNetApiAttestationResponse。下面的代码可能有什么问题?如何获得证明响应以检查 android 设备是在模拟器上运行还是在 xamarin 形式的 root 设备上运行?

protected override void OnCreate(Bundle bundle)
{
    Instance = this;

    TabLayoutResource = Resource.Layout.Tabbar;
    ToolbarResource = Resource.Layout.Toolbar;

    BackgroundAggregator.Init(this);
    base.OnCreate(bundle);

    DependencyService.Register<ToastNotification>();
    ToastNotification.Init(this);

    Rg.Plugins.Popup.Popup.Init(this);
    global::Xamarin.Forms.Forms.Init(this, bundle);

    micService = DependencyService.Resolve<IMicrophoneService>();

    if (GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this, 13000000) == ConnectionResult.Success)
    {
        SafetyNetClient client = Android.Gms.SafetyNet.SafetyNetClass.GetClient(this);
        byte[] nonce = Android.Gms.SafetyNet.Nonce.Generate();

        bool valid = Task.Run(() => RunSafetyNetCheck(client, nonce)).Result;

        if (!valid)
            LoadApplication(new App());
        else
            Toast.MakeText(this, "Failed response validation with Google!", ToastLength.Short).Show();
    }
    else
    {
        Toast.MakeText(this, "Update Google Play services.!", ToastLength.Short).Show();
    }
}

private async Task<bool> RunSafetyNetCheck(SafetyNetClient client, byte[] nonce)
{
    bool valid = false;
    SafetyNetApiAttestationResponse r = await client.AttestAsync(nonce, apiKey);

    if (r != null && !string.IsNullOrEmpty(r.JwsResult))
    {
        attestationResponse = r;
        var decodedResult = r.DecodeJwsResult(nonce);

        string error = null;
        if (VerifyAttestResponse(decodedResult, nonce, out error))
        {
            valid = await attestationResponse.ValidateWithGoogle(apiKey);
        }
        else
        {
            Toast.MakeText(this, "Compatibility Failed: " + error, ToastLength.Long).Show();
        }
    }
    else
    {
        Toast.MakeText(this, "Failed to Check Compatibility", ToastLength.Long).Show();
    }
    return valid;
}

private bool VerifyAttestResponse(string data, byte[] sentNonce, out string errorMessage)
{
    errorMessage = null;
    var json = JsonObject.Parse(data);

    var error = GetValue(json, "error");
    var nonce = GetValue(json, "nonce");
    var timestampMs = GetValue(json, "timestampMs");
    var apkPackageName = GetValue(json, "apkPackageName");
    var apkCertDigestSha256 = GetValue(json, "apkCertificateDigestSha256");
    var apkDigestSha256 = GetValue(json, "apkDigestSha256");
    var ctsProfileMatch = GetValue(json, "ctsProfileMatch") == "true";

    if (!string.IsNullOrEmpty(error))
    {
        errorMessage = "Response Contained an Error: " + error;
        return false;
    }

    var sentNonceStr = Convert.ToBase64String(sentNonce);
    if (!nonce.Equals(sentNonceStr))
    {
        errorMessage = "Nonce's do no match";
        return false;
    }
    if (PackageName != apkPackageName)
    {
        errorMessage = "Package Names do not match";
        return false;
    }
    if (!ctsProfileMatch)
    {
        errorMessage = "CTS Profile was false";
        return false;
    }
    return true;
}

private string GetValue(JsonValue json, string field)
{
    if (!json.ContainsKey(field))
        return string.Empty;

    return json[field].ToString().Trim('"');
}
4

1 回答 1

1

我在这里制作了自己的示例,无法重现您看到的行为。您可以在以下存储库中找到完整代码:https ://github.com/Cheesebaron/Xamarin-SafetyNet

相关部分在我做的活动中:

protected override async void OnCreate(Bundle savedInstanceState)
{
    ...

    var attestation = await safetynetHelper.RequestAttestation();
    ctsProfileMatch.Text = $"{attestation.ctsProfileMatch}";
    basicIntegrity.Text = $"{attestation.basicIntegrity}";
}

在我的安全网助手中,我执行以下操作:

public async Task<(bool ctsProfileMatch, bool basicIntegrity)> RequestAttestation()
{
    SafetyNetClient client = SafetyNetClass.GetClient(context);
    var nonce = Nonce.Generate(24);

    try
    {
        var response = await client.AttestAsync(nonce, attestationApiKey).ConfigureAwait(false);
        var result = response.JwsResult;
        var validSignature = await VerifyAttestationOnline(result).ConfigureAwait(false);
        ...
    }
    catch (Exception)
    {
        // handle errors here
    }

    return (false, false);
}

注意所有的电话都有.ConfigureAwait(false). 我们不需要一直切换上下文。

这可以正常工作并按预期加载证明。

于 2021-08-19T20:26:56.203 回答