@animo-id/expo-secure-environment

中文文档
0.3.0发布于 2026/10/28APACHE-2.0TypeScriptCommonJS构建来源已验证近 30 天下载 9494

博览安全环境

中文使用文档
文档目录16 节
  1. 开始
  2. 使用量
  3. 支持加密算法
  4. 检查支持
  5. 创建密钥对
  6. 拿公用钥匙
  7. 签名数据
  8. 多次签名
  9. 密钥证明 (Android)
  10. 错误
  11. 从0.2.0移走
  12. 选项代替 biometricsBacked
  13. 撤回安全的环境被移除
  14. 错误
  15. 捐款
  16. 许可证

Animo Logo

博览会-安全环境

电源   Animo Logo


License

开始  |  使用量  |  捐款  |  许可证


一个 博览模块 利用设备的安全环境(HSM、SE等)锁定的生物鉴别认证支持加密操作.

需要博览会SDK 53或更新。 支持Android 11(API 30)和更新,以及iOS 16.4和更新.

支持更古老的Android版本的应用程序仍然可以包括库. 那边 isSecureEnvironmentSupported 财务报告和审定财务报表 isUserAuthenticationAvailable 返回时 false,其他函数则丢出一个 SecureEnvironmentNotSupportedError。 。 。 .

开始

首先使用您的软件包管理器安装模块 .

npm install @animo-id/expo-secure-environment

然后预建应用程序, 以使 Expo 模块包可以添加为本地依赖 :

npx expo prebuild

您已经安装并配置了安全环境模块 .

使用量

您现在可以导入 @animo-id/expo-secure-environment 在您的申请.

支持加密算法

密钥算法页:1

签名算法: ECDSA和SHA256

检查支持

密钥被存储在iOS上的"安全飞地"中,并存储在StrongBox,Android上的"信任执行环境"(TEE)或软件中. 检查设备在生成密钥前是否有一个 :

import { isSecureEnvironmentSupported } from "@animo-id/expo-secure-environment";

isSecureEnvironmentSupported(); // Secure Enclave on iOS, StrongBox on Android
isSecureEnvironmentSupported({ minimumKeyStorage: "trustedEnvironment" }); // TEE or StrongBox on Android

需要用户认证的密钥也需要注册生物鉴别技术或设备密码. 在创建此密钥的流程前选中此项, 例如, 请用户先设置 Face ID :

import { isUserAuthenticationAvailable } from "@animo-id/expo-secure-environment";

isUserAuthenticationAvailable(); // biometrics enrolled
isUserAuthenticationAvailable({ methods: ["biometric", "deviceCredential"] }); // biometrics or a device passcode

在iOS上,这也是 false 生物鉴别技术在尝试失败后被锁定.

创建密钥对

默认使用密钥需要每次生物鉴别认证:

import { generateKeypair } from "@animo-id/expo-secure-environment";

await generateKeypair("my-key");

用选项配置密钥 :

await generateKeypair("my-key", {
  userAuthentication: {
    methods: ["biometric", "deviceCredential"],
    invalidateOnBiometricChange: true,
  },
  minimumKeyStorage: "trustedEnvironment",
});
选项默认说明
userAuthentication需要签名的用户认证,或 false 没有.
userAuthentication.methods['biometric']biometric (身份证、触摸身份证、Android 第3类生物鉴别技术)和/或 deviceCredential (device passcode,PIN,图案或密码).
userAuthentication.invalidateOnBiometricChangetrue当在设备上添加或去除生物鉴别技术时,密钥是否变得无法使用. 仅适用于下列情况: methods 实值 ['biometric']。 。 。 .
userAuthentication.validitySeconds0仅限Android. 该密钥在用户认证后可以使用多久 . 0 需要认证每个签名.
minimumKeyStorage'strongBox'仅限Android. 将密钥存储在最安全的存储器中 Android 上的密钥存储iOS总是使用安全飞地.
preferStrongBoxtrue仅限Android. 设备拥有时是否将密钥存储在 StrongBox 中, 以及何时 minimumKeyStorage 不需要这样.
attestationChallenge仅限Android. 创建包含此挑战的密钥验证, 参见 密钥证明。 。 。 .

Android 上的密钥存储

Android在索取时会将密钥存储于StrongBox. 所有其他密钥都去设备的默认密钥存储:TEE,或者没有TEE设备上的软件,如模拟器. Apps不能选择TEE和软件,所以 minimumKeyStorage 设置您接受的最低安全存储 :

minimumKeyStorage存储密钥的地方失败的时间
strongBoxStrongBox, 一个单独的安全元素.该设备没有"强框".
trustedEnvironment当设备拥有了它时强框,否则默认的密钥存储,必须是TEE.该装置没有TEE.
software设备拥有后有强框,否则默认密钥存储:TEE,或软件.从来没有.

当StrongBox无法存储密钥时,它会转到默认密钥存储处取而代之. StrongBox比TEE慢,可以同时运行较少的操作. 要总是使用默认密钥存储, 例如当您同时生成许多密钥时, 设置 preferStrongBox: false。 。 。 .

软件中的一键无法被你的应用程序所读取,但Android本身可以读取,因此它不能被保护免受被损坏(如被扎入)的设备.

getKeyStorage 返回键的结尾 :

import { getKeyStorage } from "@animo-id/expo-secure-environment";

await getKeyStorage("my-key"); // 'strongBox', 'trustedEnvironment', 'software' or 'secureHardware'

Android 11 不说安全硬件中的密钥是StrongBox还是TEE,所以它返回了 secureHardware 两者都有 核查人也可以从 密钥验证。 。 。 .

拿公用钥匙

返回 P-256 公钥的压缩形式(而不是 DER 编码的主题PublicKeyInfo ):

import { getPublicBytesForKeyId } from "@animo-id/expo-secure-environment";

const publicKey: Uint8Array = await getPublicBytesForKeyId("my-key");

签名数据

返回原始签名(而不是一个编码为 ECDSA-Sig-Value) 。 当密钥需要用户认证时,请用户先认证:

import { sign } from "@animo-id/expo-secure-environment";

const signature = await sign("my-key", message, {
  prompt: { title: "Sign in to Example", cancel: "Cancel" },
});

等待一个显示提示的签名, 然后再开始下一个 。 iOS 显示一个提示, 所以第二个提示取消第一个提示, 然后丢出一个 UserAuthenticationCanceledErrorAndroid 显示一个接一个的提示.

多次签名

一次创建多个签名, 例如要提交多个证书, 使用 withUserAuthentication。在iOS上,用户在第一次签名时用需要的密钥进行认证一次,下一次签名则重新使用该认证。 不需要用户认证的密钥从不问. 在Android上 它的标志像 sign: 保存默认值 validitySeconds 联 合 国 0 并显示每个签名一个提示, 标题中写着用户的签名 。 安全硬件随后允许每个认证一个签名,所以应用程序中没有任何其他代码可以不经询问用户而签名.

import { withUserAuthentication } from "@animo-id/expo-secure-environment";

async function signCredentials(credentials: { keyId: string; name: string }[], message: Uint8Array) {
  return withUserAuthentication(
    async ({ sign }) => {
      const signatures = [];
      for (const [index, { keyId, name }] of credentials.entries()) {
        // The prompt of each signature on Android
        const prompt = { title: `Share ${name}`, subtitle: `${index + 1} of ${credentials.length}` };
        signatures.push(await sign(keyId, message, { prompt }));
      }
      return signatures;
    },
    // The prompt of the one authentication on iOS
    { prompt: { title: `Share ${credentials.length} credentials` } }
  );
}

只有 sign 联 合 国 withUserAuthentication 重用认证, 并且直到调用返回为止 。 后被掷出. 其它 sign 应用程序中的呼叫仍然询问用户, 也当回调运行时, 所以通过 sign 用于共享认证的代码。 它一次签一个消息,所以第二个提示不能取消第一个. 在iOS上,下一个密钥在接受用户认证的方法时重新使用认证:这个密钥只接受密码在生物鉴别后再次询问.

在Android上,键生成方式为 validitySeconds 上文 0 询问一次,然后在有效结束之前不急于签名。 有效性不那么可靠。 在它结束之前,应用程序中的任何代码都可以在不迅速的情况下签名,而不只是 sign 联 合 国 withUserAuthentication,并用其中一把钥匙解锁设备 methods 也开始吧 如果你使用它, 请保持足够长的时间 以便你马上创建的签名.

密钥证明 (Android)

在Android上,一个密钥可以用密钥验证来创建:来自设备安全硬件的证书链,证明密钥是在那里生成的,描述密钥是如何被保护的,包括挑战. 创建密钥时通过挑战,然后获得证书链(base64被编码为 DER 证书,叶先:

import {
  generateKeypair,
  getAttestationCertificateChain,
} from "@animo-id/expo-secure-environment";

await generateKeypair("my-key", { attestationChallenge: challenge });
const certificateChain: string[] = await getAttestationCertificateChain("my-key");

iOS没有安全飞地密钥的密钥证明. 挑战被忽视 getAttestationCertificateChain 掷出.

OpenID4VCI 中的密钥证明 key_storage 财务报告和审定财务报表 user_authentication 键的级别(攻击潜在阻力,ISO 18045)。 您的钱包从如何配置密钥来决定这些关卡 userAuthentication,从何处 getKeyStorage 说一个密钥被存储。 这个库没有指定关卡.

错误

所有错误延伸 SecureEnvironmentError,具有 keyId 和本地错误 code。有特定原因的错误有自己的类:

错误掷出时
SecureEnvironmentNotSupportedError设备没有安全飞地, 或者没有请求 minimumKeyStorage,或运行Android 10或以上.
KeyNotFoundError此 ID 不存在密钥 .
KeyAlreadyExistsError此 ID 的密钥已经存在 .
KeyInvalidatedError仅限Android. 该密钥被永久作废,因为生物鉴别技术改变或屏幕锁被去掉.
UserAuthenticationCanceledError用户,应用程序或系统取消了认证提示.
UserAuthenticationFailedError用户没有成功认证,例如指纹不被识别.
UserAuthenticationLockedOutError生物测量在尝试失败太多后被锁定. 当用户进入设备密码时,它们会解锁,在Android上,第一次闭锁也于30秒后结束.
UserAuthenticationUnavailableError用户无法使用所请求的方法进行认证,例如没有注册生物鉴别技术.

从0.2.0移走

用0.2.0创建的密钥继续工作. sign 从密钥本身读取它是否需要用户认证.

目前最低iOS版本为16.4 (was 13.4),最低Expo SDK为53.

选项代替 biometricsBacked

generateKeypair 财务报告和审定财务报表 sign 不再需要一个 biometricsBacked 参数。 默认值与0.2.0相同:每个签名的生物鉴别认证,当生物鉴别仪改变时,密钥无效,而Android存储于StrongBox.

// 0.2.0
await generateKeypair("my-key", false);
await sign("my-key", message, false);

// now
await generateKeypair("my-key", { userAuthentication: false });
await sign("my-key", message);

第三个论点是: sign 现在设置认证提示的文本,参见 签名数据。 。 。 .

撤回安全的环境被移除

setFallbackSecureEnvironment, (中文(简体) ), shouldUseFallbackSecureEnvironment, (中文(简体) ), isLocalSecureEnvironmentSupported 编辑 SecureEnvironment 界面被删除。 现在的功能总是使用设备的安全环境,以及 generateKeypair 丢出一个 SecureEnvironmentNotSupportedError 当设备没有它.

如果您使用后退, 请检查支持 isSecureEnvironmentSupported 并呼唤你的后退你自己。 继续使用存储在那里的后退键 :

  • isSecureEnvironmentSupported 不总是给出与0.2.0相同的结果. 在iOS上它现在返回 false 没有安全飞地,例如模拟器。 在Android上它会返回 true 用于每个带有 StrongBox 的设备,其中0.2.0 需要 KeyMint 1.0 或更新。 存储每个密钥创建位置, 而不是再次检查支持 .
  • 在Android设备上,没有强框,您可以在TEE中存储密钥 minimumKeyStorage: "trustedEnvironment" 而不是用倒计时 装有"强Box"的设备仍然存放在那里.

错误

  • nativeError 改为: code,本地错误代码(例如:. ERR_KEY_NOT_FOUND) (中文(简体) ). 原始错误在 cause。 。 。 .
  • 构造器选择: new SecureEnvironmentError(message, { keyId, code, cause })。 。 。 . SecureEnvironmentError.fromNative 删除.
  • 认证提示的错误现在有自己的类 。 在Android上,0.2.0 扔这些作为一个平地 SecureEnvironmentError。 。 。 .

KeyNotFoundError 财务报告和审定财务报表 KeyAlreadyExistsError 不变。 其他错误类别被删除 :

0.2.0 (中文(简体) )现在
BiometricAuthenticationFailedUserAuthenticationCanceledError, (中文(简体) ), UserAuthenticationFailedError, (中文(简体) ), UserAuthenticationLockedOutError 或者说 UserAuthenticationUnavailableError
NoHardwareKeyStoreSecureEnvironmentNotSupportedError
KeychainQueryError, (中文(简体) ), CouldNotConvertIntoPublicKey, (中文(简体) ), CouldNotConvertIntoExternalRepresentation, (中文(简体) ), CouldNotCreateSignature, (中文(简体) ), CouldNotGenerateKeyPair, (中文(简体) ), NoSignatureOnCryptoObject, (中文(简体) ), NotExecutedFromMainThreadSecureEnvironmentError

捐款

你想修补还是补充? 太好了,我们喜欢社区贡献! 要参与,请跟随我们 捐款准则。 。 。 .

测试在例应用中运行 反应原生机理。 。 。 . pnpm test:ios 财务报告和审定财务报表 pnpm test:android 用模拟器或仿真器运行它们, pnpm test:ios:device 财务报告和审定财务报表 pnpm test:android:device 电话连接到你的电脑上 只有电话测试安全硬件 见 一般事务人员(其他职等) 详细情况.

许可证

此寄存器根据 Apache 2.0 (英语) 执照.

版本与发布记录

@animo-id/expo-secure-environment 共发布 22 个版本,首次发布于 2024/07/26;过去 12 个月发布了 2 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.3.0latest2026/10/2810 天前
0.2.02026/09/251 个月前
0.1.52025/10/131.1 年前
0.1.42025/10/131.1 年前
0.1.32025/10/131.1 年前
0.1.22025/10/131.1 年前

关于 @animo-id/expo-secure-environment 的常见问题

@animo-id/expo-secure-environment 是什么?

博览安全环境

如何安装 @animo-id/expo-secure-environment?

在项目目录运行 npm install @animo-id/expo-secure-environment,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:expo(>=53.0.0)、react(*)、react-native(*)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@animo-id/expo-secure-environment 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@animo-id/expo-secure-environment 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@animo-id/expo-secure-environment 可以商用吗?

@animo-id/expo-secure-environment 使用 APACHE-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@animo-id/expo-secure-environment 的下载量有多少?

根据 npm 官方下载统计,@animo-id/expo-secure-environment 在 2026/10/06 – 2026/11/04 这 30 天内被下载 9,494 次,日均约 316 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@animo-id/expo-secure-environment 还在维护吗?

最新版本 0.3.0 发布于 2026/10/28(10 天前);至今共发布 22 个版本,其中过去 12 个月发布了 2 个;首次发布于 2024/07/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。