Android提供了一个API,用于生成用于加密操作的密钥,并将其存储在Android系统密钥存储中或从中存储。
我遵循KeyGenParameterSpec类的JavaDocs中的Example。密钥的生成,存储和加载工作。但是,如果我尝试使用密钥,则密码对象的init()调用将失败。我调试了一下,可以看到加载的Key类型为“ android.security.keystore.AndroidKeyStoreSecretKey”。该实现防止密钥的byte []被暴露。我出于安全原因了解这一点,但是如果我想使用密钥,则必须获取密钥内容。所以,我必须做错什么。也许,还有另一种在Android中使用加密操作的方法吗?还是密钥的加载代码错误?
这是代码:
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)
对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)。从技术上讲,PKCS#5填充未针对大于64位的块大小进行定义(AES使用128位块)。通常,当人们说PKCS#5填充时,这些天是指PKCS#7填充。
您看到的特定错误是因为Bouncy Castle错误地声称支持AES / CBC / PKCS5Padding的Android密钥库密钥(请参阅Bouncy Castle问题跟踪器,发行号BJA-543)。
PS最佳实践是让加密的Cipher实现为您生成随机IV,而不是自己为Cipher提供IV-您以后可以使用Cipher.getIV()查询生成的IV。如果出于某种原因在加密时必须提供自己的IV,则在生成密钥时,您需要禁用对密钥的默认随机加密要求(https://developer.android.com/reference/android/security /keystore/KeyGenParameterSpec.Builder.html#setRandomizedEncryptionRequired(boolean))。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句