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);
}
(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();
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
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.
Top comments (0)