在Android中存储AES密钥

时间:2016-05-19 13:05:23

标签: android encryption keystore android-keystore

我想在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实现

2 个答案:

答案 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();
        }
    }
}