1# 细粒度用户身份认证访问控制开发指导 2 3细粒度用户身份认证访问控制是基于已有用户身份认证访问控制的扩展,提供了基于生物特征和锁屏密码二次身份认证的细粒度访问控制能力,允许设置密钥在加密、解密、签名、验签、密钥协商、密钥派生的单个或多个场景时是否需要进行身份验证。 4 5比如,业务需要使用HUKS密钥加密保存账号密码信息等数据,要求在加密的时候不进行指纹等身份认证,解密的时候需要进行指纹等身份认证,这是就需要依赖HUKS提供细粒度的二次身份认证访问控制机制。 6 7使用该功能仅需在密钥生成阶段,通过额外指定用于细粒度用户身份认证访问控制的HuksTag:HUKS_TAG_KEY_AUTH_PURPOSE,来指定在某种算法用途的情况下需要使用用户身份认证访问控制能力。 8 9> **说明:** 10> 对于对称加解密场景,仅AES/CBC、AES/GCM、SM4/CBC模式支持细粒度访问控制。 11 12## 开发步骤 13 141. 生成密钥,指定指纹类型的访问控制及相关属性,指定HUKS_TAG_KEY_AUTH_PURPOSE值。 15 16 ```ts 17 import { huks } from "@kit.UniversalKeystoreKit"; 18 19 /* 20 * 确定密钥别名和封装密钥属性参数集 21 */ 22 let keyAlias = 'test_sm4_key_alias'; 23 24 class throwObject { 25 isThrow: boolean = false; 26 } 27 28 let properties: Array<huks.HuksParam> = [ 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 67 let huksOptions: huks.HuksOptions = { 68 properties: properties, 69 inData: new Uint8Array(new Array()) 70 } 71 72 /* 73 * 生成密钥 74 */ 75 async function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 76 return new Promise<void>((resolve, reject) => { 77 try { 78 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 79 if (error) { 80 reject(error); 81 } else { 82 resolve(data); 83 } 84 }); 85 } catch (error) { 86 throwObject.isThrow = true; 87 throw (error as Error); 88 } 89 }); 90 } 91 92 async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 93 console.info(`enter promise generateKeyItem`); 94 let throwObject: throwObject = { isThrow: false }; 95 try { 96 await generateKeyItem(keyAlias, huksOptions, throwObject) 97 .then((data) => { 98 console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`); 99 }) 100 .catch((error: Error) => { 101 if (throwObject.isThrow) { 102 throw (error as Error); 103 } else { 104 console.error(`promise: generateKeyItem failed` + JSON.stringify(error)); 105 } 106 }); 107 } catch (error) { 108 console.error(`promise: generateKeyItem input arg invalid` + JSON.stringify(error)); 109 } 110 } 111 112 async function TestGenKeyForFingerprintAccessControl() { 113 await publicGenKeyFunc(keyAlias, huksOptions); 114 } 115 ``` 116 1172. 使用密钥,加密时不需要用户身份认证访问控制。 118 119 ```ts 120 import { huks } from "@kit.UniversalKeystoreKit"; 121 122 class HuksProperties { 123 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 124 value: huks.HuksKeyAlg | huks.HuksKeySize | huks.HuksKeyPurpose | huks.HuksKeyPadding | huks.HuksCipherMode 125 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_ECC; 126 } 127 128 /* 129 * 确定密钥别名和封装密钥属性参数集 130 */ 131 let keyAlias = 'test_sm4_key_alias'; 132 let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; // 明文数据。 133 let IV = '1234567890123456'; // 此处为样例代码,实际使用需采用随机值。 134 let handle = 0; 135 let cipherText: Uint8Array; // 加密后的密文数据。 136 137 function StringToUint8Array(str: string) { 138 let arr: number[] = []; 139 for (let i = 0, j = str.length; i < j; ++i) { 140 arr.push(str.charCodeAt(i)); 141 } 142 return new Uint8Array(arr); 143 } 144 145 /* 集成生成密钥参数集 & 加密参数集 */ 146 let propertiesEncrypt: HuksProperties[] = [ 147 { 148 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 149 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 150 }, 151 { 152 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 153 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, 154 }, 155 { 156 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 157 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 158 }, 159 { 160 tag: huks.HuksTag.HUKS_TAG_PADDING, 161 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 162 }, 163 { 164 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 165 value: huks.HuksCipherMode.HUKS_MODE_CBC, 166 }, 167 { 168 tag: huks.HuksTag.HUKS_TAG_IV, 169 value: StringToUint8Array(IV), 170 } 171 ]; 172 let encryptOptions: huks.HuksOptions = { 173 properties: propertiesEncrypt, 174 inData: new Uint8Array(new Array()) 175 } 176 177 class throwObject1 { 178 isThrow: boolean = false; 179 } 180 181 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject1) { 182 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 183 try { 184 huks.initSession(keyAlias, huksOptions, (error, data) => { 185 if (error) { 186 reject(error); 187 } else { 188 resolve(data); 189 } 190 }); 191 } catch (error) { 192 throwObject.isThrow = true; 193 throw (error as Error); 194 } 195 }); 196 } 197 198 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 199 console.info(`enter promise doInit`); 200 let throwObject: throwObject1 = { isThrow: false }; 201 try { 202 await initSession(keyAlias, huksOptions, throwObject) 203 .then((data) => { 204 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 205 handle = data.handle as number; 206 }) 207 .catch((error: Error) => { 208 if (throwObject.isThrow) { 209 throw (error as Error); 210 } else { 211 console.error(`promise: doInit failed` + JSON.stringify(error)); 212 } 213 }); 214 } catch (error) { 215 console.error(`promise: doInit input arg invalid` + JSON.stringify(error)); 216 } 217 } 218 219 function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject1) { 220 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 221 try { 222 huks.finishSession(handle, huksOptions, (error, data) => { 223 if (error) { 224 reject(error); 225 } else { 226 resolve(data); 227 } 228 }); 229 } catch (error) { 230 throwObject.isThrow = true; 231 throw (error as Error); 232 } 233 }); 234 } 235 236 async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) { 237 console.info(`enter promise doFinish`); 238 let throwObject: throwObject1 = { isThrow: false }; 239 try { 240 await finishSession(handle, huksOptions, throwObject) 241 .then((data) => { 242 cipherText = data.outData as Uint8Array; 243 console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`); 244 }) 245 .catch((error: Error) => { 246 if (throwObject.isThrow) { 247 throw (error as Error); 248 } else { 249 console.error(`promise: doFinish failed` + JSON.stringify(error)); 250 } 251 }); 252 } catch (error) { 253 console.error(`promise: doFinish input arg invalid` + JSON.stringify(error)); 254 } 255 } 256 257 async function testSm4Cipher() { 258 /* 初始化密钥会话获取挑战值 */ 259 await publicInitFunc(keyAlias, encryptOptions); 260 /* 加密 */ 261 encryptOptions.inData = StringToUint8Array(cipherInData); 262 await publicFinishFunc(handle, encryptOptions); 263 } 264 ``` 265 2663. 使用密钥,解密时需要进行用户身份认证访问控制。 267 268 ```ts 269 import { huks } from "@kit.UniversalKeystoreKit"; 270 import { userAuth } from '@kit.UserAuthenticationKit'; 271 import { BusinessError } from "@kit.BasicServicesKit" 272 273 let keyAlias = 'test_sm4_key_alias'; 274 let IV = '1234567890123456'; // 此处为样例代码,实际使用需采用随机值。 275 let handle = 0; 276 let cipherText: Uint8Array; // 密文数据。 277 /* 278 * 确定封装密钥属性参数集 279 */ 280 let finishOutData: Uint8Array; // 解密后的明文数据。 281 let fingerAuthToken: Uint8Array; 282 let challenge: Uint8Array; 283 let authType = userAuth.UserAuthType.FINGERPRINT; 284 let authTrustLevel = userAuth.AuthTrustLevel.ATL1; 285 286 class throwObject { 287 isThrow: boolean = false; 288 } 289 290 function StringToUint8Array(str: string) { 291 let arr: number[] = []; 292 for (let i = 0, j = str.length; i < j; ++i) { 293 arr.push(str.charCodeAt(i)); 294 } 295 return new Uint8Array(arr); 296 } 297 298 /* 集成生成密钥参数集 & 加密参数集 */ 299 class propertyDecryptType { 300 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM 301 value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksKeyPadding | huks.HuksCipherMode 302 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_SM4 303 } 304 305 let propertiesDecrypt: propertyDecryptType[] = [ 306 { 307 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 308 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 309 }, 310 { 311 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 312 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 313 }, 314 { 315 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 316 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 317 }, 318 { 319 tag: huks.HuksTag.HUKS_TAG_PADDING, 320 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 321 }, 322 { 323 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 324 value: huks.HuksCipherMode.HUKS_MODE_CBC, 325 }, 326 { 327 tag: huks.HuksTag.HUKS_TAG_IV, 328 value: StringToUint8Array(IV), 329 } 330 ] 331 let decryptOptions: huks.HuksOptions = { 332 properties: propertiesDecrypt, 333 inData: new Uint8Array(new Array()) 334 } 335 336 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 337 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 338 try { 339 huks.initSession(keyAlias, huksOptions, (error, data) => { 340 if (error) { 341 reject(error); 342 } else { 343 resolve(data); 344 } 345 }); 346 } catch (error) { 347 throwObject.isThrow = true; 348 throw (error as Error); 349 } 350 }); 351 } 352 353 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 354 console.info(`enter promise doInit`); 355 let throwObject: throwObject = { isThrow: false }; 356 try { 357 await initSession(keyAlias, huksOptions, throwObject) 358 .then((data) => { 359 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 360 handle = data.handle; 361 challenge = data.challenge as Uint8Array; 362 }) 363 .catch((error: BusinessError) => { 364 if (throwObject.isThrow) { 365 throw (error as Error); 366 } else { 367 console.error(`promise: doInit failed` + JSON.stringify(error)); 368 } 369 }); 370 } catch (error) { 371 console.error(`promise: doInit input arg invalid` + JSON.stringify(error)); 372 } 373 } 374 375 function userIAMAuthFinger(huksChallenge: Uint8Array) { 376 // 获取认证对象。 377 let authTypeList: userAuth.UserAuthType[] = [authType]; 378 const authParam: userAuth.AuthParam = { 379 challenge: huksChallenge, 380 authType: authTypeList, 381 authTrustLevel: userAuth.AuthTrustLevel.ATL1 382 }; 383 const widgetParam: userAuth.WidgetParam = { 384 title: '请输入密码', 385 }; 386 let auth: userAuth.UserAuthInstance; 387 try { 388 auth = userAuth.getUserAuthInstance(authParam, widgetParam); 389 console.info("get auth instance success"); 390 } catch (error) { 391 console.error("get auth instance failed" + JSON.stringify(error)); 392 return; 393 } 394 // 订阅认证结果。 395 try { 396 auth.on("result", { 397 onResult(result) { 398 console.info("[HUKS] -> [IAM] userAuthInstance callback result = " + JSON.stringify(result)); 399 fingerAuthToken = result.token; 400 } 401 }); 402 console.info("subscribe authentication event success"); 403 } catch (error) { 404 console.error("subscribe authentication event failed " + JSON.stringify(error)); 405 } 406 // 开始认证。 407 try { 408 auth.start(); 409 console.info("authV9 start auth success"); 410 } catch (error) { 411 console.error("authV9 start auth failed, error = " + JSON.stringify(error)); 412 } 413 } 414 415 function finishSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) { 416 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 417 try { 418 huks.finishSession(handle, huksOptions, token, (error, data) => { 419 if (error) { 420 reject(error); 421 } else { 422 resolve(data); 423 } 424 }); 425 } catch (error) { 426 throwObject.isThrow = true; 427 throw (error as Error); 428 } 429 }); 430 } 431 432 async function publicFinishFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) { 433 console.info(`enter promise doFinish`); 434 let throwObject: throwObject = { isThrow: false }; 435 try { 436 await finishSession(handle, huksOptions, token, throwObject) 437 .then((data) => { 438 finishOutData = data.outData as Uint8Array; 439 console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`); 440 }) 441 .catch((error: BusinessError) => { 442 if (throwObject.isThrow) { 443 throw (error as Error); 444 } else { 445 console.error(`promise: doFinish failed` + JSON.stringify(error)); 446 } 447 }); 448 } catch (error) { 449 console.error(`promise: doFinish input arg invalid` + JSON.stringify(error)); 450 } 451 } 452 453 async function testSm4CipherInit() { 454 /* 初始化密钥会话获取挑战值 */ 455 await publicInitFunc(keyAlias, decryptOptions); 456 /* 调用userIAM进行身份认证 */ 457 userIAMAuthFinger(challenge); 458 } 459 460 async function testSm4CipherFinish() { 461 /* 认证成功后进行解密, 需要传入Auth获取到的authToken值 */ 462 decryptOptions.inData = cipherText; 463 await publicFinishFunc(handle, fingerAuthToken, decryptOptions); 464 } 465 ``` 466