可通过 FIPS 140-3 认证的 GKI 加密模块

GKI 内核包含一个名为 fips140.ko 的 Linux 内核模块,该模块符合加密软件模块的 FIPS 140-3 要求。如果运行 GKI 内核的产品需要 FIPS 认证,可以提交此模块以进行此认证。

具体而言,必须满足以下 FIPS 140-3 要求才能使用加密例程:

  • 此模块必须先检查自己的完整性,然后才能提供加密算法。
  • 此模块必须先使用已知答案的自测来测试和验证其已获批准的加密算法,然后才能提供这些算法。

为什么要使用单独的内核模块

FIPS 140-3 验证基于这样一种理念:基于软件或硬件的模块一旦通过认证就不能再更改。如果发生了更改,就必须重新认证。这与当前所用的软件开发流程有所不同;由于此要求,FIPS 软件模块在设计时通常会把关注点尽可能放在加密组件上,以确保与加密无关的更改不需要重新评估加密。

GKI 内核在受支持的整个生命周期内会定期更新。这使得无法将整个内核置于 FIPS 模块内,因为这样的模块在每次内核更新后都需要重新认证。虽然将“FIPS 模块”定义为内核映像的子集可以缓解这一问题,但并未解决该问题,因为“FIPS 模块”的二进制内容的更改频率仍会大大高于需求。

在内核版本 6.1 之前,GKI 在编译时还启用了 LTO(链接时优化),因为 LTO 是控制流完整性这项重要安全功能的前提条件。

因此,我们将 FIPS 140-3 要求涵盖的所有代码封装到一个单独的内核模块 (fips140.ko) 中,该模块仅依赖于作为构建基础的 GKI 内核源代码所提供的稳定接口。这意味着该模块可用于属于同一代的不同 GKI 版本,并且只有在模块自身携带的代码中修复了任何问题时,才需要更新模块并重新提交以进行认证。

模块适用情形

GKI 内核自身携带的代码依赖于同样封装在 FIPS 140-3 内核模块中的加密例程。因此,内置加密例程实际上并没有从 GKI 内核中移出,而是被复制到了该模块中。加载该模块后,内置加密例程会从 Linux CryptoAPI 中取消注册,并被模块携带的例程取代。

这意味着 fips140.ko 模块完全是可选的,只有在要求进行 FIPS 140-3 认证时才需要部署。除此之外,该模块没有任何额外的功能,在不必要的情况下加载它只会影响启动时间,而不会带来任何好处。

如何部署该模块

您可以按照以下步骤将该模块整合到 Android build 中:

  • 将模块名称添加到 BOARD_VENDOR_RAMDISK_KERNEL_MODULES 中。这会使得模块被复制到供应商 ramdisk 中。
  • 将模块名称添加到 BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD 中。这会使得模块名称被添加到目标上的 modules.load 中。modules.load 包含设备启动时 init 加载的模块列表。

完整性自检

FIPS 140-3 内核模块会在模块加载时获取自己的 .code.rodata 部分的 HMAC-SHA256 摘要,并将其与模块中记录的摘要进行比较。该操作发生在 Linux 模块加载程序进行常规修改(例如,ELF 重定位处理和对这两个部分进行的 CPU errata 替代修补)之后。为确保能够正确重现摘要,请采取以下额外步骤:

  • 将 ELF 重定位保留在该模块内,以便可以反向应用于 HMAC 的输入。
  • 该模块会对内核为动态影子调用堆栈做出的所有代码补丁进行反转。具体而言,该模块会将从影子调用堆栈推送或弹出的任何指令替换为原先存在的指针身份验证代码 (PAC) 指令。
  • 为该模块停用所有其他代码修补,包括静态密钥和相应的跟踪点,以及供应商钩子。

已知答案的自测

FIPS 140-3 要求涵盖的所有已实现算法在使用之前都必须执行一个已知答案的自测。根据 FIPS 140-3 实现指南 10.3.A,每个算法采用单个测试向量(使用任意受支持的密钥长度)就可以满足加密要求,只要对加密和解密都进行测试即可。

Linux CryptoAPI 采用了算法优先级的概念,其中同一算法的多个实现可以共存(例如,使用特殊加密指令的实现,以及不实现这些指令的 CPU 的回退)。因此,需要测试同一算法的所有实现。这是必要的,因为 Linux CryptoAPI 允许避开基于优先级的选择,而选择优先级更低的算法。

模块中包含的算法

下面列出了 FIPS 140-3 模块中包含的所有算法。这适用于 android12-5.10android13-5.10android13-5.15android14-5.15android14-6.1android15-6.6 内核分支,而我们会适当注明内核版本之间的差异。

算法 实现 是否可批准 定义
aes aes-genericaes-arm64aes-ce、AES 库 明文 AES 分块加密,无操作模式:支持所有密钥大小(128 位、192 位和 256 位)。除库实现之外的所有实现都可以通过模板与某个操作模式组合。
cmac(aes) cmac(模板)、cmac-aes-neoncmac-aes-ce AES-CMAC:支持所有 AES 密钥大小。cmac 模板可以使用 cmac(<aes-impl>)aes 的任何实现组合。其他实现是独立的。
ecb(aes) ecb(模板)、ecb-aes-neonecb-aes-neonbsecb-aes-ce AES-ECB:支持所有 AES 密钥大小。ecb 模板可以使用 ecb(<aes-impl>)aes 的任何实现组合。其他实现是独立的。
cbc(aes) cbc(模板)、cbc-aes-neoncbc-aes-neonbscbc-aes-ce AES-CBC:支持所有 AES 密钥大小。cbc 模板可以使用 ctr(<aes-impl>)aes 的任何实现组合。其他实现是独立的。
cts(cbc(aes)) cts(模板)、cts-cbc-aes-neoncts-cbc-aes-ce AES-CBC-CTS 或 AES-CBC 与密文窃取:使用的惯例是 CS3;最后两个密文块会无条件地交换。支持所有 AES 密钥大小。cts 模板可以使用 cts(<cbc(aes)-impl>)cbc 的任何实现组合。其他实现是独立的。
ctr(aes) ctr(模板)、ctr-aes-neonctr-aes-neonbsctr-aes-ce AES-CTR:支持所有 AES 密钥大小。ctr 模板可以使用 ctr(<aes-impl>)aes 的任何实现组合。其他实现是独立的。
xts(aes) xts(模板)、xts-aes-neonxts-aes-neonbsxts-aes-ce AES-XTS:在内核版本 6.1 及更低版本中,支持所有 AES 密钥大小;在内核版本 6.6 及更高版本中,仅支持 AES-128 和 AES-256。xts 模板可以使用 xts(<ecb(aes)-impl>)ecb(aes) 的任何实现组合。其他实现是独立的。所有实现都会实施 FIPS 要求的弱密钥检查;也就是说,第一部分和第二部分相等的 XTS 密钥会被拒绝。
gcm(aes) gcm(模板)、gcm-aes-ce 1 AES-GCM:支持所有 AES 密钥大小。仅支持 96 位 IV。与此模块中的所有其他 AES 模式一样,调用方负责提供 IV。gcm 模板可以使用 gcm_base(<ctr(aes)-impl>,<ghash-impl>)ctr(aes)ghash 的任何实现组合。其他实现是独立的。
sha1 sha1-genericsha1-ce SHA-1 加密哈希函数
sha224 sha224-genericsha224-arm64sha224-ce SHA-224 加密哈希函数:与 SHA-256 共享代码。
sha256 sha256-genericsha256-arm64sha256-ce、SHA-256 库 SHA-256 加密哈希函数:除了标准 CryptoAPI 接口之外,还会向 SHA-256 提供库接口。此库接口采用不同的实现。
sha384 sha384-genericsha384-arm64sha384-ce SHA-384 加密哈希函数:与 SHA-512 共享代码。
sha512 sha512-genericsha512-arm64sha512-ce SHA-512 加密哈希函数
sha3-224 sha3-224-generic SHA3-224 加密哈希函数。仅存在于内核版本 6.6 及更高版本中。
sha3-256 sha3-256-generic 与上一个相同,但摘要长度为 256 位 (SHA3-256)。所有摘要长度都使用相同的 Keccak 实现。
sha3-384 sha3-384-generic 与上一个相同,但摘要长度为 384 位 (SHA3-384)。所有摘要长度都使用相同的 Keccak 实现。
sha3-512 sha3-512-generic 与上一个相同,但摘要长度为 512 位 (SHA3-512)。所有摘要长度都使用相同的 Keccak 实现。
hmac hmac(模板) HMAC(密钥哈希消息认证码):hmac 模板可以使用 hmac(<sha-alg>)hmac(<sha-impl>) 与任何 SHA 算法或实现组合。
stdrng drbg_pr_hmac_sha1drbg_pr_hmac_sha256drbg_pr_hmac_sha384drbg_pr_hmac_sha512 HMAC_DRBG 已使用具名哈希函数进行实例化,并启用了防预测功能:包含运行状况检查。此接口的使用方会获得自己的 DRBG 实例。
stdrng drbg_nopr_hmac_sha1drbg_nopr_hmac_sha256drbg_nopr_hmac_sha384drbg_nopr_hmac_sha512 drbg_pr_* 算法相同,但停用了防预测功能。与防预测的变体共享代码。在内核版本 5.10 中,优先级最高的 DRBG 为 drbg_nopr_hmac_sha256。在内核版本 5.15 及更高版本中,它为 drbg_pr_hmac_sha512
jitterentropy_rng jitterentropy_rng 抖动 RNG,版本为 2.2.0(内核版本为 6.1 及更低版本)或 3.4.0(内核版本为 6.6 及更高版本)。此接口的使用方会获得自己的 Jitter RNG 实例。它们不会重复使用 DRBG 使用的实例。
xcbc(aes) xcbc-aes-neonxcbc-aes-ce
xctr(aes) xctr-aes-neonxctr-aes-ce 仅存在于内核版本 5.15 及更高版本中。
cbcmac(aes) cbcmac-aes-neoncbcmac-aes-ce
essiv(cbc(aes),sha256) essiv-cbc-aes-sha256-neonessiv-cbc-aes-sha256-ce

从源代码构建模块

对于 Android 14 及更高版本(包括 android-mainline),可以使用以下命令从源代码构建 fips140.ko 模块。

  • 使用 Bazel 构建:

    tools/bazel run //common:fips140_dist
  • 使用 build.sh(旧版)构建:

    BUILD_CONFIG=common/build.config.gki.aarch64.fips140 build/build.sh

这些命令会执行完整构建,包括内核和嵌入了 HMAC-SHA256 摘要内容的 fips140.ko 模块。

最终用户指南

Crypto Officer 指南

要运行内核模块,必须将操作系统限制为单一操作员操作模式。这是由 Android 使用处理器中的内存管理硬件自动处理的。

内核模块不能单独安装;它包含在设备固件中,并在启动时自动加载。内核模块只能在批准的操作模式下运行。

Crypto Officer 可以通过重启设备在任何时候运行自测。

使用方指南

内核模块的使用方是需要使用加密算法的其他内核组件。内核模块在使用算法时不提供额外的逻辑,并且不会将任何参数存储超过执行加密操作所需的时间。

出于 FIPS 合规性目的使用算法时,仅限于使用已批准的算法。为了符合 FIPS 140-3“服务指标”要求,该模块提供了一个 fips140_is_approved_service 函数,用于指示算法是否已被批准。

自测错误

如果自测失败,内核模块会导致内核崩溃,设备将停止启动。如果重新启动设备无法解决问题,则必须将设备启动到恢复模式 (Recovery mode),通过重新刷写设备来解决问题。


  1. 按照预期,该模块的 AES-GCM 实现可以为“经过批准的算法”,而不能为“经过批准的模块”。这类 AES-GCM 实现可以得到验证,但从 FIPS 模块的角度来讲,不能将 AES-GCM 视为经过批准的算法。 这是因为 GCM 的 FIPS 模块要求与不会生成自己的 IV 的 GCM 实现不兼容。