2014-09-25 230 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.