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