1# Refined Key Access Control Development 2 3As an extension of the access control based on user identity authentication, the refined key access control provides fine-grained access control capabilities via secondary identity authentication based on biometric features and lock screen passwords. You can set whether identity authentication is required for a key in one or more scenarios such as encryption, decryption, signing, signature verification, key agreement, and key derivation. 4 5For example, a service needs to use a HUKS key to encrypt the account password information. In this scenario, identity authentication is not required in encryption but required in decryption. To achieve this purpose, you can use the refined access control feature provided by HUKS. 6 7To implement this feature, you only need to set **HuksTag** to **HUKS_TAG_KEY_AUTH_PURPOSE**. 8 9## How to Develop 10 111. Generate a key, set HuksUserAuthType to fingerprint authentication, and set other parameters including **HUKS_TAG_KEY_AUTH_PURPOSE**. 12 13 ```ts 14 import huks from '@ohos.security.huks'; 15 import { BusinessError } from '@ohos.base'; 16 /* 17 * Set the key alias and encapsulate the key property set. 18 */ 19 let keyAlias = 'test_sm4_key_alias'; 20 class throwObject { 21 isThrow: boolean = false; 22 } 23 class propertyType { 24 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 25 value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksCipherMode | huks.HuksKeyPadding 26 | huks.HuksUserAuthType | huks.HuksAuthAccessType | huks.HuksChallengeType = huks.HuksKeyAlg.HUKS_ALG_SM4 27 } 28 let properties: propertyType[] = [ 29 { 30 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 31 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 32 }, 33 { 34 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 35 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 36 }, 37 { 38 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 39 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 40 }, 41 { 42 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 43 value: huks.HuksCipherMode.HUKS_MODE_CBC, 44 }, 45 { 46 tag: huks.HuksTag.HUKS_TAG_PADDING, 47 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 48 }, 49 { 50 tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, 51 value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT 52 }, 53 { 54 tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, 55 value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL 56 }, 57 { 58 tag: huks.HuksTag.HUKS_TAG_CHALLENGE_TYPE, 59 value: huks.HuksChallengeType.HUKS_CHALLENGE_TYPE_NORMAL 60 }, 61 { 62 tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_PURPOSE, 63 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 64 } 65 ] 66 let huksOptions: huks.HuksOptions = { 67 properties: properties, 68 inData: new Uint8Array(new Array()) 69 } 70 /* 71 * Generate a key. 72 */ 73 async function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 74 return new Promise<void>((resolve, reject) => { 75 try { 76 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 77 if (error) { 78 reject(error); 79 } else { 80 resolve(data); 81 } 82 }); 83 } catch (error) { 84 throwObject.isThrow = true; 85 throw(error as Error); 86 } 87 }); 88 } 89 async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 90 console.info(`enter promise generateKeyItem`); 91 let throwObject: throwObject = {isThrow: false}; 92 try { 93 await generateKeyItem(keyAlias, huksOptions, throwObject) 94 .then((data) => { 95 console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`); 96 }) 97 .catch((error: BusinessError) => { 98 if (throwObject.isThrow) { 99 throw(error as Error); 100 } else { 101 console.error(`promise: generateKeyItem failed` + error); 102 } 103 }); 104 } catch (error) { 105 console.error(`promise: generateKeyItem input arg invalid` + error); 106 } 107 } 108 async function TestGenKeyForFingerprintAccessControl() { 109 await publicGenKeyFunc(keyAlias, huksOptions); 110 } 111 ``` 112 1132. Use the key. User identity authentication is not required when the key is used for encryption. 114 115 ```ts 116 import huks from '@ohos.security.huks'; 117 import { BusinessError } from '@ohos.base'; 118 class HuksProperties { 119 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 120 value: huks.HuksKeyAlg | huks.HuksKeySize | huks.HuksKeyPurpose | huks.HuksKeyPadding | huks.HuksCipherMode 121 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_ECC; 122 } 123 /* 124 * Set the key alias and encapsulate the key property set. 125 */ 126 let srcKeyAlias = 'sm4_key_fingerprint_access'; 127 let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; // Plaintext 128 let IV = '1234567890123456'; 129 let handle = 0; 130 let cipherText: Uint8Array; // Ciphertext after encryption. 131 function StringToUint8Array(str: string) { 132 let arr: number[] = []; 133 for (let i = 0, j = str.length; i < j; ++i) { 134 arr.push(str.charCodeAt(i)); 135 } 136 return new Uint8Array(arr); 137 } 138 /* Set the key generation parameter set and key encryption parameter set. */ 139 let propertiesEncrypt: HuksProperties[] = [ 140 { 141 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 142 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 143 }, 144 { 145 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 146 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, 147 }, 148 { 149 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 150 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 151 }, 152 { 153 tag: huks.HuksTag.HUKS_TAG_PADDING, 154 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 155 }, 156 { 157 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 158 value: huks.HuksCipherMode.HUKS_MODE_CBC, 159 }, 160 { 161 tag: huks.HuksTag.HUKS_TAG_IV, 162 value: StringToUint8Array(IV), 163 } 164 ]; 165 let encryptOptions: huks.HuksOptions = { 166 properties: propertiesEncrypt, 167 inData: new Uint8Array(new Array()) 168 } 169 class throwObject1{ 170 isThrow: boolean = false; 171 } 172 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject1) { 173 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 174 try { 175 huks.initSession(keyAlias, huksOptions, (error, data) => { 176 if (error) { 177 reject(error); 178 } else { 179 resolve(data); 180 } 181 }); 182 } catch (error) { 183 throwObject.isThrow = true; 184 throw (error as Error); 185 } 186 }); 187 } 188 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 189 console.info(`enter promise doInit`); 190 let throwObject: throwObject1 = { isThrow: false }; 191 try { 192 await initSession(keyAlias, huksOptions, throwObject) 193 .then((data) => { 194 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 195 handle = data.handle as number; 196 }) 197 .catch((error: BusinessError) => { 198 if (throwObject.isThrow) { 199 throw (error as Error); 200 } else { 201 console.error(`promise: doInit failed` + error); 202 } 203 }); 204 } catch (error) { 205 console.error(`promise: doInit input arg invalid` + error); 206 } 207 } 208 function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject1) { 209 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 210 try { 211 huks.finishSession(handle, huksOptions, (error, data) => { 212 if (error) { 213 reject(error); 214 } else { 215 resolve(data); 216 } 217 }); 218 } catch (error) { 219 throwObject.isThrow = true; 220 throw (error as Error); 221 } 222 }); 223 } 224 async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) { 225 console.info(`enter promise doFinish`); 226 let throwObject: throwObject1 = { isThrow: false }; 227 try { 228 await finishSession(handle, huksOptions, throwObject) 229 .then((data) => { 230 cipherText = data.outData as Uint8Array; 231 console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`); 232 }) 233 .catch((error: BusinessError) => { 234 if (throwObject.isThrow) { 235 throw (error as Error); 236 } else { 237 console.error(`promise: doFinish failed` + error); 238 } 239 }); 240 } catch (error) { 241 console.error(`promise: doFinish input arg invalid` + error); 242 } 243 } 244 async function testSm4Cipher() { 245 /* Initialize the key session to obtain a challenge. */ 246 await publicInitFunc(srcKeyAlias, encryptOptions); 247 /** Encryption */ 248 encryptOptions.inData = StringToUint8Array(cipherInData); 249 await publicFinishFunc(handle, encryptOptions); 250 } 251 ``` 252 2533. Use the key. User identity authentication is required when the key is used for decryption. 254 255 ```ts 256 import huks from '@ohos.security.huks'; 257 import userIAM_userAuth from '@ohos.userIAM.userAuth'; 258 import { BusinessError } from '@ohos.base'; 259 /* 260 * Set the key alias and encapsulate the key property set. 261 */ 262 let srcKeyAlias = 'sm4_key_fingerprint_access'; 263 let cipherText = 'r56ywtTJUQC6JFJ2VV2kZw=='; // Ciphertext obtained, which may vary in actual situation. 264 let IV = '1234567890123456'; 265 let handle: number; 266 let finishOutData: Uint8Array; // Plaintext after decryption. 267 let fingerAuthToken: Uint8Array; 268 let challenge: Uint8Array; 269 let authType = userIAM_userAuth.UserAuthType.FINGERPRINT; 270 let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1; 271 class throwObject { 272 isThrow: boolean = false; 273 } 274 function StringToUint8Array(str: string) { 275 let arr: number[] = []; 276 for (let i = 0, j = str.length; i < j; ++i) { 277 arr.push(str.charCodeAt(i)); 278 } 279 return new Uint8Array(arr); 280 } 281 /* Set the key generation parameter set and key encryption parameter set. */ 282 class propertyDecryptType { 283 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM 284 value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksKeyPadding | huks.HuksCipherMode 285 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_SM4 286 } 287 let propertiesDecrypt: propertyDecryptType[] = [ 288 { 289 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 290 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 291 }, 292 { 293 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 294 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 295 }, 296 { 297 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 298 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 299 }, 300 { 301 tag: huks.HuksTag.HUKS_TAG_PADDING, 302 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 303 }, 304 { 305 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 306 value: huks.HuksCipherMode.HUKS_MODE_CBC, 307 }, 308 { 309 tag: huks.HuksTag.HUKS_TAG_IV, 310 value: StringToUint8Array(IV), 311 } 312 ] 313 let decryptOptions: huks.HuksOptions = { 314 properties: propertiesDecrypt, 315 inData: new Uint8Array(new Array()) 316 } 317 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 318 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 319 try { 320 huks.initSession(keyAlias, huksOptions, (error, data) => { 321 if (error) { 322 reject(error); 323 } else { 324 resolve(data); 325 } 326 }); 327 } catch (error) { 328 throwObject.isThrow = true; 329 throw(error as Error); 330 } 331 }); 332 } 333 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 334 console.info(`enter promise doInit`); 335 let throwObject: throwObject = {isThrow: false}; 336 try { 337 await initSession(keyAlias, huksOptions, throwObject) 338 .then ((data) => { 339 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 340 handle = data.handle; 341 challenge = data.challenge as Uint8Array; 342 }) 343 .catch((error: BusinessError) => { 344 if (throwObject.isThrow) { 345 throw(error as Error); 346 } else { 347 console.error(`promise: doInit failed` + error); 348 } 349 }); 350 } catch (error) { 351 console.error(`promise: doInit input arg invalid` + error); 352 } 353 } 354 function userIAMAuthFinger(huksChallenge: Uint8Array) { 355 // Obtain an authentication object. 356 let authTypeList:userIAM_userAuth.UserAuthType[]= new Array(); 357 authTypeList[0] = authType; 358 const authParam:userIAM_userAuth.AuthParam = { 359 challenge: huksChallenge, 360 authType: authTypeList, 361 authTrustLevel: userIAM_userAuth.AuthTrustLevel.ATL1 362 }; 363 const widgetParam:userIAM_userAuth.WidgetParam = { 364 title: 'Enter password', 365 }; 366 let auth : userIAM_userAuth.UserAuthInstance; 367 try { 368 auth = userIAM_userAuth.getUserAuthInstance(authParam, widgetParam); 369 console.log("get auth instance success"); 370 } catch (error) { 371 console.error("get auth instance failed" + error); 372 return; 373 } 374 // Subscribe to the authentication result. 375 try { 376 auth.on("result", { 377 onResult(result) { 378 console.log("[HUKS] -> [IAM] userAuthInstance callback result = " + JSON.stringify(result)); 379 fingerAuthToken = result.token; 380 } 381 }); 382 console.log("subscribe authentication event success"); 383 } catch (error) { 384 console.error("subscribe authentication event failed " + error); 385 } 386 // Start user authentication. 387 try { 388 auth.start(); 389 console.info("authV9 start auth success"); 390 } catch (error) { 391 console.error("authV9 start auth failed, error = " + error); 392 } 393 } 394 function finishSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) { 395 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 396 try { 397 huks.finishSession(handle, huksOptions, token, (error, data) => { 398 if (error) { 399 reject(error); 400 } else { 401 resolve(data); 402 } 403 }); 404 } catch (error) { 405 throwObject.isThrow = true; 406 throw(error as Error); 407 } 408 }); 409 } 410 async function publicFinishFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) { 411 console.info(`enter promise doFinish`); 412 let throwObject: throwObject = {isThrow: false}; 413 try { 414 await finishSession(handle, huksOptions, token, throwObject) 415 .then ((data) => { 416 finishOutData = data.outData as Uint8Array; 417 console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`); 418 }) 419 .catch((error: BusinessError) => { 420 if (throwObject.isThrow) { 421 throw(error as Error); 422 } else { 423 console.error(`promise: doFinish failed` + error); 424 } 425 }); 426 } catch (error) { 427 console.error(`promise: doFinish input arg invalid` + error); 428 } 429 } 430 async function testSm4Cipher() { 431 /* Initialize the key session to obtain a challenge. */ 432 await publicInitFunc(srcKeyAlias, decryptOptions); 433 /* Invoke userIAM to perform user identity authentication. */ 434 userIAMAuthFinger(challenge); 435 /* Perform decryption after the authentication is successful. The **authToken** value returned after the authentication needs to be passed in. */ 436 decryptOptions.inData = StringToUint8Array(cipherText); 437 await publicFinishFunc(handle, fingerAuthToken, decryptOptions); 438 } 439 ``` 440