2014-09-25 132 views
8

我想使用Android 4.3中可用的Android密钥存储提供程序来安全地保存私钥,然后使用此私钥来加密和解码数据。如何使用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”的别名,并尝试在此基础上创建和存储私钥。正如你所看到的,我尝试基于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”。

我找不到任何理由和网上研究已证明无果,所以我想知道如果有人有任何想法可能会出错?

+4

1.您生成KeyPair并且不使用它。您的generateNewKeyPair方法不会返回任何内容。 2.您不会将任何内容保存到KeyStore以稍后加载它。请参考KeyStore使用示例。它可以帮助你http://developer.android.com/samples/BasicAndroidKeyStore/index.html – 2014-09-25 16:25:48

+0

@AlexanderZhak尽管许多upvotes,你的评论是错误的:检查官方文档:https://developer.android.com/ training/articles/keystore.html#UserAuthentication这就是您如何使用Android Keystore--如果您将KeyFactory与Android Keystore实例一起使用,则不需要明确地放置该密钥。 – for3st 2016-09-21 11:51:22

回答

1

为什么blueBirdKeyStore在:

blueBirdKeyStorage.loadKeyStore(); 

它不应该是:

keyStorage.loadKeyStore(); 

此外,你还没有使用的 '别名' 在你loadPrivateKey():

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

现在,我不确定,但是不应该在此使用'别名'吗?

0

你的类中的loadPrivateKey不使用“别名”来检索密钥。它使用了另一个课程的常量,所以我不确定你在这里期待什么。

+0

不,它使用正确的别名。 – for3st 2016-09-22 08:08:01

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.