Created
December 20, 2018 17:25
-
-
Save eoinahern/258bd7eb245b47bd5b116afe1407b037 to your computer and use it in GitHub Desktop.
android keystore encryption class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class KeyStoreHelper { | |
private static final String ALIAS = "mikey"; | |
private static final String ANDROID_KEYSTORE = "AndroidKeyStore"; | |
private final Context context; | |
private Calendar start; | |
private Calendar end; | |
private KeyStore keyStore; | |
public KeyStoreHelper(Context context, String keyStoreName) { | |
this.context = context; | |
try { | |
keyStore = KeyStore.getInstance(keyStoreName); | |
keyStore.load(null); | |
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) { | |
Timber.e(e); | |
} | |
} | |
public KeyStore getKeyStore() { | |
return keyStore; | |
} | |
private CipherOutputStream createCipherStream(ByteArrayOutputStream outputStream, Cipher cipher, String input) { | |
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); | |
try { | |
cipherOutputStream.write(input.getBytes("UTF-8")); | |
cipherOutputStream.close(); | |
} catch (IOException e) { | |
Timber.e(e); | |
} | |
return cipherOutputStream; | |
} | |
public synchronized String encryptString(String unencryptedStr) throws KeyStoreException { | |
if (!keyStore.containsAlias(ALIAS)) { | |
generateKeyPair(ALIAS); | |
} | |
KeyStore.PrivateKeyEntry privateKeyEntry; | |
RSAPublicKey publicKey; | |
try { | |
privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(ALIAS, null); | |
publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey(); | |
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); | |
cipher.init(Cipher.ENCRYPT_MODE, publicKey); | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
createCipherStream(outputStream, cipher, unencryptedStr); | |
byte[] bytes = outputStream.toByteArray(); | |
return Base64.encodeToString(bytes, Base64.DEFAULT); | |
} catch (NoSuchPaddingException | InvalidKeyException | UnrecoverableEntryException | NoSuchAlgorithmException e) { | |
Timber.e(e); | |
return ""; | |
} | |
} | |
public synchronized String decryptString(String encryptedString) { | |
try { | |
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(ALIAS, null); | |
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding"); | |
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey()); | |
CipherInputStream cipherInputStream = new CipherInputStream( | |
new ByteArrayInputStream(Base64.decode(encryptedString, Base64.DEFAULT)), output); | |
List<Byte> values = new ArrayList<>(); | |
int nextByte; | |
while ((nextByte = cipherInputStream.read()) != -1) { | |
values.add((byte) nextByte); | |
} | |
byte[] bytes = new byte[values.size()]; | |
for (int i = 0; i < bytes.length; i++) { | |
bytes[i] = values.get(i); | |
} | |
return new String(bytes, 0, bytes.length, "UTF-8"); | |
} catch (IOException | NoSuchAlgorithmException | UnrecoverableEntryException | InvalidKeyException | KeyStoreException | NoSuchPaddingException e) { | |
Timber.e(e); | |
return ""; | |
} | |
} | |
private void generateKeyPair(String alias) { | |
initCalendarElements(); | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | |
getKeyPairAPIBelow23(); | |
} else { | |
getKeyPairAPIOver23(alias); | |
} | |
} | |
private void initCalendarElements() { | |
start = Calendar.getInstance(); | |
end = Calendar.getInstance(); | |
end.add(Calendar.YEAR, 5); | |
} | |
private KeyPair getKeyPairAPIBelow23() { | |
try { | |
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE); | |
keyPairGenerator.initialize(new KeyPairGeneratorSpec.Builder(context) | |
.setAlias(ALIAS) | |
.setSubject(new X500Principal("CN=" + ALIAS)) | |
.setSerialNumber(BigInteger.ONE) | |
.setStartDate(start.getTime()) | |
.setEndDate(end.getTime()) | |
.build()); | |
return keyPairGenerator.generateKeyPair(); | |
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | |
Timber.e(e); | |
return null; | |
} | |
} | |
@RequiresApi(Build.VERSION_CODES.M) | |
private KeyPair getKeyPairAPIOver23(String alias) { | |
try { | |
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE); | |
keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_SIGN | | |
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) | |
.setDigests(KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA512) | |
.setCertificateSubject(new X500Principal("CN=" + alias)) | |
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) | |
.setCertificateSerialNumber(BigInteger.ONE) | |
.build()); | |
return keyPairGenerator.generateKeyPair(); | |
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { | |
Timber.e(e); | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment