A nonce value must meet the following requirements:
- Contain 16 to 66 bytes.
- (Recommended) Be randomly generated by the server for each request.
|
|
An app calls the SysIntegrity API to check the system integrity of a device. If the device is insecure, the app will take appropriate measures.
To call the SysIntegrity API, perform the following steps:
A nonce value must meet the following requirements:
Safety Detect provides two SysIntegrity APIs which require different parameters. However, both the nonce and APP ID parameters are required for the two APIs. As for the sysIntegrity(SysIntegrityRequest sysIntegrityRequest) API, you also need to pass the signature verification mode to SysIntegrityRequest. The signature verification mode is the same as that specified by alg in the header of the obtained JWS-format response.
You can perform the following operations to obtain the app ID:
private void invokeSysIntegrity() { SafetyDetectClient mClient = SafetyDetect.getClient(getActivity()); // TODO(developer): Change the value of nonce to a random value generated by the server. byte[] nonce = Random value generated by the server String alg = "PS256" SysIntegrityRequest sysintegrityrequest = new SysIntegrityRequest(); sysintegrityrequest.setAppId("3*******"); sysintegrityrequest.setNonce(nonce); sysintegrityrequest.setAlg(alg); Task task = mClient.sysIntegrity(sysintegrityrequest); task.addOnSuccessListener(new OnSuccessListener<SysIntegrityResp>() { @Override public void onSuccess(SysIntegrityResp response) { // Indicates that communication with the service was successful. // Use response.getResult() to obtain the result data. String jwsStr = response.getResult(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // An error occurred during communication with the service. if (e instanceof ApiException) { // An error with the HMS API contains some // additional details. ApiException apiException = (ApiException) e; // You can retrieve the status code using // the apiException.getStatusCode() method. Log.e(TAG, "Error: " + SafetyDetectStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " + apiException.getMessage()); } else { // A different, unknown type of error occurred. Log.e(TAG, "ERROR:" + e.getMessage()); } } }); }
private fun invokeSysIntegrity() { // TODO(developer): Change the value of nonce to a random value generated by the server. val nonce = Random value generated by the server // TODO (developer): Change your app ID. You can obtain your app ID in AppGallery Connect. val alg = "PS256" val sysIntegrityRequest = SysIntegrityRequest() sysIntegrityRequest.appId = APP_ID sysIntegrityRequest.nonce = nonce sysIntegrityRequest.alg = alg SafetyDetect.getClient(activity) .sysIntegrity(sysIntegrityRequest) .addOnSuccessListener { response -> // Indicates communication with the service was successful. // Use response.getResult() to obtain the result data. val jwsStr = response.result // Process the result data here. val jwsSplit = jwsStr.split(".").toTypedArray() val jwsPayloadStr = jwsSplit[1] val payloadDetail = String(Base64.decode(jwsPayloadStr.toByteArray(StandardCharsets.UTF_8), Base64.URL_SAFE), StandardCharsets.UTF_8) try { val jsonObject = JSONObject(payloadDetail) val basicIntegrity = jsonObject.getBoolean("basicIntegrity") fg_button_sys_integrity_go.setBackgroundResource(if (basicIntegrity) R.drawable.btn_round_green else R.drawable.btn_round_red) fg_button_sys_integrity_go.setText(R.string.rerun) val isBasicIntegrity = basicIntegrity.toString() val basicIntegrityResult = "Basic Integrity: $isBasicIntegrity" fg_payloadBasicIntegrity.text = basicIntegrityResult if (!basicIntegrity) { val advice = "Advice: " + jsonObject.getString("advice") fg_payloadAdvice.text = advice } } catch (e: JSONException) { val errorMsg = e.message Log.e(TAG, errorMsg ?: "unknown error") } } .addOnFailureListener { e -> // There was an error communicating with the service. val errorMsg: String? errorMsg = if (e is ApiException) { // An error with the HMS API contains some additional details. val apiException = e as ApiException SafetyDetectStatusCodes.getStatusCodeString(apiException.statusCode) + ": " + apiException.message // You can use the apiException.getStatusCode() method to obtain the status code. } else { // An unknown type of error has occurred. e.message } Log.e(TAG, errorMsg) Toast.makeText(activity?.applicationContext, errorMsg, Toast.LENGTH_SHORT).show() fg_button_sys_integrity_go.setBackgroundResource(R.drawable.btn_round_yellow) fg_button_sys_integrity_go.setText(R.string.rerun) } }
HMS Core (APK) sends the check result to the Huawei server to verify the certificate, and returns the result to you through the SysIntegrityResp object. You can use the getResult method of the object to obtain the response in JSON Web Signature (JWS) format.
{ "advice": "RESTORE_TO_FACTORY_ROM", "apkCertificateDigestSha256": ["gwpz0q/WtjtJZZK5lTXl74fI/8QAKGLAhdhlznKkLhQ="], "apkDigestSha256": "nBrInk2DLVQrgcQ1DXYnIUIMnjJ+mVo0lwUicF7OzJM=", "apkPackageName": "com.huawei.hms.safetydetectsample", "appId": "1*******", "basicIntegrity": false, "detail": ["root", "unlocked"], "nonce": "UjJScmEyNGZWbTV4YTJNZw==", "timestampMs": 1612683290520 }
If the value of the basicIntegrity field in the check result is false, the detail field will list the specific reason why the value false is returned. For details, please refer to getResult. You can decide whether to remind users of the risks based on your security requirements.
For details about the fields, please refer to API Reference.
For details about the verification logic, please refer to SysIntegrity in Client Sample Code.