利用 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+