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

8
我正试图使用Android 4.3中提供的Android密钥存储提供程序来安全地保存私钥,然后使用此私钥来加密和解密数据。
我认为我已经正确实现了这个过程和代码,但是我目前遇到一个奇怪的问题,我无法解决。
我有一个名为KeyStorage的类,用于创建密钥对、加载密钥库和检索私钥,该类的代码如下:
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"的别名,并尝试基于此创建和存储私钥。因此,您可以看到我尝试基于别名创建新的密钥对,加载密钥库,最后检索私钥。但是它没有起作用。

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”。

我找不到任何原因,并且在线研究也没有结果,所以我想知道是否有人知道可能出了什么问题?


4
  1. 你生成了密钥对却没有运用它。你的generateNewKeyPair方法并没有返回任何东西。
  2. 你没有将任何内容保存到KeyStore中以便以后加载。请参考关于KeyStore使用的示例,它可能会对你有所帮助。http://developer.android.com/samples/BasicAndroidKeyStore/index.html
- Alexander Zhak
@AlexanderZhak 尽管您的评论获得了许多赞,但是它是错误的:请查看官方文档:https://developer.android.com/training/articles/keystore.html#UserAuthentication 这就是您如何使用Android Keystore - 如果您使用带有Android Keystore实例的KeyFactory,则无需显式放置密钥。 - Patrick
3个回答

1
您用于检查键是否存在的方法存在缺陷:
if (keyStore.isKeyEntry(alias)) {
    Log.e("E", "Could not find key alias: " + alias);
    return null;
}

根据 javadoc,.isKeyEntry() 的行为如下:

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

但是您的密钥不是通过 setEntry() 创建的。我猜想如果只是加载密钥,那么……
KeyStore.Entry entry = ks.getEntry(alias, null);

it won't be null. 不会是空的。

这里有一个完整的示例,介绍如何使用Android Keystore与pre-M和M Apis一起使用简单方法。


1
为什么 blueBirdKeyStore 在这里?
blueBirdKeyStorage.loadKeyStore();

"不应该是这样吗:"
keyStorage.loadKeyStore();

此外,在loadPrivateKey()中你没有使用“alias”:
KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);

现在,我不确定,但是你应该在这里使用“别名”吧?

0
你的类中的loadPrivateKey方法没有使用“alias”来检索密钥。它正在使用另一个类的常量,所以我不确定你在这里期望什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接