1# 消息认证码计算CMAC(ArkTS) 2 3<!--Kit: Crypto Architecture Kit--> 4<!--Subsystem: Security--> 5<!--Owner: @zxz--3--> 6<!--Designer: @lanming--> 7<!--Tester: @PAFT--> 8<!--Adviser: @zengyawen--> 9 10CMAC通过使用分组密码(如AES)和一个密钥生成认证码,确保消息在传输过程中未被篡改。 11 12## 开发步骤 13 14在调用update接口传入数据时,可以[一次性传入所有数据](#cmac一次性传入数据),也可以把数据人工分段,然后[分段update](#分段cmac)。对于同一段数据而言,是否分段,计算结果没有差异。对于数据量较大的数据,开发者可以根据实际需求选择是否分段传入。 15 16下面分别提供两种方式的示例代码。 17 18### CMAC(一次性传入数据) 19 201. 调用[cryptoFramework.createMac](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatemac18),指定消息认证码算法为CMAC,指定对称算法为AES128,生成消息认证码实例(Mac)。 21 222. 调用[cryptoFramework.createSymKeyGenerator](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatesymkeygenerator)和[SymKeyGenerator.convertKey](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#convertkey-1),生成密钥算法为AES256的对称密钥(SymKey)。 23 生成对称密钥的详细开发指导,请参考[指定二进制数据生成对称密钥](crypto-convert-binary-data-to-sym-key.md)。 24 253. 调用[Mac.init](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#init-6),指定共享对称密钥(SymKey),初始化Mac对象。 26 274. 调用[Mac.update](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#update-8),传入自定义消息,进行消息认证码计算。单次update的长度没有限制。 28 295. 调用[Mac.doFinal](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#dofinal-2),获取Mac计算结果。 30 316. 调用[Mac.getMacLength](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#getmaclength),获取Mac长度,单位为字节。 32 33- 以使用await方式一次性传入数据,获取消息认证码计算结果为例: 34 35 ```ts 36 import { cryptoFramework } from '@kit.CryptoArchitectureKit'; 37 import { buffer } from '@kit.ArkTS'; 38 39 async function genSymKeyByData(symKeyData: Uint8Array) { 40 let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; 41 let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128'); 42 let symKey = await aesGenerator.convertKey(symKeyBlob); 43 console.info('convertKey success'); 44 return symKey; 45 } 46 async function doCmac() { 47 // 把字符串按utf-8解码为Uint8Array,使用固定的128位的密钥,即16字节。 48 let keyData = new Uint8Array(buffer.from("12345678abcdefgh", 'utf-8').buffer); 49 let key = await genSymKeyByData(keyData); 50 let spec: cryptoFramework.CmacSpec = { 51 algName: "CMAC", 52 cipherName: "AES128", 53 }; 54 let message = 'cmacTestMessage'; // 待进行CMAC的数据。 55 let mac = cryptoFramework.createMac(spec); 56 await mac.init(key); 57 // 数据量不多时,可以一次性更新,将所有数据传入,接口没有入参长度限制。 58 await mac.update({ data: new Uint8Array(buffer.from(message, 'utf-8').buffer) }); 59 let macResult = await mac.doFinal(); 60 console.info('CMAC result:' + macResult.data); 61 let macLen = mac.getMacLength(); 62 console.info('CMAC len:' + macLen); 63 } 64 ``` 65 66- 以使用同步方式一次性传入数据,获取消息认证码计算结果为例: 67 68 ```ts 69 import { cryptoFramework } from '@kit.CryptoArchitectureKit'; 70 import { buffer } from '@kit.ArkTS'; 71 72 function genSymKeyByData(symKeyData: Uint8Array) { 73 let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; 74 let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128'); 75 let symKey = aesGenerator.convertKeySync(symKeyBlob); 76 console.info('[Sync]convertKey success'); 77 return symKey; 78 } 79 function doCmacBySync() { 80 // 把字符串按utf-8解码为Uint8Array,使用固定的128位的密钥,即16字节。 81 let keyData = new Uint8Array(buffer.from("12345678abcdefgh", 'utf-8').buffer); 82 let key = genSymKeyByData(keyData); 83 let spec: cryptoFramework.CmacSpec = { 84 algName: "CMAC", 85 cipherName: "AES128", 86 }; 87 let message = 'cmacTestMessage'; // 待进行CMAC的数据。 88 let mac = cryptoFramework.createMac(spec); 89 mac.initSync(key); 90 // 数据量不大时,可以一次性更新,将所有数据传入,接口没有入参长度限制。 91 mac.updateSync({ data: new Uint8Array(buffer.from(message, 'utf-8').buffer) }); 92 let macResult = mac.doFinalSync(); 93 console.info('[Sync]CMAC result:' + macResult.data); 94 let macLen = mac.getMacLength(); 95 console.info('CMAC len:' + macLen); 96 } 97 ``` 98 99### 分段CMAC 100 1011. 调用[cryptoFramework.createMac](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatemac18),指定消息认证码算法CMAC,对称算法AES256,生成消息认证码实例(Mac)。 102 1032. 调用[cryptoFramework.createSymKeyGenerator](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatesymkeygenerator)、[SymKeyGenerator.convertKey](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#convertkey-1),生成密钥算法为AES256的对称密钥(SymKey)。 104 生成对称密钥的详细开发指导,请参考[指定二进制数据生成对称密钥](crypto-convert-binary-data-to-sym-key.md)。 105 1063. 调用[Mac.init](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#init-7),指定共享对称密钥(SymKey),初始化Mac对象。 107 1084. 传入自定义消息,设置每次传入数据量为20字节,多次调用[Mac.update](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#update-9),计算消息认证码。 109 1105. 调用[Mac.doFinal](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#dofinal-3),获取Mac计算结果。 111 1126. 调用[Mac.getMacLength](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#getmaclength),获取Mac消息认证码的长度,单位为字节。 113 114- 以使用await方式分段传入数据,获取消息认证码计算结果为例。 115 116 ```ts 117 import { cryptoFramework } from '@kit.CryptoArchitectureKit'; 118 import { buffer } from '@kit.ArkTS'; 119 120 async function genSymKeyByData(symKeyData: Uint8Array) { 121 let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; 122 let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128'); 123 let symKey = await aesGenerator.convertKey(symKeyBlob); 124 console.info('convertKey success'); 125 return symKey; 126 } 127 async function doLoopCmac() { 128 // 把字符串按utf-8解码为Uint8Array,使用固定的128位的密钥,即16字节。 129 let keyData = new Uint8Array(buffer.from("12345678abcdefgh", 'utf-8').buffer); 130 let key = await genSymKeyByData(keyData); 131 let spec: cryptoFramework.CmacSpec = { 132 algName: "CMAC", 133 cipherName: "AES128", 134 }; 135 let mac = cryptoFramework.createMac(spec); 136 // 假设消息共43字节,根据UTF-8解码后,仍是43字节。 137 let messageText = "aaaaa......bbbbb......ccccc......ddddd......eee"; 138 let messageData = new Uint8Array(buffer.from(messageText, 'utf-8').buffer); 139 let updateLength = 20; // 假设以20字节为单位进行分段update,实际并无具体要求。 140 await mac.init(key); 141 for (let i = 0; i < messageData.length; i += updateLength) { 142 let updateMessage = messageData.subarray(i, i + updateLength); 143 let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage }; 144 await mac.update(updateMessageBlob); 145 } 146 let macOutput = await mac.doFinal(); 147 console.info("CMAC result: " + macOutput.data); 148 let macLen = mac.getMacLength(); 149 console.info('CMAC len:' + macLen); 150 } 151 ``` 152 153- 以使用同步方式分段传入数据,获取消息认证码计算结果为例。 154 155 ```ts 156 import { cryptoFramework } from '@kit.CryptoArchitectureKit'; 157 import { buffer } from '@kit.ArkTS'; 158 159 function genSymKeyByData(symKeyData: Uint8Array) { 160 let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; 161 let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128'); 162 let symKey = aesGenerator.convertKeySync(symKeyBlob); 163 console.info('[Sync]convertKey success'); 164 return symKey; 165 } 166 function doLoopCmacBySync() { 167 // 把字符串按utf-8解码为Uint8Array,使用固定的128位的密钥,即16字节。 168 let keyData = new Uint8Array(buffer.from("12345678abcdefgh", 'utf-8').buffer); 169 let key = genSymKeyByData(keyData); 170 let spec: cryptoFramework.CmacSpec = { 171 algName: "CMAC", 172 cipherName: "AES128", 173 }; 174 let mac = cryptoFramework.createMac(spec); 175 // 假设信息共43字节,utf-8解码后仍为43字节。 176 let messageText = "aaaaa.....bbbbb.....ccccc.....ddddd.....eee"; 177 let messageData = new Uint8Array(buffer.from(messageText, 'utf-8').buffer); 178 let updateLength = 20; // 假设以20字节为单位进行分段update,实际没有具体要求。 179 mac.initSync(key); 180 for (let i = 0; i < messageData.length; i += updateLength) { 181 let updateMessage = messageData.subarray(i, i + updateLength); 182 let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage }; 183 mac.updateSync(updateMessageBlob); 184 } 185 let macOutput = mac.doFinalSync(); 186 console.info("[Sync]CMAC result: " + macOutput.data); 187 let macLen = mac.getMacLength(); 188 console.info('CMAC len:' + macLen); 189 } 190 ``` 191