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
。这会导致模块被复制到供应商 ramdisk。 - 将模块名称添加到
BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
。这会导致模块名称被添加到目标上的modules.load
中。modules.load
保存设备启动时由init
加载的模块列表。
完整性自检
FIPS 140-3 内核模块在模块加载时获取其自己的.code
和.rodata
部分的 HMAC-SHA256 摘要,并将其与模块中记录的摘要进行比较。这是在 Linux 模块加载器已经进行了通常的修改之后发生的,例如 ELF 重定位处理和对这些部分的 CPU 勘误表的替代修补。采取以下附加步骤来确保可以正确再现摘要:
- ELF 重定位保留在模块内部,以便可以反向应用到 HMAC 的输入。
- 该模块的所有其他代码修补均被禁用,包括静态密钥、跟踪点以及供应商挂钩。
已知答案自测
FIPS 140-3 要求涵盖的任何实施的算法在使用之前都必须执行已知答案的自测试。根据FIPS 140-3 实施指南 10.3.A ,只要测试加密和解密,每个算法使用任何受支持的密钥长度的单个测试向量就足以满足密码的要求。
Linux CryptoAPI 有一种算法优先级的概念,其中同一算法的多种实现(例如使用特殊加密指令的实现,以及不实现这些指令的 CPU 的后备)可能共存。因此,需要测试同一算法的所有实现。这是必要的,因为 Linux CryptoAPI 允许回避基于优先级的选择,并选择较低优先级的算法。
模块中包含的算法
FIPS 140-3 模块中包含的所有算法列出如下。这适用于android12-5.10
、 android13-5.10
、 android13-5.15
、 android14-5.15
和android14-6.1
内核分支,但会在适当的地方注明内核版本之间的差异。
算法 | 实施 | 可批准 | 定义 |
---|---|---|---|
aes | aes-generic 、 aes-arm64 、 aes-ce 、 AES 库 | 是的 | 普通 AES 块密码,无操作模式:支持所有密钥大小(128 位、192 位和 256 位)。除库实现之外的所有实现都可以通过模板与操作模式组合。 |
cmac(aes) | cmac (模板)、 cmac-aes-neon 、 cmac-aes-ce | 是的 | AES-CMAC:支持所有 AES 密钥大小。 cmac 模板可以使用cmac(<aes-impl>) 与任何aes 实现组成。其他实现是独立的。 |
ecb(aes) | ecb (模板)、 ecb-aes-neon 、 ecb-aes-neonbs 、 ecb-aes-ce | 是的 | AES-ECB:支持所有 AES 密钥大小。 ecb 模板可以使用ecb(<aes-impl>) 与任何aes 实现组成。其他实现是独立的。 |
cbc(aes) | cbc (模板)、 cbc-aes-neon 、 cbc-aes-neonbs 、 cbc-aes-ce | 是的 | AES-CBC:支持所有 AES 密钥大小。 cbc 模板可以使用ctr(<aes-impl>) 与任何aes 实现组成。其他实现是独立的。 |
cts(cbc(aes)) | cts (模板)、 cts-cbc-aes-neon 、 cts-cbc-aes-ce | 是的 | 带有密文窃取的 AES-CBC-CTS 或 AES-CBC:使用的约定是CS3 ;最后两个密文块无条件交换。支持所有 AES 密钥大小。 cts 模板可以使用cts(<cbc(aes)-impl>) 与cbc 的任何实现组成。其他实现是独立的。 |
ctr(aes) | ctr (模板)、 ctr-aes-neon 、 ctr-aes-neonbs 、 ctr-aes-ce | 是的 | AES-CTR:支持所有 AES 密钥大小。 ctr 模板可以使用ctr(<aes-impl>) 与任何aes 实现组成。其他实现是独立的。 |
xts(aes) | xts (模板)、 xts-aes-neon 、 xts-aes-neonbs 、 xts-aes-ce | 是的 | AES-XTS:支持所有 AES 密钥大小。 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-generic , sha1-ce | 是的 | SHA-1 加密哈希函数 |
sha224 | sha224-generic 、 sha224-arm64 、 sha224-ce | 是的 | SHA-224 加密哈希函数:代码与 SHA-256 共享。 |
sha256 | sha256-generic 、 sha256-arm64 、 sha256-ce 、 SHA-256 库 | 是的 | SHA-256 加密哈希函数:除了传统的 CryptoAPI 接口之外,还为 SHA-256 提供了库接口。该库接口使用不同的实现。 |
sha384 | sha384-generic 、 sha384-arm64 、 sha384-ce | 是的 | SHA-384 加密哈希函数:代码与 SHA-512 共享。 |
sha512 | sha512-generic 、 sha512-arm64 、 sha512-ce | 是的 | SHA-512 加密哈希函数 |
hmac | hmac (模板) | 是的 | HMAC(密钥哈希消息身份验证代码): hmac 模板可以使用hmac(<sha-alg>) 或hmac(<sha-impl>) 与任何 SHA 算法或实现组成。 |
stdrng | drbg_pr_hmac_sha1 、 drbg_pr_hmac_sha256 、 drbg_pr_hmac_sha384 、 drbg_pr_hmac_sha512 | 是的 | HMAC_DRBG 使用指定的哈希函数实例化并启用预测阻力:包括运行状况检查。此接口的用户获得自己的 DRBG 实例。 |
stdrng | drbg_nopr_hmac_sha1 、 drbg_nopr_hmac_sha256 、 drbg_nopr_hmac_sha384 、 drbg_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 版:此接口的用户可以获得自己的 Jitter RNG 实例。他们不会重用 DRBG 使用的实例。 |
xcbc(aes) | xcbc-aes-neon , xcbc-aes-ce | 不 | |
xctr(aes) | xctr-aes-neon , xctr-aes-ce | 不 | 仅存在于内核版本 5.15 及更高版本中。 |
cbcmac(aes) | cbcmac-aes-neon , cbcmac-aes-ce | 不 | |
essiv(cbc(aes),sha256) | essiv-cbc-aes-sha256-neon , essiv-cbc-aes-sha256-ce | 不 |
从源代码构建模块
在 Android 14 及更高版本(包括android-mainline
)上,可以使用以下命令从 GKI 内核源构建fips140.ko
模块:
tools/bazel run //common:fips140_dist
在 Android 13 及更低版本上,可以使用以下命令从 GKI 内核源构建fips140.ko
模块:
BUILD_CONFIG=common/build.config.gki.aarch64.fips140 build/build.sh
这将使用内核和fips140.ko
模块执行完整构建,并嵌入其内容的正确 HMAC-SHA256 摘要。
在 Android 14 及更高版本中,使用以下命令使用Bazel而不是build/build.sh
进行构建:
tools/bazel run //common:fips140_dist
最终用户指导
加密官员指导
为了操作内核模块,操作系统必须限制为单一操作员操作模式。这是由 Android 使用处理器中的内存管理硬件自动处理的。
内核模块不能单独安装;它作为设备固件的一部分包含在启动时自动加载。它仅在批准的操作模式下运行。
加密官可以通过重新启动设备随时运行自检。
用户指导
内核模块的使用者是需要使用密码算法的其他内核组件。内核模块在算法的使用中不提供额外的逻辑,并且在执行加密操作所需的时间之外不存储任何参数。
出于 FIPS 合规性目的而使用的算法仅限于经批准的算法。为了满足 FIPS 140-3“服务指示器”要求,该模块提供了函数fips140_is_approved_service
来指示算法是否获得批准。
自检错误
如果自检失败,内核模块会导致内核崩溃,并且设备不会继续启动。如果重新启动设备无法解决问题,则设备必须启动到恢复模式,以通过重新刷新设备来纠正问题。
预计该模块的 AES-GCM 实现可以“算法批准”,但不能“模块批准”。它们可以被验证,但从 FIPS 模块的角度来看,AES-GCM 不能被视为经过批准的算法。这是因为 GCM 的 FIPS 模块要求与不生成自己的 IV 的 GCM 实现不兼容。 ↩