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 构建中

  • 将模块名称添加到 BOARD_VENDOR_RAMDISK_KERNEL_MODULES。 这会将模块复制到 vendor ramdisk。
  • 将模块名称添加到 BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD。 这会将模块名称添加到目标设备上的 modules.load 中。 modules.load 保存着设备启动时由 init 加载的模块列表。

完整性自检

FIPS 140-3 内核模块在模块加载时会获取自身 .code.rodata 区段的 HMAC-SHA256 摘要,并将其与模块中记录的摘要进行比较。 这发生在 Linux 模块加载器已对这些区段进行常用修改(例如 ELF 重定位处理和 CPU 勘误表的备选方案修补)之后。 采取以下附加步骤来确保可以正确再现摘要

  • 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 模板可以与 aes 的任何实现组合,使用 cmac(<aes-impl>)。 其他实现是独立的。
ecb(aes) ecb(模板)、ecb-aes-neonecb-aes-neonbsecb-aes-ce AES-ECB:支持所有 AES 密钥大小。 ecb 模板可以与 aes 的任何实现组合,使用 ecb(<aes-impl>)。 其他实现是独立的。
cbc(aes) cbc(模板)、cbc-aes-neoncbc-aes-neonbscbc-aes-ce AES-CBC:支持所有 AES 密钥大小。 cbc 模板可以与 aes 的任何实现组合,使用 ctr(<aes-impl>)。 其他实现是独立的。
cts(cbc(aes)) cts(模板)、cts-cbc-aes-neoncts-cbc-aes-ce AES-CBC-CTS 或带密文窃取的 AES-CBC:使用的约定是 CS3;最后两个密文块会无条件交换。 支持所有 AES 密钥大小。 cts 模板可以与 cbc 的任何实现组合,使用 cts(<cbc(aes)-impl>)。 其他实现是独立的。
ctr(aes) ctr(模板)、ctr-aes-neonctr-aes-neonbsctr-aes-ce AES-CTR:支持所有 AES 密钥大小。 ctr 模板可以与 aes 的任何实现组合,使用 ctr(<aes-impl>)。 其他实现是独立的。
xts(aes) xts(模板)、xts-aes-neonxts-aes-neonbsxts-aes-ce AES-XTS:在内核版本 6.1 及更低版本中,支持所有 AES 密钥大小;在内核版本 6.6 及更高版本中,仅支持 AES-128 和 AES-256。 xts 模板可以与 ecb(aes) 的任何实现组合,使用 xts(<ecb(aes)-impl>)。 其他实现是独立的。 所有实现都实现了 FIPS 要求的弱密钥检查;也就是说,将拒绝第一个和第二个半部分相等的 XTS 密钥。
gcm(aes) gcm(模板)、gcm-aes-ce 1 AES-GCM:支持所有 AES 密钥大小。 仅支持 96 位 IV。 与此模块中的所有其他 AES 模式一样,调用方负责提供 IV。 gcm 模板可以与 ctr(aes)ghash 的任何实现组合,使用 gcm_base(<ctr(aes)-impl>,<ghash-impl>)。 其他实现是独立的。
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 模板可以与任何 SHA 算法或实现组合,使用 hmac(<sha-alg>)hmac(<sha-impl>)
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 Jitter 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 模块。

最终用户指南

加密专员指南

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

内核模块无法单独安装;它作为设备固件的一部分包含在内,并在启动时自动加载。 它仅在批准的操作模式下运行。

加密专员可以随时通过重启设备来运行自检。

用户指南

内核模块的用户是需要使用加密算法的其他内核组件。 内核模块在使用算法时没有提供额外的逻辑,也没有存储超出执行加密操作所需时间的任何参数。

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

自检错误

如果发生自检失败,内核模块会导致内核崩溃,并且设备不会继续启动。 如果重启设备无法解决问题,则设备必须启动到恢复模式以通过重新刷写设备来纠正问题。


  1. 预计模块的 AES-GCM 实现可以是“算法批准”的,但不是“模块批准”的。 它们可以经过验证,但从 FIPS 模块的角度来看,AES-GCM 不能被视为批准的算法。 这是因为 GCM 的 FIPS 模块要求与不生成自身 IV 的 GCM 实现不兼容。