Android密钥库系统KeyStore

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android密钥库系统KeyStore相关的知识,希望对你有一定的参考价值。

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

密钥库系统并不是让程序直接进行存储程序的私密信息的,比如说用户账号密码,其提供了一个密钥安全容器,保护密钥材料免遭未经授权的使用,一个应用程序可以在密钥库中存储多个密钥并且只允许应用自身访问,应用程序可以在密钥库系统中生成,存储,获取存储其中的公钥或者私钥,因此可使用密钥库系统中的密钥来进行数据的加密。

密钥库系统由 KeyChain API 以及在 Android 4.3(API 级别 18)中引入的 Android 密钥库提供程序功能使用。

安卓系统提供了下面几种KeyStore类型:

各种类型的详细说明可以参考: https://developer.android.com/openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyStore

先创建一个Activity,自定义布局从页面上来实现几种功能

效果图:

说明:
1.输入框输入要增加的密钥的名称,点击添加按钮进行添加一个新密钥;
2.输入框输入要删除的密钥的名称,点击删除按钮进行删除一个已存在的密钥;
3.这里指定了数据明文,点击密钥列表中的item可选中指定的密钥,用于使用密钥进行加密和解密,选中密钥后,可点击加密按钮进行加密,加密后可点击解密按钮进行解密;
4.密钥列表显示当前应用在密钥库系统中生成了的密钥,长按可删除密钥;

MainActivity

密钥库系统工具类

生成密钥时使用X500Principal指定了自签署证书,参数分别代表
CN:通用名称
O:组织
OU:组织单元
C:国家
并且指定密钥的有效时间,并且指定了用于生成密钥对的自签名证书的序列号。

这里指定了通过密钥库系统生成RSA密钥。

先从密钥库中取出密钥,使用公钥进行加密

先从密钥库中取出密钥,使用私钥进行解密

使用密钥对数据签名,签名算法须与秘钥算法保持一致。

使用密钥对数据进行签名认证,签名算法须与秘钥算法保持一致。

密钥库支持的算法可参考: https://developer.android.com/training/articles/keystore

demo链接: https://github.com/samlss/KeyStore

Android KeyStore - 密钥并不总是持久的

【中文标题】Android KeyStore - 密钥并不总是持久的【英文标题】:Android KeyStore - keys not always persisted 【发布时间】:2016-06-20 10:30:56 【问题描述】:

在我的应用程序中,我们使用 RSA 密钥,该应用程序在首次启动时生成(使用 android 密钥库)。由于未知原因,该应用未能从某些设备上的密钥库中检索到密钥。我检查了日志,但找不到此错误与特定操作系统版本或特定设备型号之间的关联。另外,我确定该应用程序仅在创建密钥后才尝试读取它。所以 - 我的问题是:据我所知,android 密钥库应该是持久的。什么会导致这样的错误?

下面是相关的代码示例。

密钥生成:

try 
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", keyStore.getProvider());

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
            KeyGenParameterSpec spec;
            spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT| KeyProperties.PURPOSE_SIGN| KeyProperties.PURPOSE_VERIFY)
                    .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
                    .setKeySize(2048)
                    .build();

            generator.initialize(spec);
         else 
            Calendar start = new GregorianCalendar();
            Calendar end = new GregorianCalendar();
            end.add(Calendar.YEAR, 500);

            KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
                    .setAlias(alias)
                    .setSubject(new X500Principal("CN="+ subject))
                    .setSerialNumber(BigInteger.valueOf(new Random().nextInt(Integer.MAX_VALUE)))
                    .setStartDate(start.getTime())
                    .setEndDate(end.getTime())
                    .setKeySize(2048)
                    .build();

            generator.initialize(spec);
        
        return generator.generateKeyPair();
     catch (Exception e) 
        logger.warn("Failed to create private key in store", e);
        return null;
    

使用以下代码初始化密钥库本身:

KeyStore androidKeyStore = KeyStore.getInstance("AndroidKeyStore");
            androidKeyStore.load(null);
            return androidKeyStore;

我们使用以下代码来检索密钥,错误是在某些设备上密钥库返回 null:

        try 
        Key key = keyStore.getKey(alias, null);

        if (key == null)
            logger.warn("Key not found in key store");
            return null;
        

        if (key instanceof PrivateKey) 
            // Get certificate of public key
            Certificate cert = keyStore.getCertificate(alias);

            // Get public key
            PublicKey publicKey = cert.getPublicKey();

            // Return a key pair
            return new KeyPair(publicKey, (PrivateKey) key);
         else 
            logger.warn("Key found, but not from current type. type found: " + key.getClass().getSimpleName());
        
        return null;
    catch (Exception e)
        logger.warn("Failed to get private key in store", e);
        return null;
    

谢谢, 奥马尔

【问题讨论】:

【参考方案1】:

以防万一有人遇到同样的问题: 我发现适用于 android 的 Azure Active Directory 库遭受类似的issue 的影响,并且通过阅读我看到它们链接到two issues 的代码类似于这个问题和我们遇到的另一个问题。因此,我打算使用基于 p12 文件的密钥库,存储在应用程序私有存储中。

【讨论】:

【参考方案2】:

您的密钥是在生成后立即丢失还是在一段时间后丢失?看看这个问题AndroidKeyStore getEntry is consistently failing after certain point 链接到这篇很棒的文章:http://doridori.github.io/android-security-the-forgetful-keystore/

这个故事的寓意是,如果您使用 AndroidKeyStore,请准备好在某些情况下丢失您的密钥!

【讨论】:

是的,我也想通了。这就是我停止使用 Android KeyStore 的原因。谢谢!

以上是关于Android密钥库系统KeyStore的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Mac 上找到适用于 android 的密钥库

Android 硬件支持的密钥库中的 PublicKey 有多安全?

Android KeyStore - 密钥并不总是持久的

什么是 android 中的生产密钥库,如何获得生产密钥库的路径?

Android 签名密钥库

在 Android 密钥库中安全地存储密钥