The hash-based message authentication code (HMAC) algorithm employs a designated digest algorithm and takes a shared key and message as inputs to generate a fixed-length message authentication code (MAC) to check the integrity of packets. The HMAC adds key input on the basis of the message digest algorithm to ensure information correctness.
During the HMAC operation, you can pass in all the data at a time or pass in data by segment. The same data will produce the same result no matter how the data is passed. Use the appropriate method based on the data size.
The following provides examples of HMAC operations with different data passing methods.
Call cryptoFramework.createMac with the MD algorithm SHA256 to create a Mac instance.
Call cryptoFramework.createSymKeyGenerator and SymKeyGenerator.convertKey to generate a symmetric key (SymKey) using HMAC.
For details, see Converting Binary Data into a Symmetric Key.
Call Mac.init to initialize the Mac instance using the shared symmetric key (SymKey).
Call Mac.update to pass in the data. The amount of data to be passed in by a single Mac.update() call is not limited.
Call Mac.doFinal to generate a MAC.
Call Mac.getMacLength to obtain the length of the MAC, in bytes.
Example: Pass in the full data to generate a MAC using await.
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
async function genSymKeyByData(symKeyData: Uint8Array) {
let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
let hmacGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
let symKey = await hmacGenerator.convertKey(symKeyBlob);
console.info('convertKey result: success.');
return symKey;
}
async function doHmac() {
try {
// Encode the string into a Uint8Array in UTF-8, using a fixed 128-bit key, that is, 16 bytes.
let keyData = new Uint8Array(buffer.from('12345678abcdefgh', 'utf-8').buffer);
let key = await genSymKeyByData(keyData);
let macAlgName = 'SHA256'; // Digest algorithm name.
let message = 'hmacTestMessage'; // Data to be processed by HMAC.
let mac = cryptoFramework.createMac(macAlgName);
await mac.init(key);
// When the data volume is small, you can call update only once to pass all the data. The API does not limit the input parameter length.
await mac.update({ data: new Uint8Array(buffer.from(message, 'utf-8').buffer) });
let macResult = await mac.doFinal();
console.info('HMAC result: ' + macResult.data);
let macLen = mac.getMacLength();
console.info('HMAC len: ' + macLen);
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`call failed: errCode: ${e.code}, errMsg: ${e.message}`);
}
} Example: Pass in the full data to generate a MAC using synchronous APIs.
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
function genSymKeyByData(symKeyData: Uint8Array) {
let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
let hmacGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
let symKey = hmacGenerator.convertKeySync(symKeyBlob);
console.info('[Sync]convertKey result: success.');
return symKey;
}
function doHmacBySync() {
try {
// Encode the string into a Uint8Array in UTF-8, using a fixed 128-bit key, that is, 16 bytes.
let keyData = new Uint8Array(buffer.from('12345678abcdefgh', 'utf-8').buffer);
let key = genSymKeyByData(keyData);
let macAlgName = 'SHA256'; // Digest algorithm name
let message = 'hmacTestMessage'; // Data to be processed by HMAC
let mac = cryptoFramework.createMac(macAlgName);
mac.initSync(key);
// When the data volume is small, you can call update only once to pass all the data. The API does not limit the length of the input parameter.
mac.updateSync({ data: new Uint8Array(buffer.from(message, 'utf-8').buffer) });
let macResult = mac.doFinalSync();
console.info('[Sync]HMAC result: ' + macResult.data);
let macLen = mac.getMacLength();
console.info('HMAC len: ' + macLen);
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`call failed: errCode: ${e.code}, errMsg: ${e.message}`);
}
} Call cryptoFramework.createMac with the MD algorithm SHA256 to create a Mac instance.
Call cryptoFramework.createSymKeyGenerator and SymKeyGenerator.convertKey to generate a symmetric key (SymKey) using HMAC.
For details, see Converting Binary Data into a Symmetric Key.
Call Mac.init to initialize the Mac instance using the shared symmetric key (SymKey).
Call Mac.update multiple times to pass in 20 bytes each time.
Call Mac.doFinal to generate a MAC.
Call Mac.getMacLength to obtain the length of the MAC, in bytes.
Example: Pass in data by segment to generate a MAC using await.
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
async function genSymKeyByData(symKeyData: Uint8Array) {
let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
let hmacGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
let symKey = await hmacGenerator.convertKey(symKeyBlob);
console.info('convertKey result: success.');
return symKey;
}
async function doLoopHmac() {
try {
// Encode the string into a Uint8Array using UTF-8, and use a fixed 128-bit key, that is, 16 bytes.
let keyData = new Uint8Array(buffer.from('12345678abcdefgh', 'utf-8').buffer);
let key = await genSymKeyByData(keyData);
let macAlgName = 'SHA256'; // Digest algorithm name.
let mac = cryptoFramework.createMac(macAlgName);
// Assume the message is 43 bytes in total, and it is also 43 bytes after UTF-8 decoding.
let messageText = 'aaaaa.....bbbbb.....ccccc.....ddddd.....eee';
let messageData = new Uint8Array(buffer.from(messageText, 'utf-8').buffer);
let updateLength = 20; // Assume the update is segmented in units of 20 bytes; there is no actual requirement for this.
await mac.init(key);
for (let i = 0; i < messageData.length; i += updateLength) {
let updateMessage = messageData.subarray(i, i + updateLength);
let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
await mac.update(updateMessageBlob);
}
let macOutput = await mac.doFinal();
console.info('HMAC result: ' + macOutput.data);
let macLen = mac.getMacLength();
console.info('HMAC len: ' + macLen);
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`call failed: errCode: ${e.code}, errMsg: ${e.message}`);
}
} Example: Pass in data by segment to generate a MAC using synchronous APIs.
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
function genSymKeyByData(symKeyData: Uint8Array) {
let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
let hmacGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
let symKey = hmacGenerator.convertKeySync(symKeyBlob);
console.info('[Sync]convertKey result: success.');
return symKey;
}
function doLoopHmacBySync() {
try {
// Encode the string into a Uint8Array using UTF-8, and use a fixed 128-bit key, that is, 16 bytes.
let keyData = new Uint8Array(buffer.from('12345678abcdefgh', 'utf-8').buffer);
let key = genSymKeyByData(keyData);
let macAlgName = 'SHA256'; // Digest algorithm name.
let mac = cryptoFramework.createMac(macAlgName);
// Assume the message is 43 bytes in total, and it is also 43 bytes after UTF-8 decoding.
let messageText = 'aaaaa.....bbbbb.....ccccc.....ddddd.....eee';
let messageData = new Uint8Array(buffer.from(messageText, 'utf-8').buffer);
let updateLength = 20; // Assume the update is segmented in units of 20 bytes; there is no actual requirement for this.
mac.initSync(key);
for (let i = 0; i < messageData.length; i += updateLength) {
let updateMessage = messageData.subarray(i, i + updateLength);
let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
mac.updateSync(updateMessageBlob);
}
let macOutput = mac.doFinalSync();
console.info('[Sync]HMAC result: ' + macOutput.data);
let macLen = mac.getMacLength();
console.info('HMAC len: ' + macLen);
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`call failed: errCode: ${e.code}, errMsg: ${e.message}`);
}
} Call cryptoFramework.createMac with the MAC algorithm set to HMAC and MD algorithm set to SHA256 to create a Mac instance.
Call cryptoFramework.createSymKeyGenerator and SymKeyGenerator.convertKey to generate a symmetric key (SymKey) using HMAC.
For details, see Converting Binary Data into a Symmetric Key.
Call Mac.init to initialize the Mac instance using the shared symmetric key (SymKey).
Call Mac.update to pass in the data. The amount of data to be passed in by a single Mac.update() call is not limited.
Call Mac.doFinal to generate a MAC.
Call Mac.getMacLength to obtain the length of the MAC, in bytes.
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
async function genSymKeyByData(symKeyData: Uint8Array) {
let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
let hmacGenerator = cryptoFramework.createSymKeyGenerator('HMAC');
let symKey = await hmacGenerator.convertKey(symKeyBlob);
console.info('convertKey result: success.');
return symKey;
}
async function doHmac() {
try {
// Encode the string into a Uint8Array in UTF-8, using a fixed 128-bit key, that is, 16 bytes.
let keyData = new Uint8Array(buffer.from('12345678abcdefgh', 'utf-8').buffer);
let key = await genSymKeyByData(keyData);
let spec: cryptoFramework.HmacSpec = {
algName: 'HMAC',
mdName: 'SHA256',
};
let message = 'hmacTestMessage'; // Data to be processed by HMAC.
let mac = cryptoFramework.createMac(spec);
await mac.init(key);
// When the data volume is small, you can call update only once to pass all the data. The API does not limit the parameter length.
await mac.update({ data: new Uint8Array(buffer.from(message, 'utf-8').buffer) });
let macResult = await mac.doFinal();
console.info('HMAC result: ' + macResult.data);
let macLen = mac.getMacLength();
console.info('HMAC len: ' + macLen);
} catch (err) {
let e: BusinessError = err as BusinessError;
console.error(`call failed: errCode: ${e.code}, errMsg: ${e.message}`);
}
}