Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Encryptor and Decryptor for data encryption.decryption using the 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();
}
}
/**
______ _____ _
| ____| / ____| | |
| |__ _ __ | | _ __ _ _ _ __ | |_ ___ _ __
| __| | '_ \| | | '__| | | | '_ \| __/ _ \| '__|
| |____| | | | |____| | | |_| | |_) | || (_) | |
|______|_| |_|\_____|_| \__, | .__/ \__\___/|_|
__/ | |
|___/|_|
*/
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;
}
}
/**
_____ _ _ _
/ ____| | | | | | |
| (___ __ _ _ __ ___ _ __ | | ___ | | | |___ __ _ __ _ ___
\___ \ / _` | '_ ` _ \| '_ \| |/ _ \ | | | / __|/ _` |/ _` |/ _ \
____) | (_| | | | | | | |_) | | __/ | |__| \__ \ (_| | (_| | __/
|_____/ \__,_|_| |_| |_| .__/|_|\___| \____/|___/\__,_|\__, |\___|
| | __/ |
|_| |___/
*/
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();
}
}
}

How use with api 18, please help me

Owner

josias1991 commented Oct 8, 2017 edited

You will have to use one of the other init() and getInstance() methods provided by the KeyGenerator. See here: https://developer.android.com/reference/javax/crypto/KeyGenerator.html.

You can do something like this in the getSecretKey method:

private SecretKey getSecretKey(final String alias) throws NoSuchAlgorithmException,
        NoSuchProviderException, InvalidAlgorithmParameterException {

    KeyGenerator keyGenerator;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        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());
    } else {
        keyGenerator = KeyGenerator.getInstance(ANDROID_KEY_STORE);
        
        // or something like 
        
        keyGenerator = KeyGenerator.getInstance("supported algorithm here", ANDROID_KEY_STORE);
        
        // use the supported init method here such as this one: https://developer.android.com/reference/javax/crypto/KeyGenerator.html#init(int, java.security.SecureRandom)   
        keyGenerator.init(/* ... */);
    }

    return keyGenerator.generateKey();
}

For supported init methods algorithms below api 23 you can see the documentation in the link provided above. Each algorithm specifies what api it is supported in.

Each algorithm is described in the KeyGenerator section of the Java Cryptography Architecture Standard Algorithm Name Documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment