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