利用 Android 密钥库系统,您可以在容器中存储加密密钥,从而提高从设备中提取密钥的难度。在密钥进入密钥库后,可以将它们用于加密操作,而密钥材料仍不可导出。此外,它提供了密钥使用的时间和方式限制措施,例如要求进行用户身份验证才能使用密钥,或者限制为只能在某些加密模式中使用。如需了解详情,请参阅安全功能部分。

密钥库系统由 Android 4.0(API 级别 14)中引入的 Security 库使用。本文介绍何时以及如何使用 Android 密钥库提供程序。

安全功能

Android 密钥库系统可以保护密钥材料免遭未经授权的使用。首先,Android 密钥库可以防止从应用进程和 Android 设备中整体提取密钥材料,从而避免了在 Android 设备之外以未经授权的方式使用密钥材料。其次,Android 密钥库可以让应用指定密钥的授权使用方式,并在应用进程之外强制实施这些限制,从而避免了在 Android 设备上以未经授权的方式使用密钥材料。

提取防范

Android 密钥库密钥使用两项安全措施来避免密钥材料被提取:密钥材料永不进入应用进程。通过 Android 密钥库密钥执行加密操作时,应用会在后台将待签署或验证的明文、密文和消息馈送到执行加密操作的系统进程。如果应用进程受到,者也许能使用应用密钥,但无法提取密钥材料(例如,在 Android 设备以外使用)。

您可以将密钥材料绑定至 Android 设备的安全硬件,例如可信执行环境 (TEE) 和安全元件 (SE)。为密钥启用此功能时,其密钥材料永远不会暴露于安全硬件之外。如果 Android 操作系统受到或者者可以读取设备内部存储空间,者也许能在 Android 设备上使用任意应用的 Android 密钥库,但无法从设备上提取这些数据。只有设备的安全硬件支持密钥算法、分块模式、填充方案和密钥有权配合使用的摘要的特定组合时,才可启用此功能。要检查是否为密钥启用了此功能,请获取密钥的

硬件安全模块

运行 Android 9(API 级别 28)或更高版本的受支持设备可拥有 StrongBox Keymaster,它是位于硬件安全模块中的 Keymaster HAL 的一种实现。该模块包含以下组成部分:

自己的 CPU。

安全存储空间。

真实随机数生成器。

可抵御软件包篡改和未经授权旁加载应用的附加机制。

检查存储在 StrongBox Keymaster 中的密钥时,系统会通过可信执行环境 (TEE) 证实密钥的完整性。

为支持低能耗的 StrongBox 实现,为一部分算法和密钥大小提供了支持:

RSA 2048

AES 128 和 256

ECDSA P-256

HMAC-SHA256(支持 8-64 字节密钥大小,含首末值)

Triple DES 168

使用 KeyStore 类生成或导入密钥时,您需要通过将 true 传递给 setIsStrongBoxBacked() 方法,指示在 StrongBox Keymaster 中存储密钥的偏好。

注意:如果 StrongBox Keymaster 不适用于密钥的给定算法和关联的密钥大小,框架会抛出 StrongBoxUnavailableException。

密钥使用授权

为了避免在 Android 设备上以未经授权的方式使用密钥,在生成或导入密钥时,Android 密钥库会让应用指定密钥的授权使用方式。一旦生成或导入密钥,其授权将无法更改。然后,每次使用密钥时,都会由 Android 密钥库强制执行授权。这是一项高级安全功能,通常仅用于有以下要求的情形:在生成/导入密钥后(而不是之前或当中),应用进程受到不会导致密钥以未经授权的方式使用。

支持的密钥使用授权分为以下几类:加密:授权密钥算法、运算或目的(加密、解密、签署、验证)、填充方案、分块模式以及可与密钥搭配使用的摘要;

时间有效性间隔:密钥获得使用授权的时间间隔;

用户身份验证:密钥只能在用户最近进行身份验证时使用。请参阅要求进行用户身份验证才能使用密钥。

作为一项额外的安全措施,对于密钥材料位于安全硬件内的密钥(请参阅

选择密钥链或 Android 密钥库提供程序

如果您需要系统全局凭据,请使用

使用 Android 密钥库提供程序让各个应用存储自己的凭据,并且只允许应用自身访问。通过这种方式,应用可以管理仅可供自身使用的凭据,同时所提供的安全优势还可媲美

使用 Android 密钥库提供程序

如需使用此功能,请使用标准的 AndroidKeyStore 提供程序。

生成新私钥

生成新的

Security 库为生成有效的对称密钥提供了默认实现,如以下代码段所示:

Kotlin
// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)Java
// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

或者,您也可以稍后使用

Kotlin
/*
* Generate a new EC key pair entry in the Android Keystore by
* using the KeyPairGenerator API. The private key can only be
* used for signing or verification and only with SHA-256 or
* SHA-512 as the message digest.
*/
val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC,
"AndroidKeyStore"
)
val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).run {
setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
build()
}
kpg.initialize(parameterSpec)
val kp = kpg.generateKeyPair()Java
/*
* Generate a new EC key pair entry in the Android Keystore by
* using the KeyPairGenerator API. The private key can only be
* used for signing or verification and only with SHA-256 or
* SHA-512 as the message digest.
*/
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build());
KeyPair kp = kpg.generateKeyPair();

生成新密钥

如需生成密钥,请按照与生成新私钥相同的流程进行操作。在每种情况下,您都需要使用 Security 库。

更安全地导入加密密钥

借助 Android 9(API 级别 28)及更高版本,您能够利用 ASN.1 编码密钥格式将已加密密钥安全导入密钥库。Keymaster 随后会在密钥库中将密钥解密,因此密钥的内容永远不会以明文形式出现在设备的主机内存中。此过程提高了密钥解密的安全性。

注意:只有搭载 Keymaster 4 或更高版本的设备才支持该功能。

如需支持以安全方式将已加密密钥导入密钥库,请完成以下步骤:

生成目的为 PURPOSE_WRAP_KEY 的密钥对。建议也为该密钥对添加认证。

在您信任的服务器或机器上,生成 SecureKeyWrapper 应包含的 ASN.1 消息。

该封装容器包含以下架构:

KeyDescription ::= SEQUENCE {
keyFormat INTEGER,
authorizationList AuthorizationList
}
SecureKeyWrapper ::= SEQUENCE {
wrapperFormatVersion INTEGER,
encryptedTransportKey OCTET_STRING,
initializationVector OCTET_STRING,
keyDescription KeyDescription,
secureKey OCTET_STRING,
tag OCTET_STRING
}

创建 WrappedKeyEntry 对象,传入字节数组形式的 ASN.1 消息。

将该 WrappedKeyEntry 对象传入接受 Keystore.Entry 对象的 setEntry() 的重载。

使用密钥库条目

AndroidKeyStore 提供程序的使用通过所有标准

列出条目

通过调用

Kotlin
/*
* Load the Android KeyStore instance using the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply {
load(null)
}
val aliases: Enumeration = ks.aliases()Java
/*
* Load the Android KeyStore instance using the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration aliases = ks.aliases();
对数据进行签名和验证
Kotlin
/*
* Use a PrivateKey in the KeyStore to create a signature over
* some data.
*/
val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply {
load(null)
}
val entry: KeyStore.Entry = ks.getEntry(alias, null)
if (entry !is KeyStore.PrivateKeyEntry) {
Log.w(TAG, "Not an instance of a PrivateKeyEntry")
return null
}
val signature: ByteArray = Signature.getInstance("SHA256withECDSA").run {
initSign(entry.privateKey)
update(data)
sign()
}Java
/*
* Use a PrivateKey in the KeyStore to create a signature over
* some data.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof PrivateKeyEntry)) {
Log.w(TAG, "Not an instance of a PrivateKeyEntry");
return null;
}
Signature s = Signature.getInstance("SHA256withECDSA");
s.initSign(((PrivateKeyEntry) entry).getPrivateKey());
s.update(data);
byte[] signature = s.sign();

类似地,请使用

Kotlin
/*
* Verify a signature previously made by a PrivateKey in our
* KeyStore. This uses the X.509 certificate attached to our
* private key in the KeyStore to validate a previously
* generated signature.
*/
val ks = KeyStore.getInstance("AndroidKeyStore").apply {
load(null)
}
val entry = ks.getEntry(alias, null) as? KeyStore.PrivateKeyEntry
if (entry == null) {
Log.w(TAG, "Not an instance of a PrivateKeyEntry")
return false
}
val valid: Boolean = Signature.getInstance("SHA256withECDSA").run {
initVerify(entry.certificate)
update(data)
verify(signature)
}Java
/*
* Verify a signature previously made by a PrivateKey in our
* KeyStore. This uses the X.509 certificate attached to our
* private key in the KeyStore to validate a previously
* generated signature.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof PrivateKeyEntry)) {
Log.w(TAG, "Not an instance of a PrivateKeyEntry");
return false;
}
Signature s = Signature.getInstance("SHA256withECDSA");
s.initVerify(((PrivateKeyEntry) entry).getCertificate());
s.update(data);
boolean valid = s.verify(signature);

要求进行用户身份验证才能使用密钥

生成密钥或将密钥导入到 AndroidKeyStore 时,您可以指定仅授权经过身份验证的用户使用密钥。用户使用安全锁定屏幕凭据(图案/PIN 码/密码、指纹)的子集进行身份验证。

这是一项高级安全功能,通常仅用于有以下要求的情形:在生成/导入密钥后(而不是之前或当中),应用进程受到不会导致密钥被未经身份验证的用户使用。

如果仅授权经过身份验证的用户使用密钥,可将密钥配置为以下列两种模式之一运行:经过身份验证的用户可以在一段时间内使用密钥。在用户解锁安全锁定屏幕或使用 setUserAuthenticationValidityDurationSeconds 在密钥生成或导入时指定。此类密钥只有在启用了安全锁定屏幕的情况下才能生成或导入(请参阅

用户身份验证会授权与某一密钥关联的特定加密操作。在此模式中,涉及此类密钥的每个操作都必须由用户单独授权。目前,此类授权的唯一方式是指纹身份验证:

支持的算法

Cipher

算法

提供支持的 API 级别

备注

AES/CBC/NoPadding

23+

AES/CBC/PKCS7Padding

23+

AES/CTR/NoPadding

23+

AES/ECB/NoPadding

23+

AES/ECB/PKCS7Padding

23+

AES/GCM/NoPadding

23+

仅支持 12 字节长的 IV。

RSA/ECB/NoPadding

18+

RSA/ECB/PKCS1Padding

18+

RSA/ECB/OAEPWithSHA-1AndMGF1Padding

23+

RSA/ECB/OAEPWithSHA-224AndMGF1Padding

23+

RSA/ECB/OAEPWithSHA-256AndMGF1Padding

23+

RSA/ECB/OAEPWithSHA-384AndMGF1Padding

23+

RSA/ECB/OAEPWithSHA-512AndMGF1Padding

23+

RSA/ECB/OAEPPadding

23+

KeyGenerator

算法

提供支持的 API 级别

备注

AES

23+

支持的大小:128、192、256

HmacSHA1

23+

支持的大小:8-1024(含),必须是 8 的倍数

默认大小:160

HmacSHA224

23+

支持的大小:8-1024(含),必须是 8 的倍数

默认大小:224

HmacSHA256

23+

支持的大小:8-1024(含),必须是 8 的倍数

默认大小:256

HmacSHA384

23+

支持的大小:8-1024(含),必须是 8 的倍数

默认大小:384

HmacSHA512

23+

支持的大小:8-1024(含),必须是 8 的倍数

默认大小:512

KeyFactory

KeyStoreKeyStore 支持的密钥类型与 KeyPairGenerator 和 KeyGenerator 支持的相同。

KeyPairGenerator

算法

提供支持的 API 级别

备注

DSA

19-22

EC

23+

支持的大小:224、256、384、521

支持的命名曲线:P-224 (secp224r1)、P-256(又称为 secp256r1 和 prime256v1)、P-384(又称为 secp384r1)、P-521(又称为 secp521r1)

在 API 级别 23 前,EC 密钥可使用经“RSA”算法初始化的

RSA

18+

支持的大小:512、768、1024、2048、3072、4096

支持的公开指数:3、65537

默认公开指数:65537

Mac

算法

提供支持的 API 级别

备注

HmacSHA1

23+

HmacSHA224

23+

HmacSHA256

23+

HmacSHA384

23+

HmacSHA512

23+

Signature

算法

提供支持的 API 级别

备注

MD5withRSA

18+

NONEwithECDSA

23+

NONEwithRSA

18+

SHA1withDSA

19-22

SHA1withECDSA

19+

SHA1withRSA

18+

SHA1withRSA/PSS

23+

SHA224withDSA

20-22

SHA224withECDSA

20+

SHA224withRSA

20+

SHA224withRSA/PSS

23+

SHA256withDSA

19-22

SHA256withECDSA

19+

SHA256withRSA

18+

SHA256withRSA/PSS

23+

SHA384withDSA

19-22

SHA384withECDSA

19+

SHA384withRSA

18+

SHA384withRSA/PSS

23+

SHA512withDSA

19-22

SHA512withECDSA

19+

SHA512withRSA

18+

SHA512withRSA/PSS

23+

SecretKeyFactory

算法

提供支持的 API 级别

备注

AES

23+

支持的密钥规范:

HmacSHA1

23+

支持的密钥规范:

HmacSHA224

23+

支持的密钥规范:

HmacSHA256

23+

支持的密钥规范:

HmacSHA384

23+

支持的密钥规范:

HmacSHA512

23+

支持的密钥规范: