我想在Android设备上的AndroidKeyStore中存储AES密钥
我尝试使用KeyGenerator
KeyGenerator keyGen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
keyGen.init(256);
SecretKey secretKey = keyGen.generateKey();
但我无法从KeyStore访问该密钥,后来我尝试使用KeyPairGenerator
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
kpg.initialize(new KeyPairGeneratorSpec.Builder(this)
.setAlias("alias")
.build());
KeyPair kp = kpg.genKeyPair();
但是
java.security.NoSuchAlgorithmException:未找到KeyPairGenerator AES实现
答案 0 :(得分:6)
Android Keystore仅支持API Level 23(参见https://developer.android.com/training/articles/keystore.html#SupportedAlgorithms)。在较旧的平台上,您可以使用Android Keystore RSA密钥包装AES密钥。但是,这意味着AES密钥的密钥材料将在您的应用程序进程中可用,这消除了使用Android密钥库的许多安全优势。
答案 1 :(得分:-3)
为了简单起见,我创建了一个简单的应用程序,演示了如何使用Android Keystore系统来保存密码,加密密码,显示加密的表单并对其进行解密。
我不会进入任何XML/layout
细节,这是非常基本的东西。无论如何,我将在最后发布完整的源代码。
让我们跳进这件事的肉。
我做的是创造了2个班级。一个称为EnCryptor
,另一个称为Decryptor
。这些名字非常自我解释。
对于此示例,我们将使用以下加密/解密转换算法:“AES/GCM/NoPadding”
创建新密钥 在我们开始加密过程之前,我们需要为我们想要用来加密/解密数据的别名找到一个名称。这可以是任何字符串。长期不是空洞的。别名是生成的密钥将在Android KeyStore中显示的条目的名称。
<强>解密器:强>
class DeCryptor {
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private KeyStore keyStore;
DeCryptor() throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
IOException {
initKeyStore();
}
private void initKeyStore() throws KeyStoreException, CertificateException,
NoSuchAlgorithmException, IOException {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
keyStore.load(null);
}
String decryptData(final String alias, final byte[] encryptedData, final byte[] encryptionIv)
throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException,
NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException,
BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(alias), spec);
return new String(cipher.doFinal(encryptedData), "UTF-8");
}
private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException,
UnrecoverableEntryException, KeyStoreException {
return ((KeyStore.SecretKeyEntry) keyStore.getEntry(alias, null)).getSecretKey();
}
}
EnCryptor:
class EnCryptor {
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private byte[] encryption;
private byte[] iv;
EnCryptor() {
}
byte[] encryptText(final String alias, final String textToEncrypt)
throws UnrecoverableEntryException, NoSuchAlgorithmException, KeyStoreException,
NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IOException,
InvalidAlgorithmParameterException, SignatureException, BadPaddingException,
IllegalBlockSizeException {
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias));
iv = cipher.getIV();
return (encryption = cipher.doFinal(textToEncrypt.getBytes("UTF-8")));
}
@NonNull
private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {
final KeyGenerator keyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
return keyGenerator.generateKey();
}
byte[] getEncryption() {
return encryption;
}
byte[] getIv() {
return iv;
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String SAMPLE_ALIAS = "MYALIAS";
@BindView (R.id.toolbar)
Toolbar toolbar;
@BindView (R.id.ed_text_to_encrypt)
EditText edTextToEncrypt;
@BindView (R.id.tv_encrypted_text)
TextView tvEncryptedText;
@BindView (R.id.tv_decrypted_text)
TextView tvDecryptedText;
private EnCryptor encryptor;
private DeCryptor decryptor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
encryptor = new EnCryptor();
try {
decryptor = new DeCryptor();
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException |
IOException e) {
e.printStackTrace();
}
}
@OnClick ({R.id.btn_encrypt, R.id.btn_decrypt})
public void onClick(final View view) {
final int id = view.getId();
switch (id) {
case R.id.btn_encrypt:
encryptText();
break;
case R.id.btn_decrypt:
decryptText();
break;
}
}
private void decryptText() {
try {
tvDecryptedText.setText(decryptor
.decryptData(SAMPLE_ALIAS, encryptor.getEncryption(), encryptor.getIv()));
} catch (UnrecoverableEntryException | NoSuchAlgorithmException |
KeyStoreException | NoSuchPaddingException | NoSuchProviderException |
IOException | InvalidKeyException e) {
Log.e(TAG, "decryptData() called with: " + e.getMessage(), e);
} catch (IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
}
private void encryptText() {
try {
final byte[] encryptedText = encryptor
.encryptText(SAMPLE_ALIAS, edTextToEncrypt.getText().toString());
tvEncryptedText.setText(Base64.encodeToString(encryptedText, Base64.DEFAULT));
} catch (UnrecoverableEntryException | NoSuchAlgorithmException | NoSuchProviderException |
KeyStoreException | IOException | NoSuchPaddingException | InvalidKeyException e) {
Log.e(TAG, "onClick() called with: " + e.getMessage(), e);
} catch (InvalidAlgorithmParameterException | SignatureException |
IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
}