什么是可信应用服务

你有没有想过,怎么证明你拍的照片是真的?怎么证明你的位置没有被篡改?这就是可信应用服务要解决的问题。

可信应用服务(Trusted App Service)是 Device Security Kit 的一部分,它提供了两个很酷的功能:

  1. 安全摄像头:拍出来的照片带有数字签名,可以证明照片是真的,没有被篡改过
  2. 安全地理位置:获取的位置信息带有数字签名,可以证明位置是真的,没有被伪造

简单说,可信应用服务就是让你的应用能"自证清白"。拍的照片是真的,获取的位置也是真的。

核心功能

可信应用服务提供以下功能:

  1. 创建证明密钥:生成一对加密密钥,用来签名和验证。安全摄像头和安全地理位置共用同一个证明密钥,所以只需要创建一次。密钥创建后,会在设备的安全区域里保存,保证密钥不被窃取
  2. 初始化证明会话:创建一个安全会话,用来管理密钥的生命周期。证明会话会验证密钥的有效性,确保密钥没有被篡改。会话创建后,才能使用安全摄像头或安全地理位置功能
  3. 获取安全图像:拍出来的照片带有数字签名。签名包含了拍照时间、设备信息、照片哈希值等数据。服务器收到照片后,用公钥验证签名,就能确认照片是真的、没有被篡改过。比如执法人员拍照取证,照片的签名可以作为法律证据
  4. 获取安全地理位置:获取的位置信息带有数字签名。签名包含了定位时间、设备信息、坐标哈希值等数据。服务器收到位置后,用公钥验证签名,就能确认位置是真的、没有被伪造。比如员工打卡时,签名可以证明他确实在公司

环境搭建

硬件要求

  • 设备类型:手机、平板、2in1 设备
  • HarmonyOS 系统:HarmonyOS NEXT Developer Beta1 及以上

软件要求

  • DevEco Studio 版本:DevEco Studio NEXT Developer Beta1 及以上
  • HarmonyOS SDK 版本:HarmonyOS NEXT Developer Beta1 SDK 及以上

搭建步骤

  1. 安装 DevEco Studio:去华为开发者官网下载安装
  2. 配置开发环境:确保网络环境正常
  3. 设备调试:使用真机进行调试

项目结构

├── entry/src/main/ets
│  ├── common
│  │  ├── CertChain.ets            // 证书链相关操作类
│  │  ├── Permission.ets           // 权限相关操作类
│  │  └── TrustedServiceOption.ets // 可信应用服务接口参数
│  ├── entryability
│  │  └── EntryAbility.ets         // 程序入口类
│  ├── model
│  │  ├── SecureCamera.ets         // 安全相机类
│  │  └── SecureLocation.ets       // 安全地理位置类
│  └── pages
│     └── Index.ets                // 主页面

项目结构比较清晰,核心逻辑在 model 目录下的两个文件里。

第一步:配置权限

module.json5 中添加权限:

{
  "requestPermissions": [
    {
      "name": "ohos.permission.CAMERA"
    },
    {
      "name": "ohos.permission.APPROXIMATELY_LOCATION"
    },
    {
      "name": "ohos.permission.LOCATION"
    }
  ]
}

这里需要三个权限:

  • CAMERA:相机权限,用来拍照
  • APPROXIMATELY_LOCATION:粗略位置权限
  • LOCATION:精确位置权限

第二步:导入模块

import { trustedAppService } from '@kit.DeviceSecurityKit';

导入可信应用服务模块。

第三步:创建证明密钥

在使用安全摄像头或安全地理位置之前,需要先创建证明密钥。

async createAttestKey(): Promise<void> {
  trustedAppService.createAttestKey(createOptions)
    .then(() => {
      this.message += '\n\n创建证明密钥成功';
    })
    .catch(() => {
      this.message += '\n\n创建证明密钥失败';
    });
}

调用 trustedAppService.createAttestKey 创建证明密钥。这个密钥是用来签名的,安全摄像头和安全地理位置共用同一个证明密钥。

在页面出现时创建密钥,页面消失时销毁密钥:

aboutToAppear(): void {
  this.createAttestKey();
}

aboutToDisappear(): void {
  trustedAppService.destroyAttestKey();
}

第四步:初始化安全摄像头

创建好证明密钥后,就可以初始化安全摄像头了。

async initCamera(surfaceId: string, callback: AsyncCallback<string>): Promise<void> {
  try {
    const cameraMgr = camera.getCameraManager(getContext(this) as common.UIAbilityContext);

    // 获取前置摄像头
    const frontCamera = this.getSecureCameraDevice(cameraMgr);

    // 获取前置摄像头在安全模式下支持的能力
    const capability = this.getSecureCameraOutputCapability(cameraMgr, frontCamera);

    // 获取预览流配置信息
    const previewProfile = this.getPreviewProfile(capability);

    // 获取安全流配置信息
    const photoProfile = this.getPreviewProfile(capability);

    // 创建预览流输出对象
    this.previewOutputObj = cameraMgr.createPreviewOutput(previewProfile, surfaceId);

    // 创建安全流输出对象
    const receiver = this.createSecurePhotoReceiver(callback);
    const secureSurfaceId = await receiver.getReceivingSurfaceId();
    this.photoOutputObj = cameraMgr.createPreviewOutput(photoProfile, secureSurfaceId);

    // 创建相机输入对象
    this.cameraInput = cameraMgr.createCameraInput(frontCamera);

    // 初始化安全相机会话
    await this.initSecureCameraAttestContext(this.cameraInput);

    // 打开会话
    await this.openSessionFlow(cameraMgr);
  } catch (err) {
    throw new Error((err as BusinessError).message);
  }
}

这个函数做了很多事情:

  1. 获取相机管理器:通过 camera.getCameraManager 获取
  2. 获取前置摄像头:选择安全模式的摄像头设备
  3. 获取摄像头能力:查看摄像头支持哪些功能
  4. 创建预览流:用来在屏幕上显示预览画面
  5. 创建安全流:用来接收带签名的照片
  6. 初始化证明会话:创建安全相机会话,验证密钥有效性
  7. 打开会话:开始使用摄像头

第五步:打开安全摄像头

用户点击"打开安全相机"按钮时,先检查权限,再初始化摄像头。

Button('打开安全相机').onClick(() => {
  Permission.checkCameraPermission()
    .then((hasPermission: boolean) => {
      if (!hasPermission) {
        return Permission.requestCameraPermission();
      }
      return Promise.resolve();
    })
    .then(() => {
      CameraService.initCamera(this.xComponentController.getXComponentSurfaceId(), (err, msg) => {
        this.message += `\n\n${msg}`;
      });
    })
    .catch(() => {
      this.message += `\n\n打开安全相机失败`;
      this.createAttestKey();
    });
});

先检查相机权限,如果没有权限就请求权限。权限通过后,调用 CameraService.initCamera 初始化安全摄像头。

第六步:获取安全地理位置

安全地理位置有两种获取模式:速度优先和精度优先。

Button('获取地理位置(速度优先)').onClick(() => {
  Permission.checkLocationPermission()
    .then((hasPermission: boolean) => {
      if (!hasPermission) {
        return Permission.requestLocationPermission();
      }
      return Promise.resolve();
    })
    .then(() => {
      const priority = trustedAppService.LocatingPriority.PRIORITY_LOCATING_SPEED;
      return LocationService.getVerifiedSecureLocation(priority);
    })
    .then((locationString: string) => {
      this.message += `\n\n${locationString}`;
    })
    .catch(() => {
      this.message += `\n\n获取地理位置失败`;
      this.createAttestKey();
    });
});

先检查位置权限,然后调用 LocationService.getVerifiedSecureLocation 获取安全位置信息。

public async getVerifiedSecureLocation(priority: trustedAppService.LocatingPriority): Promise<string> {
  try {
    await this.initSecureLocationAttestContext();
    const secureLocation = await trustedAppService.getCurrentSecureLocation(this.timeout, priority);
    // 最佳实践是在服务器端完成安全位置的签名验证
    await this.verifySecureLocation(secureLocation);
    return JSON.stringify(secureLocation.originalLocation);
  } catch (err) {
    throw new Error((err as BusinessError).message);
  }
}

获取安全地理位置的步骤:

  1. 初始化证明会话:创建安全地理位置的证明会话
  2. 获取安全位置:调用 trustedAppService.getCurrentSecureLocation 获取位置
  3. 验证位置:验证位置信息的签名是否有效
  4. 返回结果:返回位置信息

两种位置获取模式

可信应用服务支持两种位置获取模式:

速度优先(PRIORITY_LOCATING_SPEED)

  • 获取速度快
  • 精度相对较低
  • 适合对速度要求高的场景,比如导航

精度优先(PRIORITY_ACCURACY)

  • 获取速度慢
  • 精度高
  • 适合对精度要求高的场景,比如打卡签到

实际应用场景

可信应用服务在实际开发中有很多用途:

考勤打卡

// 员工打卡时,获取安全地理位置
async function checkIn() {
  const priority = trustedAppService.LocatingPriority.PRIORITY_ACCURACY;
  const location = await trustedAppService.getCurrentSecureLocation(timeout, priority);
  // 把带签名的位置信息发送给服务器
  await uploadCheckIn(location);
}

证据采集

// 执法人员拍照取证
async function collectEvidence() {
  // 拍出来的照片带有数字签名
  const photo = await takeSecurePhoto();
  // 照片可以作为法律证据
  await uploadEvidence(photo);
}

物流追踪

// 快递员签收时,获取安全位置
async function confirmDelivery() {
  const priority = trustedAppService.LocatingPriority.PRIORITY_LOCATING_SPEED;
  const location = await trustedAppService.getCurrentSecureLocation(timeout, priority);
  // 确保签收位置是真实的
  await confirmDeliveryAt(location);
}

适用场景

可信应用服务适合以下场景:

  • 考勤应用:防作弊打卡
  • 执法应用:证据采集
  • 物流应用:签收确认
  • 金融应用:远程开户的身份验证
  • 政务应用:在线办事的身份验证

注意事项

  1. 权限要求:需要相机和位置权限
  2. 证明密钥:安全摄像头和安全地理位置共用同一个证明密钥
  3. 服务器验证:最佳实践是在服务器端完成签名验证
  4. 网络要求:需要联网才能完成验证
  5. 设备支持:需要设备支持安全摄像头功能

核心流程图

可信应用服务的整体使用流程:

安全摄像头

安全地理位置

配置相机和位置权限

导入 trustedAppService 模块

创建证明密钥 createAttestKey

需要安全摄像头还是安全地理位置?

初始化安全相机会话

创建预览流和安全流

拍摄带数字签名的照片

初始化安全位置证明会话

获取安全地理位置

将数据发送到服务器

服务器验证数字签名

签名是否有效?

数据真实可信

数据可能被篡改

可信应用服务的应用场景:

可信应用服务

考勤打卡

执法取证

物流签收

远程开户

获取带签名的安全位置

证明员工确实在公司

拍摄带签名的安全照片

照片可作为法律证据

获取快递员签收位置

确保签收位置真实

获取安全人脸照片

验证申请人身份

总结

可信应用服务让你的应用能"自证清白",核心流程:

  1. 创建证明密钥
  2. 初始化证明会话
  3. 获取安全图像或安全地理位置
  4. 在服务器端验证签名

掌握了这些,你就能让你的应用支持安全摄像头和安全地理位置功能,提升应用的安全性和可信度。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐