从AndroidKeystore加载私钥时出现问题

时间:2016-01-18 12:00:06

标签: android

Android提供了一个API,用于为加密操作生成密钥,并在Androids Systemkeystore中存储/加载它们。

我在KeyGenParameterSpec类的JavaDocs中跟随了Example。密钥的生成,存储和加载工作。但是如果我尝试使用密钥,则密码对象的init()调用将失败。我调试了一下,我可以看到,加载的Key的类型为“android.security.keystore.AndroidKeyStoreSecretKey”。此实现可防止密钥的byte []被暴露。我出于安全原因理解这一点,但如果我想使用密钥,我必须获得关键内容。所以,我必须做错事。也许,在Android中使用加密操作还有另一种方法吗?或者Key的加载代码是错误的?

以下是代码:

KeyGenerator keyGenerator = KeyGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");

KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("demo-alias", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
builder.setKeySize(256);
builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC);
builder.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
keyGenerator.init(builder.build());

// this key will work with a CipherObject ...
SecretKey key = keyGenerator.generateKey();

// Load the key from the Keystore
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);

// This key will not work with the Cipher Object
SecretKey notWorkingKey = (SecretKey) keyStore.getKey("demo-alias", null);

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// That call fails
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[]{87, 99, -94, 23, -17, 26, 84, -117, 59, -59, 25, -88, -66, 86, -42, 78}));

byte[] crypted = cipher.doFinal("testdata".getBytes());

密码的init(...)失败,出现以下异常:

java.lang.NullPointerException: Attempt to get length of null array
    at com.android.org.bouncycastle.crypto.params.KeyParameter.<init>(KeyParameter.java:13)
    at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineInit(BaseBlockCipher.java:557)
    at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:608)
    at javax.crypto.Cipher.tryCombinations(Cipher.java:532)
    at javax.crypto.Cipher.getSpi(Cipher.java:437)
    at javax.crypto.Cipher.init(Cipher.java:909)
    at javax.crypto.Cipher.init(Cipher.java:859)
    at de.demo.crypt.LoginActivity.executeLogin(LoginActivity.java:95)
    at de.demo.crypt.LoginActivity.access$000(LoginActivity.java:37)
    at de.demo.crypt.LoginActivity$1.onClick(LoginActivity.java:58)
    at de.demo.crypt.ActionButton.buttonClicked(ActionButton.java:104)
    at de.demo.crypt.ActionButton.access$000(ActionButton.java:17)
    at de.demo.crypt.ActionButton$1.onClick(ActionButton.java:60)
    at android.view.View.performClick(View.java:5198)
    at android.view.View$PerformClick.run(View.java:21147)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

1 个答案:

答案 0 :(得分:8)

对Cipher.getInstance使用“AES / CBC / PKCS7Padding”或“AES / CBC /”+ KeyProperties.ENCRYPTION_PADDING_PKCS7。

Android Keystore仅支持AES的PKCS#7填充(请参阅https://developer.android.com/training/articles/keystore.html#SupportedCiphers)。对于大于64位的块大小(AES使用128位块),技术上没有定义PKCS#5填充。通常情况下,当人们说PKCS#5填充时,他们​​的意思是PKCS#7填充。

您所看到的特殊错误是因为Bouncy Castle错误地声称支持AES / CBC / PKCS5Padding的Android Keystore密钥(请参阅Bouncy Castle问题跟踪器问题BJA-543)。

P上。 S.最佳做法是让加密Cipher实现为您生成随机IV,而不是自己为Cipher提供IV - 您可以稍后使用Cipher.getIV()查询生成的IV。如果由于某种原因,您必须在加密时提供自己的IV,则在生成密钥时,您需要禁用密钥(https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.Builder.html#setRandomizedEncryptionRequired(boolean))上的随机加密的默认要求。