[ 译文原文:Android Keystore System ]
Android Keystore system 允许您将加密密钥存储在容器中,以使其难以从设备中提取。一旦密钥在密钥库中,它们可用于加密操作, key material
保持不可导出。此外,Android Keystore system
还提供了限制密钥何时和如何使用的功能,例如要求密钥使用的用户认证或限制密钥仅在某些加密模式下使用。
Keystore system
被用于 Keychain API
以及在 Android 4.3中引入的AndroidKeystore功能
,本文档介绍了何时以及如何使用 AndroidKeystore
。
Android Keystore系统保护 key material
免受未经授权的使用。首先,Android Keystore通过防止从应用程序进程和Android设备整体上提取 key material
,减轻了 key material
在Android设备之外未经授权的使用。其次,在Android设备上,Android KeyStore指定了密钥在一个应用程序内授权使用,然后在应用程序进程之外被限制使用,从而减轻了Android设备上未经授权而使用 key material
的情况。
保护Android Keystore密钥的 key material
不被抽取的2种措施:
key material
从不进入应用进程。
当应用程序使用Android Keystore获得密钥执行加密操作时,明文,密文和要签名或验证的消息被送到执行密码操作的系统进程。如果应用程序的进程受到威胁,攻击者可能可以使用该应用获取到的密钥,但无法提取 key material
(例如,在Android设备之外使用)。
Key material
被允许绑定到Android设备的安全硬件(例如,可信赖执行环境(TEE)、安全元素(SE))。
当这个功能被用于密钥时,Key material
不会被暴露在安全硬件外。这个功能虽然保证了Key material
不被提取,但是如果Android OS
被破环或者攻击者可以读取设备的内部存储,则其就可以在设备上获取并使用应用程序存储在AndroidKeystore中的密钥。而且重要的一点是,密钥通常是算法、block mod、填充模式、摘要的特殊组合,只有当这个组合被被设备的安全硬件所支持时,这个功能才能被启用,这是关键前提。如果要检查一个密钥是否适用于 Android设备的安全硬件
功能,可以获取密钥的 KeyInfo
对象,并且检查 KeyInfo.isInsideSecurityHardware()
的返回值。
为了避免在Android设备上密钥被未经授权的使用,AndroidKeystore建议应用程序在生成或者获取密钥之前做一次特殊的密钥授权,只有通过验证的用户才能使用密钥,而一旦密钥被应用程序生成或者获取之后,其使用者是谁则不属于AndroidKeystore功能范畴。
支持的密钥的授权分为以下几类:
作为一项额外的安全措施,对于Key material
在安全硬件内的密钥(参见 KeyInfo.isInsideSecurityHardware()),依赖于Android设备的不同,一些密钥的授权(密码组成)可能由安全硬件实施。加密和用户认证授权可能由安全硬件实施,时间的有效期则不太可能由安全硬件实施,因为安全硬件通常不具有独立的安全实时时钟。
密钥的用户认证授权是否由安全硬件实施,可以使用查询:KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()。
如果您想要全系统的凭据时,使用KeyChain,当通过KeyChain API
请求使用任何凭据时,用户可以通过系统提供的UI来选择访问哪些已安装的凭据,这允许几个应用程序在用户的同意下使用相同的凭据集。
使用AndroidKeystore
可以让个别应用程序存储自己的凭据,只有其本身可以访问,同时具有和KeyChain Api
为系统级凭据提供的安全优势。此方法不需要用户交互选择凭据。
要使用此功能,你可以使用属于AndroidKeyStore在Android 4.3(API18)引入的标准类 KeyStore
、KeyPairGenerator
/ KeyGenerator
。
使用 KeyStore.getInstance(type)
方法,AndroidKeyStore
被注册为一个KeyStore
类型,并且作为一个provider
被用于 KeyPairGenerator.getInstance(algorithm, provider)
和 KeyGenerator.getInstance(algorithm, provider)
方法。
/*
* 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();
和上面类似,但是使用的是KeyGenerator
和 KeyGenParameterSpec
。
获取密钥库List
/*
* Load the Android KeyStore instance using the the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration aliases = ks.aliases();
签署和验证数据
sign data
/*
* 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();
verify data
/*
* 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 /密码,指纹)的子集对用户进行身份验证。
当一个密钥被授权只有在用户被认证的情况下才被使用,它被配置为以两种模式之一进行操作:
用户认证授权使用密钥一段时间。
一旦用户解锁了安全锁定屏幕,或者使用该KeyguardManager.createConfirmDeviceCredentialIntent
流程确认了其安全的锁定屏幕凭证,该模式中的所有键都将被授权使用 。授权保持有效的持续时间特定于每个密钥,如在密钥生成或导入期间使用setUserAuthenticationValidityDurationSeconds
所指定的。
如果只是启动了安全锁定屏幕,没有解锁过,则只能生成或者导入密钥(请参阅 KeyguardManager.isDeviceSecure()
)。
如果一旦禁用安全锁定屏幕(重新配置为无,滑动或其他不认证用户的模式)或强制重置(例如由设备管理员处理),这些密钥将永久失效。
用户认证授权 与一个密钥相关联的
特定加密操作。
在这种模式下,涉及这种密钥的每个操作必须由用户单独授权。目前,这种授权的唯一手段是指纹认证: FingerprintManager.authenticate。只有至少有一个指纹被注册才可以生成或导入这些密钥(见 FingerprintManager.hasEnrolledFingerprints)。一旦新的指纹被注册或者所有指纹都被取消注册,这些密钥将永久失效。
Algorithm | Supported (API Levels) | Notes |
---|---|---|
AES/CBC/NoPadding | 23+ | |
AES/CBC/PKCS7Padding | 23+ | |
AES/CTR/NoPadding | 23+ | |
AES/ECB/NoPadding | 23+ | |
AES/ECB/PKCS7Padding | 23+ | |
AES/GCM/NoPadding | 23+ | Only 12-byte long IVs supported. |
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+ |
Algorithm | Supported (API Levels) | Notes |
---|---|---|
AES | 23+ | Supported sizes: 128, 192, 256 |
HmacSHA1 | 23+ |
|
HmacSHA224 | 23+ |
|
HmacSHA256 | 23+ |
|
HmacSHA384 | 23+ |
|
HmacSHA512 | 23+ |
|
Algorithm | Supported (API Levels) | Notes |
---|---|---|
EC | 23+ | Supported key specs: KeyInfo (private key only), ECPublicKeySpec (public key only), X509EncodedKeySpec (public key only) |
RSA | 23+ | Supported key specs: KeyInfo (private key only), RSAPublicKeySpec (public key only), X509EncodedKeySpec (public key only) |
KeyStore supports the same key types as KeyPairGenerator
and KeyGenerator
.
KeyPairGenerator
Algorithm | Supported (API Levels) | Notes |
---|---|---|
DSA | 19–22 | |
EC | 23+ |
Prior to API Level 23, EC keys can be generated using KeyPairGenerator of algorithm “RSA” initialized |
RSA | 18+ |
|
Algorithm | Supported (API Levels) | Notes |
---|---|---|
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+ |
Algorithm | Supported (API Levels) | Notes |
---|---|---|
AES | 23+ | Supported key specs: KeyInfo |
HmacSHA1 | 23+ | Supported key specs: KeyInfo |
HmacSHA224 | 23+ | Supported key specs: KeyInfo |
HmacSHA256 | 23+ | Supported key specs: KeyInfo |
HmacSHA384 | 23+ | Supported key specs: KeyInfo |
HmacSHA512 | 23+ | Supported key specs: KeyInfo |