DEV Community

HarmonyOS
HarmonyOS

Posted on

How to solve the problem that the cloud side cannot decrypt after using the HMACSHA1 algorithm to encrypt ArkTS

Read the original article:How to solve the problem that the cloud side cannot decrypt after using the HMACSHA1 algorithm to encrypt ArkTS

Problem Description

The issue arises when encrypting critical application data on the device side using HMACSHA1 in ArkTS and decrypting it on the Java-based cloud side. The encrypted outputs mismatch, causing cloud validation failures. HMAC is a hash-based message authentication algorithm ensuring data integrity.

Background Knowledge

For security requirements, key application information must be encrypted on the device side and decrypted on the cloud side to verify data validity. The device uses the HMACSHA1 algorithm implemented in ArkTS, but the encrypted data differs from the Java-based cloud implementation, causing cloud validation to fail.

HarmonyOS encrypted data: 75,199,73,191,89,193,243,73,224,228,50,209,32,40,108,126,240,52,137,165.

Java cloud encrypted data: 75,-57,73,-65,89,-63,-13,73,-32,-28,58,-47,32,40,108,126,-16,52,-119,-91.

HMAC (Hash-based Message Authentication Code) is a hash-based message authentication code algorithm.

Troubleshooting Process

(1) Encryption/decryption tests on the HarmonyOS side succeed, confirming HarmonyOS encryption works correctly.

(2) Comparing encrypted data: Values below 128 match (e.g., 75), but values above 128 differ by exactly 256 (e.g., HarmonyOS 199 vs. Java -57 → 199 - (-57) = 256).

(3) Java uses byte (range: -128 to 127). Values >127 overflow during int-to-byte conversion (e.g., 139 becomes -117).

public String generateResponseCode(byte[] challenge) throws GeneralSecurityException, Base32String.DecodingException {
    String secret = "jEWGH2EWEe-pJdZhWPBVDQ0z-cf_fbUjOZGD0ax0BhZw";
    byte[] keyBytes = secret.getBytes();
    final Mac mac = Mac.getInstance("HMACSHA1");
    mac.init(new SecretKeySpec(keyBytes, ""));
    // The encrypted type is byte[], and since we need a numeric password, a conversion algorithm was used to transform byte[] into int.
    byte[] hash = mac.doFinal(challenge);
}
Enter fullscreen mode Exit fullscreen mode

(4) HarmonyOS uses Uint8Array (range: 0 to 255), preserving values like 139 intact.

let macAlgName = 'SH1A';
let mac = cryptoFramework.createMac(macAlgName);
let arr = stringToUint8Array('jEWHGH2EWEe-pJdZhWPBVVDQ0z-cf_fbUjOZGD0ax0BhZw');
let KeyBlob: cryptoFramework.DataBlob = { data: arr };
let symKeyGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
const symKey = await symKeyGenerator.convertKey(KeyBlob);
await mac.init(symKey);
await mac.update({ data: stringToUint8Array(message) });
let macOutput = await mac.doFinal();
Enter fullscreen mode Exit fullscreen mode

Analysis Conclusion

ArkTS Int8Array (range: -128 to 127) matches Java’s byte behavior. Convert doFinal’s Uint8Array output to Int8Array for cloud compatibility.

Solution

Convert the Uint8Array from doFinal to Int8Array:

const uint8Array = new Uint8Array([75,199,73,191,89,193,243,73,224,228,50,209,32,40,108,126,240,52,137,165]);
const int8Array: Int8Array = new Int8Array(uint8Array); // Convert to signed 8-bit array
typescriptCopy Code
const uint8Array = new Uint8Array([75,199,73,191,89,193,243,73,224,228,50,209,32,40,108,126,240,52,137,165]);
const int8Array: Int8Array = new Int8Array(uint8Array); // Convert to signed 8-bit array
Enter fullscreen mode Exit fullscreen mode

Verification Result

(1) When using methods like Mac.doFinal() (returning Uint8Array), convert results to Int8Array if the cloud uses signed bytes.

(2) For any ArkTS method returning Uint8Array, apply similar conversion if values exceed 127 to prevent overflow discrepancies.

Written by Mucahid Kincir

Top comments (0)