26
2017
09

Android Keystore System

Android Keystore system 允许您将加密密钥存储在容器中,以使其难以从设备中提取。一旦密钥在密钥库中,它们可用于加密操作, key material保持不可导出。此外,Android Keystore system还提供了限制密钥何时和如何使用的功能,例如要求密钥使用的用户认证或限制密钥仅在某些加密模式下使用。

Keystore system 被用于 Keychain API 以及在 Android 4.3中引入的AndroidKeystore功能 ,本文档介绍了何时以及如何使用 AndroidKeystore

Security 功能


Android Keystore系统保护 key material 免受未经授权的使用。首先,Android Keystore通过防止从应用程序进程和Android设备整体上提取 key material,减轻了 key material 在Android设备之外未经授权的使用。其次,在Android设备上,Android KeyStore指定了密钥在一个应用程序内授权使用,然后在应用程序进程之外被限制使用,从而减轻了Android设备上未经授权而使用 key material的情况。

预防 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功能范畴。

支持的密钥的授权分为以下几类:

  • 密码学:授权密钥算法,操作或目的(加密,解密,签名,验证),填充方案,块模式,可以使用密钥的摘要
  • 时间有效性间隔:密钥被授权使用的时间间隔
  • 用户认证:该密钥只能在用户最近得到认证后才能使用,参考 Requiring User Authentication For Key Use.

作为一项额外的安全措施,对于Key material在安全硬件内的密钥(参见 KeyInfo.isInsideSecurityHardware()),依赖于Android设备的不同,一些密钥的授权(密码组成)可能由安全硬件实施。加密和用户认证授权可能由安全硬件实施,时间的有效期则不太可能由安全硬件实施,因为安全硬件通常不具有独立的安全实时时钟。
密钥的用户认证授权是否由安全硬件实施,可以使用查询:KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()

Keychain 和 Android Keystore 比较


如果您想要全系统的凭据时,使用KeyChain,当通过KeyChain API请求使用任何凭据时,用户可以通过系统提供的UI来选择访问哪些已安装的凭据,这允许几个应用程序在用户的同意下使用相同的凭据集。

使用AndroidKeystore可以让个别应用程序存储自己的凭据,只有其本身可以访问,同时具有和KeyChain Api为系统级凭据提供的安全优势。此方法不需要用户交互选择凭据。

Android Keystore 的使用


要使用此功能,你可以使用属于AndroidKeyStore在Android 4.3(API18)引入的标准类 KeyStoreKeyPairGenerator / KeyGenerator
使用 KeyStore.getInstance(type)方法,AndroidKeyStore被注册为一个KeyStore类型,并且作为一个provider被用于 KeyPairGenerator.getInstance(algorithm, provider)KeyGenerator.getInstance(algorithm, provider) 方法。

在AndroidKeyStore中生成一个新的 Private Key

/*
 * 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();

在AndroidKeyStore中生成一个新的 Secret Key

和上面类似,但是使用的是KeyGeneratorKeyGenParameterSpec

使用密钥库

获取密钥库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<String> 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 /密码,指纹)的子集对用户进行身份验证。

当一个密钥被授权只有在用户被认证的情况下才被使用,它被配置为以两种模式之一进行操作:

  1. 用户认证授权使用密钥一段时间。

    一旦用户解锁了安全锁定屏幕,或者使用该KeyguardManager.createConfirmDeviceCredentialIntent 流程确认了其安全的锁定屏幕凭证,该模式中的所有键都将被授权使用 。授权保持有效的持续时间特定于每个密钥,如在密钥生成或导入期间使用setUserAuthenticationValidityDurationSeconds所指定的。

    如果只是启动了安全锁定屏幕,没有解锁过,则只能生成或者导入密钥(请参阅 KeyguardManager.isDeviceSecure())。

    如果一旦禁用安全锁定屏幕(重新配置为无,滑动或其他不认证用户的模式)或强制重置(例如由设备管理员处理),这些密钥将永久失效。

  2. 用户认证授权 与一个密钥相关联的 特定加密操作。

    在这种模式下,涉及这种密钥的每个操作必须由用户单独授权。目前,这种授权的唯一手段是指纹认证: FingerprintManager.authenticate。只有至少有一个指纹被注册才可以生成或导入这些密钥(见 FingerprintManager.hasEnrolledFingerprints)。一旦新的指纹被注册或者所有指纹都被取消注册,这些密钥将永久失效。

AndroidKeyStore支持的算法


  • Cipher
  • KeyGenerator
  • KeyFactory
  • KeyPairGenerator
  • Signature
  • SecretKeyFactory

Cipher

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+

KeyGenerator

Algorithm Supported (API Levels) Notes
AES 23+ Supported sizes: 128, 192, 256
HmacSHA1 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 160
HmacSHA224 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 224
HmacSHA256 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 256
HmacSHA384 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 384
HmacSHA512 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 512

KeyFactory

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

KeyStore supports the same key types as KeyPairGenerator and KeyGenerator.

KeyPairGenerator

Algorithm Supported (API Levels) Notes
DSA 19–22
EC 23+
  • Supported sizes: 224, 256, 384, 521
  • Supported named curves: P-224 (secp224r1), P-256 (aka secp256r1 and prime256v1), P-384 (aka secp384r1), P-521 (aka secp521r1)

Prior to API Level 23, EC keys can be generated using KeyPairGenerator of algorithm “RSA” initialized KeyPairGeneratorSpec whose key type is set to “EC” using setKeyType(String). EC curve name cannot be specified using this method – a NIST P-curve is automatically chosen based on the requested key size.

RSA 18+
  • Supported sizes: 512, 768, 1024, 2048, 3072, 4096
  • Supported public exponents: 3, 65537
  • Default public exponent: 65537

Signature

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+

SecretKeyFactory

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
上一篇:渐变圆环进度条实现 下一篇:#字节流转文件