1# HUKS Access Control Development
2
3
4For details about scenarios and related concepts, see [HUKS Access Control Overview](huks-identity-authentication-overview.md).
5
6
7## How to Develop
8
91. Generate a key, enable fingerprint authentication for key access, and set related parameters.
10   When a key is generated or imported, set [HuksUserAuthType](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksuserauthtype9), [HuksAuthAccessType](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksauthaccesstype9), and [HuksChallengeType](../../reference/apis-universal-keystore-kit/js-apis-huks.md#hukschallengetype9).
11
12```ts
13import { huks } from '@kit.UniversalKeystoreKit';
14
15/*
16* Set the key alias and encapsulate the key property set.
17*/
18let keyAlias = 'test_sm4_key_alias';
19let properties: Array<huks.HuksParam> = [{
20  tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
21  value: huks.HuksKeyAlg.HUKS_ALG_SM4
22}, {
23  tag: huks.HuksTag.HUKS_TAG_PURPOSE,
24  value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
25}, {
26  tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
27  value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128,
28}, {
29  tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
30  value: huks.HuksCipherMode.HUKS_MODE_CBC,
31}, {
32  tag: huks.HuksTag.HUKS_TAG_PADDING,
33  value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
34},
35  // Set HuksUserAuthType to fingerprint authentication.
36  {
37    tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE,
38    value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT
39  },
40  // Set HuksAuthAccessType to HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL, which invalidates the key when a new biometric feature (fingerprint) is enrolled.
41  {
42    tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE,
43    value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL
44  },
45  // Use the default challenge type.
46  {
47    tag: huks.HuksTag.HUKS_TAG_CHALLENGE_TYPE,
48    value: huks.HuksChallengeType.HUKS_CHALLENGE_TYPE_NORMAL
49  }];
50
51let huksOptions: huks.HuksOptions = {
52  properties: properties,
53  inData: new Uint8Array(new Array())
54}
55
56/*
57 * Generate a key.
58 */
59class throwObject {
60  isThrow: boolean = false
61}
62
63function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
64  return new Promise<void>((resolve, reject) => {
65    try {
66      huks.generateKeyItem(keyAlias, huksOptions, (error, data) => {
67        if (error) {
68          reject(error);
69        } else {
70          resolve(data);
71        }
72      });
73    } catch (error) {
74      throwObject.isThrow = true;
75      throw (error as Error);
76    }
77  });
78}
79
80async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
81  console.info(`enter promise generateKeyItem`);
82  let throwObject: throwObject = { isThrow: false };
83  try {
84    await generateKeyItem(keyAlias, huksOptions, throwObject)
85      .then((data) => {
86        console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`);
87      })
88      .catch((error: Error) => {
89        if (throwObject.isThrow) {
90          throw (error as Error);
91        } else {
92          console.error(`promise: generateKeyItem failed, ` + JSON.stringify(error));
93        }
94      });
95  } catch (error) {
96    console.error(`promise: generateKeyItem input arg invalid, ` + JSON.stringify(error));
97  }
98}
99
100async function TestGenKeyForFingerprintAccessControl() {
101  await publicGenKeyFunc(keyAlias, huksOptions);
102}
103```
104
1052. Initialize a key session to initiate fingerprint authentication. If the authentication is successful, an authentication token (**AuthToken**) is returned.
106   
107```ts
108import { huks } from '@kit.UniversalKeystoreKit';
109import { userAuth } from '@kit.UserAuthenticationKit';
110
111/*
112 * Set the key alias and encapsulate the key property set.
113 */
114let srcKeyAlias = 'test_sm4_key_alias';
115let handle: number;
116let challenge: Uint8Array;
117let fingerAuthToken: Uint8Array;
118let authType = userAuth.UserAuthType.FINGERPRINT;
119let authTrustLevel = userAuth.AuthTrustLevel.ATL1;
120/* Set the key generation parameter set and key encryption parameter set. */
121let properties: Array<huks.HuksParam> = [{
122  tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
123  value: huks.HuksKeyAlg.HUKS_ALG_SM4,
124}, {
125  tag: huks.HuksTag.HUKS_TAG_PURPOSE,
126  value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT,
127}, {
128  tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
129  value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128,
130}, {
131  tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
132  value: huks.HuksCipherMode.HUKS_MODE_CBC,
133}, {
134  tag: huks.HuksTag.HUKS_TAG_PADDING,
135  value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
136}, {
137  tag: huks.HuksTag.HUKS_TAG_IV,
138  value: StringToUint8Array(IV),
139}];
140
141let huksOptions: huks.HuksOptions = {
142  properties: properties,
143  inData: new Uint8Array(new Array())
144}
145
146class throwObject {
147  isThrow: boolean = false
148}
149
150function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
151  return new Promise<huks.HuksSessionHandle>((resolve, reject) => {
152    try {
153      huks.initSession(keyAlias, huksOptions, (error, data) => {
154        if (error) {
155          reject(error);
156        } else {
157          resolve(data);
158        }
159      });
160    } catch (error) {
161      throwObject.isThrow = true;
162      throw (error as Error);
163    }
164  });
165}
166
167async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
168  console.info(`enter promise doInit`);
169  let throwObject: throwObject = { isThrow: false };
170  try {
171    await initSession(keyAlias, huksOptions, throwObject)
172      .then((data) => {
173        console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);
174        handle = data.handle;
175        challenge = data.challenge as Uint8Array;
176      })
177      .catch((error: Error) => {
178        if (throwObject.isThrow) {
179          throw (error as Error);
180        } else {
181          console.error(`promise: doInit failed, ` + JSON.stringify(error));
182        }
183      });
184  } catch (error) {
185    console.error(`promise: doInit input arg invalid, ` + JSON.stringify(error));
186  }
187}
188
189function userIAMAuthFinger(huksChallenge: Uint8Array) {
190  // Obtain an authentication object.
191  let authTypeList: userAuth.UserAuthType[] = [authType];
192  const authParam: userAuth.AuthParam = {
193    challenge: huksChallenge,
194    authType: authTypeList,
195    authTrustLevel: userAuth.AuthTrustLevel.ATL1
196  };
197  const widgetParam: userAuth.WidgetParam = {
198    title: 'Enter password',
199  };
200  let auth: userAuth.UserAuthInstance;
201  try {
202    auth = userAuth.getUserAuthInstance(authParam, widgetParam);
203    console.info("get auth instance success");
204  } catch (error) {
205    console.error("get auth instance failed" + JSON.stringify(error));
206    return;
207  }
208  // Subscribe to the authentication result.
209  try {
210    auth.on("result", {
211      onResult(result) {
212        console.info("[HUKS] -> [IAM]  userAuthInstance callback result = " + JSON.stringify(result));
213        fingerAuthToken = result.token;
214      }
215    });
216    console.log("subscribe authentication event success");
217  } catch (error) {
218    console.error("subscribe authentication event failed, " + JSON.stringify(error));
219  }
220  // Start user authentication.
221  try {
222    auth.start();
223    console.info("authV9 start auth success");
224  } catch (error) {
225    console.error("authV9 start auth failed, error = " + JSON.stringify(error));
226  }
227}
228
229async function testInitAndAuthFinger() {
230  /* Initialize the key session to obtain a challenge. */
231  await publicInitFunc(srcKeyAlias, huksOptions);
232  /* Invoke userIAM to perform user identity authentication. */
233  userIAMAuthFinger(challenge);
234}
235```
236
2373. Pass in **AuthToken** to perform data operations.
238   
239```ts
240/*
241* The following uses a 128-bit SM4 key as an example.
242*/
243import { huks } from '@kit.UniversalKeystoreKit';
244
245/*
246* Determine the key property set to be encapsulated.
247*/
248let IV = '1234567890123456';
249let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string';
250let handle: number;
251let fingerAuthToken: Uint8Array;
252let finishOutData: Uint8Array;
253
254class throwObject {
255  isThrow: boolean = false;
256}
257
258/* Set the key generation parameter set and key encryption parameter set. */
259class propertyEncryptType {
260  tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM;
261  value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksKeyPadding | huks.HuksCipherMode
262    | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_SM4;
263}
264
265let propertiesEncrypt: propertyEncryptType[] = [
266  {
267    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
268    value: huks.HuksKeyAlg.HUKS_ALG_SM4,
269  },
270  {
271    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
272    value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT,
273  },
274  {
275    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
276    value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128,
277  },
278  {
279    tag: huks.HuksTag.HUKS_TAG_PADDING,
280    value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
281  },
282  {
283    tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
284    value: huks.HuksCipherMode.HUKS_MODE_CBC,
285  },
286  {
287    tag: huks.HuksTag.HUKS_TAG_IV,
288    value: StringToUint8Array(IV),
289  }
290]
291let encryptOptions: huks.HuksOptions = {
292  properties: propertiesEncrypt,
293  inData: new Uint8Array(new Array())
294}
295
296function StringToUint8Array(str: string) {
297  let arr: number[] = [];
298  for (let i = 0, j = str.length; i < j; ++i) {
299    arr.push(str.charCodeAt(i));
300  }
301  return new Uint8Array(arr);
302}
303
304function updateSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) {
305  return new Promise<huks.HuksReturnResult>((resolve, reject) => {
306    try {
307      huks.updateSession(handle, huksOptions, token, (error, data) => {
308        if (error) {
309          reject(error);
310        } else {
311          resolve(data);
312        }
313      });
314    } catch (error) {
315      throwObject.isThrow = true;
316      throw (error as Error);
317    }
318  });
319}
320
321async function publicUpdateFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) {
322  console.info(`enter promise doUpdate`);
323  let throwObject: throwObject = { isThrow: false };
324  try {
325    await updateSession(handle, huksOptions, token, throwObject)
326      .then((data) => {
327        console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);
328      })
329      .catch((error: Error) => {
330        if (throwObject.isThrow) {
331          throw (error as Error);
332        } else {
333          console.error(`promise: doUpdate failed, ` + JSON.stringify(error));
334        }
335      });
336  } catch (error) {
337    console.error(`promise: doUpdate input arg invalid, ` + JSON.stringify(error));
338  }
339}
340
341function finishSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) {
342  return new Promise<huks.HuksReturnResult>((resolve, reject) => {
343    try {
344      huks.finishSession(handle, huksOptions, token, (error, data) => {
345        if (error) {
346          reject(error);
347        } else {
348          resolve(data);
349        }
350      });
351    } catch (error) {
352      throwObject.isThrow = true;
353      throw (error as Error);
354    }
355  });
356}
357
358async function publicFinishFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) {
359  console.info(`enter promise doFinish`);
360  let throwObject: throwObject = { isThrow: false };
361  try {
362    await finishSession(handle, huksOptions, token, throwObject)
363      .then((data) => {
364        finishOutData = data.outData as Uint8Array;
365        console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`);
366      })
367      .catch((error: Error) => {
368        if (throwObject.isThrow) {
369          throw (error as Error);
370        } else {
371          console.error(`promise: doFinish failed, ` + JSON.stringify(error));
372        }
373      });
374  } catch (error) {
375    console.error(`promise: doFinish input arg invalid, ` + JSON.stringify(error));
376  }
377}
378
379async function testSm4Cipher() {
380  encryptOptions.inData = StringToUint8Array(cipherInData);
381  /* Pass in AuthToken. */
382  await publicUpdateFunc(handle, fingerAuthToken, encryptOptions);
383  /* Pass in AuthToken. */
384  await publicFinishFunc(handle, fingerAuthToken, encryptOptions);
385  if (finishOutData === StringToUint8Array(cipherInData)) {
386    console.info('test finish encrypt error ');
387  } else {
388    console.info('test finish encrypt success');
389  }
390}
391```
392