• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Facial Authentication
2
3## Overview
4
5### Function
6
7Facial authentication provides user authentication capabilities in identity authentication scenarios, such as device unlocking, payment, and app logins. It uses biometric recognition technologies to identify individuals based on facial characteristics. A camera is used to collect images or video streams that contain human faces, and automatically detect, track, and recognize human faces. Facial authentication is also called facial recognition. The figure below shows the architecture of facial authentication.
8
9The face authentication (Face_auth) driver is developed based on the Hardware Driver Foundation (HDF). It shields hardware differences and provides stable facial authentication capabilities for the user authentication framework (User_auth) and Face_auth service. The facial authentication capabilities include obtaining facial recognition executor list, executor information, and template information by template ID, comparing face image template information of the executor and that of User_auth, enrolling or deleting face image templates, and performing facial authentication.
10
11**Figure 1** Facial authentication architecture
12
13![image](figures/face_auth_architecture.png "Facial authentication architecture")
14
15### Basic Concepts
16
17The identity authentication consists of User_auth and basic authentication services (including PIN authentication and facial authentication). It supports basic functions such as setting and deleting user credentials and performing authentication. The system supports user identity authentication and data collection, processing, storage, and comparison.
18- Executor
19
20  The executor collects, processes, stores, and compares data for authentication. Each authentication service provides the executor capabilities, which are scheduled by User_auth to implement basic capabilities.
21
22- Executor security level
23
24  Security level required for the execution environment of an executor.
25
26- Executor role
27
28  - Executor: independently completes the entire process of credential registration and identity authentication. The executor can collect, process, store, and compare data to complete the authentication.
29
30  - Collector: only collects data during user authentication. It needs to work with the authenticator to complete user authentication.
31
32  - Authenticator: only processes data, obtains the stored credential template, and compares it with the authentication information generated.
33
34- Executor type
35
36  The authentication algorithm varies depending on the authentication mode and device used. Different executor types are defined based on the supported algorithm type or the device in use.
37
38- User_auth public key & executor public key
39
40  To ensure user data security and authentication result accuracy, measures must be taken to protect the integrity of the key information exchanged between User_auth and basic authentication services. Public keys must be exchanged when the executor provided by a basic authentication service interworks with User_auth.
41
42    The executor uses the User_auth public key to verify scheduling instructions.
43
44    User_auth uses the executor public key to verify the authentication result accuracy and the integrity of the information exchanged with the executor.
45
46- Authentication credential template
47
48  Authentication credentials are generated and stored by the authentication service when users set authentication credentials. Each template has an ID to index a set of template information files. The template information needs to be compared with the authentication data generated during authentication to complete identity authentication.
49
50- Data verification by the executor
51
52  User_auth manages the mappings between user identities and credential IDs in a unified manner. When connecting to User_auth, the executor obtains the template ID list from User_auth and updates its template ID list based on the template ID list obtained.
53
54### Working Principles
55
56The Face_auth driver provides basic facial authentication capabilities for the User_auth and Face_auth service to ensure successful facial authentication.
57You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use.
58
59**Figure 2** Face_auth service and Face_auth driver interaction
60
61![image](figures/face_auth_service_and_driver_interaction.png "Face_auth service and Face_auth driver interaction")
62
63### Constraints
64
65- To implement facial authentication, the device must have a camera and the face image must be greater than 100 x 100 pixels.
66- A Trusted Execution Environment (TEE) must be available, and facial feature information must be encrypted and stored in a TEE.
67- The face matching accuracy varies with people with similar looks and children whose facial features keep changing. If you are concerned about this, consider using other authentication modes.
68
69## Development Guidelines
70
71### When to Use
72
73The Face_auth driver provides basic facial authentication capabilities for the User_auth and Face_auth service to ensure successful facial authentication.
74
75### Available APIs
76
77**Table 1** Available APIs
78
79| API                                                      | Description                                                    |
80| ------------------------------------------------------------ | ------------------------------------------------------------ |
81| GetExecutorList(std::vector<sptr<IExecutor>>& executorList)  | Obtains the executor list.                                            |
82| GetExecutorInfo(ExecutorInfo& info)                          | Obtains the executor information, including the executor type, executor role, authentication type, security level, and executor public key.|
83| GetTemplateInfo(uint64_t templateId, TemplateInfo& info)     | Obtains information about a face image template based on the specified template ID.                              |
84| OnRegisterFinish(const std::vector<uint64_t>& templateIdList,<br>        const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully.|
85| Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br>        const sptr<IExecutorCallback>& callbackObj) | Enrolls a face image template.                                              |
86| Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList,<br>        const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) | Performs facial authentication.                                              |
87| Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br>        const sptr<IExecutorCallback>& callbackObj) | Performs facial identification.                                              |
88| Delete(const std::vector<uint64_t>& templateIdList)          | Deletes a face image template.                                              |
89| Cancel(uint64_t scheduleId)                                  | Cancels a face enrolling, authentication, or identification operation based on the **scheduleId**.                |
90| SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,<br>        const sptr<IExecutorCallback>& callbackObj) | Sends commands to the Face_auth service.             |
91
92**Table 2** Callbacks
93
94| API                                                      | Description                |
95| ------------------------------------------------------------ | ------------------------ |
96| IExecutorCallback::OnResult(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the operation result.    |
97| IExecutorCallback::OnTip(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the interaction information about the operation process.|
98
99### How to Develop
100
101The following uses the Hi3516D V300 development board as an example to demonstrate how to develop the Face_auth driver. <br/>The directory structure is as follows:
102
103```undefined
104// drivers/peripheral/face_auth
105├── BUILD.gn # Build script
106├── bundle.json # Module description file
107└── hdi_service # Face_auth driver implementation
108    ├── BUILD.gn # Build script
109    ├── include # Header files
110    └── src
111        ├── executor_impl.cpp # Implementation of authentication and enrollment APIs
112        ├── face_auth_interface_driver.cpp # Face_auth driver entry
113        └── face_auth_interface_service.cpp # Implementation of the APIs for obtaining the executor list
114```
115
116The development procedure is as follows:
117
1181. Develop the Face_auth driver based on the HDF. The **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions are used. For details about the code, see [face_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/face_auth_interface_driver.cpp).
119
120   ```c++
121   // Create an IRemoteObject object by using the custom HdfFaceAuthInterfaceHost object, which consists of the IoService object and HDI service.
122   struct HdfFaceAuthInterfaceHost {
123       struct IDeviceIoService ioService;
124       OHOS::sptr<OHOS::IRemoteObject> stub;
125   };
126
127   // Enable the IPC service to call the response API.
128   static int32_t FaceAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
129       struct HdfSBuf *reply)
130   {
131       IAM_LOGI("start");
132       auto *hdfFaceAuthInterfaceHost = CONTAINER_OF(client->device->service,
133           struct HdfFaceAuthInterfaceHost, ioService);
134
135       OHOS::MessageParcel *dataParcel = nullptr;
136       OHOS::MessageParcel *replyParcel = nullptr;
137       OHOS::MessageOption option;
138
139       if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
140           IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);
141           return HDF_ERR_INVALID_PARAM;
142       }
143       if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
144           IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);
145           return HDF_ERR_INVALID_PARAM;
146       }
147
148       return hdfFaceAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
149   }
150
151   // Initialize the HdfFaceAuthInterfaceDriver object.
152   int HdfFaceAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
153   {
154       IAM_LOGI("start");
155       if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_USERAUTH)) {
156           IAM_LOGE("set face auth hdf class failed");
157           return HDF_FAILURE;
158       }
159       return HDF_SUCCESS;
160   }
161
162   // Bind the service provided by the Face_auth driver to the HDF.
163   int HdfFaceAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
164   {
165       IAM_LOGI("start");
166       auto *hdfFaceAuthInterfaceHost = new (std::nothrow) HdfFaceAuthInterfaceHost;
167       if (hdfFaceAuthInterfaceHost == nullptr) {
168           IAM_LOGE("%{public}s: Failed to create HdfFaceAuthInterfaceHost object", __func__);
169           return HDF_FAILURE;
170       }
171
172       hdfFaceAuthInterfaceHost->ioService.Dispatch = FaceAuthInterfaceDriverDispatch;
173       hdfFaceAuthInterfaceHost->ioService.Open = NULL;
174       hdfFaceAuthInterfaceHost->ioService.Release = NULL;
175
176       auto serviceImpl = IFaceAuthInterface::Get(true);
177       if (serviceImpl == nullptr) {
178           IAM_LOGE("%{public}s: Failed to implement service", __func__);
179           return HDF_FAILURE;
180       }
181
182       hdfFaceAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
183           IFaceAuthInterface::GetDescriptor());
184       if (hdfFaceAuthInterfaceHost->stub == nullptr) {
185           IAM_LOGE("%{public}s: Failed to get stub object", __func__);
186           return HDF_FAILURE;
187       }
188
189       deviceObject->service = &hdfFaceAuthInterfaceHost->ioService;
190       IAM_LOGI("success");
191       return HDF_SUCCESS;
192   }
193
194   // Release resources of the Face_auth driver.
195   void HdfFaceAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
196   {
197       IAM_LOGI("start");
198       auto *hdfFaceAuthInterfaceHost = CONTAINER_OF(deviceObject->service,
199           struct HdfFaceAuthInterfaceHost, ioService);
200       delete hdfFaceAuthInterfaceHost;
201       IAM_LOGI("success");
202   }
203
204   // Register the entry data structure object of the Face_auth driver.
205   struct HdfDriverEntry g_faceAuthInterfaceDriverEntry = {
206       .moduleVersion = 1,
207       .moduleName = "faceauth_interface_service",
208       .Bind = HdfFaceAuthInterfaceDriverBind,
209       .Init = HdfFaceAuthInterfaceDriverInit,
210       .Release = HdfFaceAuthInterfaceDriverRelease,
211   };
212
213   // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind() function and then the Init() function. If the Init() function fails to be called, the HDF will call Release() to release driver resources and exit the driver model.
214   HDF_INIT(g_faceAuthInterfaceDriverEntry);
215   ```
216
2172. Implement the API for obtaining the executor list. For details about the code, see [face_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/face_auth_interface_service.cpp).
218
219   ```c++
220   // Executor implementation class
221   class ExecutorImpl : public IExecutor {
222   public:
223       ExecutorImpl(struct ExecutorInfo executorInfo);
224       virtual ~ExecutorImpl() {}
225
226   private:
227       struct ExecutorInfo executorInfo_; // Executor information
228   };
229
230   static constexpr uint16_t SENSOR_ID = 123; // Executor sensor ID
231   static constexpr uint32_t EXECUTOR_TYPE = 123; // Executor type
232   static constexpr size_t PUBLIC_KEY_LEN = 32; //32-byte public key of the executor
233
234   // Create an HDI service object.
235   extern "C" IFaceAuthInterface *FaceAuthInterfaceImplGetInstance(void)
236   {
237       auto faceAuthInterfaceService = new (std::nothrow) FaceAuthInterfaceService();
238       if (faceAuthInterfaceService == nullptr) {
239           IAM_LOGE("faceAuthInterfaceService is nullptr");
240           return nullptr;
241       }
242       return faceAuthInterfaceService;
243   }
244
245   // Obtain the executor list and create an executor.
246   int32_t GetExecutorList(std::vector<sptr<IExecutor>>& executorList)
247   {
248       IAM_LOGI("interface mock start");
249       executorList.clear();
250       struct ExecutorInfo executorInfoExample = {
251           .sensorId = SENSOR_ID,
252           .executorType = EXECUTOR_TYPE,
253           .executorRole = ExecutorRole::ALL_IN_ONE,
254           .authType = AuthType::FACE,
255           .esl = ExecutorSecureLevel::ESL0, // Executor security level, which ranges from ESL0 to ESL3 (highest).
256           .publicKey = std::vector<uint8_t>(PUBLIC_KEY_LEN, 0), // 32-byte public key, using the Ed25519 algorithm.
257           .extraInfo = {},
258       };
259       auto executor = new (std::nothrow) ExecutorImpl(executorInfoExample);
260       if (executor == nullptr) {
261           IAM_LOGE("executor is nullptr");
262           return HDF_FAILURE;
263       }
264       executorList.push_back(sptr<IExecutor>(executor));
265       IAM_LOGI("interface mock success");
266       return HDF_SUCCESS;
267   }
268   ```
269
2703. Implement each function of the executor. For details about the code, see [executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/executor_impl.cpp).
271
272   ```c++
273   // Obtain the executor information.
274   int32_t GetExecutorInfo(ExecutorInfo& info)
275   {
276       IAM_LOGI("interface mock start");
277       info = executorInfo_;
278       IAM_LOGI("Executor information got successfully");
279       return HDF_SUCCESS;
280   }
281
282   // Obtain template information based on templateId.
283   int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo& info)
284   {
285       IAM_LOGI("interface mock start");
286       static_cast<void>(templateId);
287       info = {0};
288       IAM_LOGI("Template information got successfully");
289       return HDF_SUCCESS;
290   }
291
292   // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key. The executor compares its template ID list with the template ID list obtained and updates its template ID list.
293   int32_t OnRegisterFinish(const std::vector<uint64_t>& templateIdList,
294       const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo)
295   {
296       IAM_LOGI("interface mock start");
297       static_cast<void>(templateIdList);
298       static_cast<void>(extraInfo);
299       static_cast<void>(frameworkPublicKey);
300       IAM_LOGI("Registration finished");
301       return HDF_SUCCESS;
302   }
303
304   // Enroll a face image.
305   int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
306       const sptr<IExecutorCallback>& callbackObj)
307   {
308       IAM_LOGI("interface mock start");
309       static_cast<void>(scheduleId);
310       static_cast<void>(extraInfo);
311       IAM_LOGI("enroll, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT);
312       int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {});
313       if (ret != ResultCode::SUCCESS) {
314           IAM_LOGE("callback result is %{public}d", ret);
315           return HDF_FAILURE;
316       }
317       return HDF_SUCCESS;
318   }
319
320   // Start facial authentication.
321   int32_t Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList,
322       const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj)
323   {
324       IAM_LOGI("interface mock start");
325       static_cast<void>(scheduleId);
326       static_cast<void>(templateIdList);
327       static_cast<void>(extraInfo);
328       IAM_LOGI("authenticate, result is %{public}d", ResultCode::NOT_ENROLLED);
329       int32_t ret = callbackObj->OnResult(ResultCode::NOT_ENROLLED, {});
330       if (ret != ResultCode::SUCCESS) {
331           IAM_LOGE("callback result is %{public}d", ret);
332           return HDF_FAILURE;
333       }
334       return HDF_SUCCESS;
335   }
336
337   // Perform facial recognition.
338   int32_t Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
339       const sptr<IExecutorCallback>& callbackObj)
340   {
341       IAM_LOGI("interface mock start");
342       static_cast<void>(scheduleId);
343       static_cast<void>(extraInfo);
344       IAM_LOGI("identify, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT);
345       int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {});
346       if (ret != ResultCode::SUCCESS) {
347           IAM_LOGE("callback result is %{public}d", ret);
348           return HDF_FAILURE;
349       }
350       return HDF_SUCCESS;
351   }
352
353   // Delete the face image template.
354   int32_t Delete(const std::vector<uint64_t>& templateIdList)
355   {
356       IAM_LOGI("interface mock start");
357       static_cast<void>(templateIdList);
358       IAM_LOGI("delete success");
359       return HDF_SUCCESS;
360   }
361
362   // Cancel the operation based on the specified scheduleId.
363   int32_t Cancel(uint64_t scheduleId)
364   {
365       IAM_LOGI("interface mock start");
366       static_cast<void>(scheduleId);
367       IAM_LOGI("cancel success");
368       return HDF_SUCCESS;
369   }
370
371   // Send template locking or unlocking command from the Face_auth service to the Face_auth driver.
372   int32_t SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,
373       const sptr<IExecutorCallback>& callbackObj)
374   {
375       IAM_LOGI("interface mock start");
376       static_cast<void>(extraInfo);
377       int32_t ret;
378       switch (commandId) {
379           case LOCK_TEMPLATE:
380               IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS);
381               ret = callbackObj->OnResult(ResultCode::SUCCESS, {});
382               if (ret != ResultCode::SUCCESS) {
383                   IAM_LOGE("callback result is %{public}d", ret);
384                   return HDF_FAILURE;
385               }
386               break;
387           case UNLOCK_TEMPLATE:
388               IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS);
389               ret = callbackObj->OnResult(ResultCode::SUCCESS, {});
390               if (ret != ResultCode::SUCCESS) {
391                   IAM_LOGE("callback result is %{public}d", ret);
392                   return HDF_FAILURE;
393               }
394               break;
395           default:
396               IAM_LOGD("not support CommandId : %{public}d", commandId);
397               ret = callbackObj->OnResult(ResultCode::GENERAL_ERROR, {});
398               if (ret != ResultCode::SUCCESS) {
399                   IAM_LOGE("callback result is %{public}d", ret);
400                   return HDF_FAILURE;
401               }
402       }
403       return HDF_SUCCESS;
404   }
405   ```
406
4074. Modify **serviceName2Config** in the **face_auth_service.cpp** file if you need to add a driver or modify driver information.
408
409   ```c++
410   // base/user_iam/face_auth/services/src/face_auth_service.cpp
411   void FaceAuthService::StartDriverManager()
412   {
413       IAM_LOGI("start");
414       // Service name and ID of the driver to add or modify. The driver service name and ID must be globally unique.
415       const std::map<std::string, UserAuth::ServiceConfig> serviceName2Config = {
416           {"face_auth_interface_service", {1, std::make_shared<FaceAuthDriverHdi>()}},
417       };
418       UserIAM::UserAuth::IDriverManager::GetInstance().Start(serviceName2Config);
419   }
420   ```
421
422### Verification
423
424Use the [User Authentication APIs](../../application-dev/reference/apis/js-apis-useriam-userauth.md) to develop a JavaScript application and verify the application on the Hi3516D V300 development board. The sample code for verifying and canceling the authentication is as follows:
425
426```js
427// API version 8
428import userIAM_userAuth from '@ohos.userIAM.userAuth';
429let auth = new userIAM_userAuth.UserAuth();
430
431export default {
432    getVersion() {
433        console.info("start to get version");
434        let version = this.auth.getVersion();
435        console.info("auth version = " + version);
436    },
437
438    startAuth() {
439        console.info("start auth");
440        this.auth.auth(null, userIAM_userAuth.UserAuthType.FACE, userIAM_userAuth.AuthTrustLevel.ATL1, {
441            onResult: (result, extraInfo) => {
442                try {
443                    console.info("auth onResult result = " + result);
444                    console.info("auth onResult extraInfo = " + JSON.stringify(extraInfo));
445                    if (result == userIAM_userAuth.ResultCode.SUCCESS) {
446                        // Add the logic to be executed when the authentication is successful.
447                    }  else {
448                        // Add the logic to be executed when the authentication fails.
449                    }
450                } catch (e) {
451                    console.info("auth onResult error = " + e);
452                }
453            },
454
455            onAcquireInfo: (module, acquire, extraInfo) => {
456                try {
457                    console.info("auth onAcquireInfo module = " + module);
458                    console.info("auth onAcquireInfo acquire = " + acquire);
459                    console.info("auth onAcquireInfo extraInfo = " + JSON.stringify(extraInfo));
460                } catch (e) {
461                    console.info("auth onAcquireInfo error = " + e);
462                }
463            }
464        });
465    },
466
467    cancelAuth() {
468        console.info("start cancel auth");
469        // Obtain contextId using auth().
470        let contextId = auth.auth(null, userIAM_userAuth.UserAuthType.FACE, userIAM_userAuth.AuthTrustLevel.ATL1, {
471            onResult: (result, extraInfo) => {
472                console.info("auth onResult result = " + result);
473            },
474
475            onAcquireInfo: (module, acquire, extraInfo) => {
476                console.info("auth onAcquireInfo module = " + module);
477            }
478        });
479        let cancelCode = this.auth.cancel(contextId);
480        if (cancelCode == userIAM_userAuth.ResultCode.SUCCESS) {
481            console.info("Authentication canceled successfully");
482        } else {
483            console.error("failed to cancel authentication");
484        }
485    }
486}
487```
488