如何使用Android密钥库提供商存储密钥

时间:2014-09-25 15:28:59

标签: android encryption private-key android-keystore

我正在尝试使用Android 4.3中提供的Android密钥存储区提供程序来安全地保存私钥,然后使用此私钥来加密和解码数据。

我认为到目前为止我已经实现了正确的方法和代码,但我目前面临一个我无法弄清楚的奇怪问题。

我有一个名为KeyStorage的类,用于创建密钥对,加载KeyStore并检索私钥,此类的代码如下:

public class KeyStorage {

public static final String ANDROID_KEYSTORE = "AndroidKeyStore";
private KeyStore keyStore;

public void loadKeyStore() {
    try {
        keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
        keyStore.load(null);
        Enumeration<String> aliases = keyStore.aliases();
        while(aliases.hasMoreElements())
            Log.e("E", "Aliases = " + aliases.nextElement());
    } catch (Exception e) {
        // TODO: Handle this appropriately in your app
        e.printStackTrace();
    }
}

public void generateNewKeyPair(String alias, Context context)
        throws Exception {

    Calendar start = Calendar.getInstance();
    Calendar end = Calendar.getInstance();
    // expires 1 year from today
    end.add(1, Calendar.YEAR);

    KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
            .setAlias(alias)
            .setSubject(new X500Principal("CN=" + alias))
            .setSerialNumber(BigInteger.TEN)
            .setStartDate(start.getTime())
            .setEndDate(end.getTime())
            .build();

    // use the Android keystore
    KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", ANDROID_KEYSTORE);
    gen.initialize(spec);

    // generates the keypair
    gen.generateKeyPair();
}

public PrivateKey loadPrivteKey(String alias) throws Exception {

    if (keyStore.isKeyEntry(alias)) {
        Log.e("E", "Could not find key alias: " + alias);
        return null;
    }

    KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);

    if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
        Log.e("E", " alias: " + alias + " is not a PrivateKey");
        return null;
    }

    return ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
}

然后我有一个名为CredentialStore的类,我尝试使用它。我创建一个名为“MySecureKey”的别名,并尝试基于此创建和存储私钥。因此,您可以看到我尝试基于Alias创建新的密钥对加载密钥库,然后最终检索私钥。但它不起作用。

public class CredentialStore {

public static final String KEY_ALIAS  = "MySecureKey";

private KeyStorage KeyStorage;

public CredentialStore(Activity context){

    keyStorage = new KeyStorage();
    try {
        keyStorage.generateNewKeyPair(KEY_ALIAS, context);
    } catch (Exception e) {
        e.printStackTrace();
    }
    blueBirdKeyStorage.loadKeyStore();

    try {
        keyStorage.loadPrivteKey(KEY_ALIAS);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

我得到的日志如下:

Aliases = MySecureKey
Could not find key alias: MySecureKey

因此,当我检查loadKeyStore方法中的别名时,它看起来就像它在日志中回来一样。但是,当我尝试使用loadKeyStore方法调用它时,我得到日志,说它无法找到密钥“MySecureKey”。

我找不到任何理由,在网上进行的研究证明是没有用的,所以我想知道是否有人知道可能会出现什么问题?

3 个答案:

答案 0 :(得分:1)

为什么它是blueBirdKeyStore:

blueBirdKeyStorage.loadKeyStore();

不应该是:

keyStorage.loadKeyStore();

另外,你还没有使用别名&#39;在你的loadPrivateKey()中:

KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);

现在,我不确定,但是你不应该使用&#39;别名&#39;在这?

答案 1 :(得分:1)

检查密钥是否存在的方法存在缺陷:

if (keyStore.isKeyEntry(alias)) {
    Log.e("E", "Could not find key alias: " + alias);
    return null;
}

根据javadoc .isKeyEntry()有以下行为

  

如果由给定别名标识的条目是由创建的,则返回true   调用setKeyEntry,或通过调用setEntry创建   PrivateKeyEntry或SecretKeyEntry。

但您的密钥不是通过setEntry()创建的。我想如果你只是用

加载密钥
KeyStore.Entry entry = ks.getEntry(alias, null);

它不会为空。

Here is a full example with simple methods on how to use the Android Keystore with pre-M and M Apis.

答案 2 :(得分:0)

loadPrivateKey in your class does not use the "alias" to retrieve the key. It's using another class's constant so I'm not sure what's you're expecting here.