Date post: | 06-Jan-2017 |
Category: |
Technology |
Upload: | frederik-schweiger |
View: | 64 times |
Download: | 1 times |
Security at your Fingertips.
+FrederikSchweiger | @flschweiger
A dive into Marshmallow’s new fingerprint and keystore APIs.
FREDERIK SCHWEIGERAll life is an experiment. The more experiments you make the better.
- Ralph Waldo Emerson
#android #technology #skydiving #entrepreneurship #skiing
about.me/FrederikSchweiger
CRYPTOGRAPHYWHY YOU SHOULD USE
...the RIGHT way?
BROKEN / NOCRYPTOGRAPHY
TOP 10 MOBILE RISK FOR 2014 / 2015
?How can I, as an Android developer, store
my user’s sensitive information securely in my app?
AndroidKeyStoreluckily there’s the
well - but what does it really do?
it stores keys(the secure way)
Let’s start at the beginning!
Android 1.6introduced a credential store for VPN & WiFi
Android 4.0introduced a public API for that, namely the
KeyChain API
Android 4.1 / 4.34.1 introduced the keymaster HAL
4.3 introduced the Android KeyStore JCA providerand hardware-backed key storage
Android 6.0improved everything
This talk will focus on theAndroid KeyStore JCA provider and how to
generate / access app-private keys
Let’s do th
is!
KeyPairGeneratorSpecGenParameter
(deprecated since API level 23)
KeyGenParameterSpec
↳ Implements AlgorithmParameterSpec for a KeyPairGenerator or KeyGenerator
↳ Instantiated by using the KeyGenParameterSpec.Builder
↳ Determines authorized use of the key, the paramters, validity start and end dates
// Get the KeyGenerator instance for AESKeyGenerator keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
// Create a KeyGenParameterSpec builder and // set the alias and different purposes of the keyKeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder( "myAwesomeSecretKey01", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
// The KeyGenParameterSpec is how parameters for your key are passed to the // generator. Choose wisely!builder .setKeySize(256) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
// Generate and store the keykeyGenerator.init(builder.build());keyGenerator.generateKey(); AES
KeyPairGenerator generator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder( "myFancyRsaKey01", KeyProperties.PURPOSE_SIGN);
Calendar start = new GregorianCalendar();Calendar end = new GregorianCalendar();end.add(Calendar.YEAR, 1);
builder .setKeySize(2048) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS) .setCertificateSubject(new X500Principal("CN=test")) .setCertificateSerialNumber(BigInteger.ONE) .setKeyValidityStart(start.getTime()) .setKeyValidityEnd(end.getTime());
generator.initialize(builder.build());generator.generateKeyPair(); RSA
successfully created"myAwesomeSecretKey01"
Great - let’s encrypt something!
AES
// Get the AndroidKeyStore instanceKeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
// Relict of the JCA API - you have to call load even// if you do not have an input stream you want to load or it'll crashkeyStore.load(null);
// Get the SecretKey from the KeyStore and instantiate a CipherSecretKey secretKey = (SecretKey) keyStore.getKey("myAwesomeSecretKey01", null);Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
// Init the Cipher and encrypt the plaintextcipher.init(Cipher.ENCRYPT_MODE, secretKey);byte[] encryptedBytes = cipher.doFinal("This is a super secret message".getBytes());
// Get the AndroidKeyStore instanceKeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
// Relict of the JCA API - you have to call load even// if you do not have an input stream you want to load or it'll crashkeyStore.load(null);
// Get the SecretKey from the KeyStore and instantiate a CipherSecretKey secretKey = (SecretKey) keyStore.getKey(SecurityConstants.KEY_AES, null);Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
// Init the Cipher and decrypt the ciphertextcipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));byte[] decryptedBytes = cipher.doFinal(cipherBytes);
AES
Key advantages of the new KeyStore
● OS provided ‘safe’ for all keys / certificates● hardware-backed cryptography for secure key
storage in a Trusted Execution Environment (TEE)● can reliably and securely create / store app-private
keys● added improved support for RSA, ECDSA, AES and
HMAC keys
TrustZone here, TrustZone there...
...TrustZone everywhere! Currently 80-90% of all devices are TrustZone enabled.
→ required as of Andoid N
AUTHENTICATIONIS ABADUX!
Authentication...
✓ is annoying✓ is time consuming✓ comes up too often
→ almost 50% of all Android users do not have a lockscreen enabled
.setUserAuthenticationRequired(true)
combined with
.setUserAuthenticationValidityDurationSeconds(30)
KeyGenerator keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder( "myAwesomeSecretKey01", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
builder .setKeySize(256) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds(30);
keyGenerator.init(builder.build());keyGenerator.generateKey();
AES
try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null);
SecretKey secretKey = (SecretKey) keyStore.getKey(SecurityConstants.KEY_AES, null); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); byte[] decryptedBytes = cipher.doFinal(cipherBytes);
} catch (UserNotAuthenticatedException e) { // User is not authenticated, let's authenticate with // device credentials! showAuthenticationScreen(); return;} catch { … } AES
private void showAuthenticationScreen() { Intent in = mKeyguardManager.createConfirmDeviceCredentialIntent(
"Hey there!", "Please...");
if (in != null) { startActivityForResult(in, REQUEST_CODE_CREDENTIALS); }}
Btw: you can find the co
de of
the example app on GitHu
b!
@Overrideprotected void onActivityResult(int requestCode,
int resultCode, Intent data) { if (requestCode == REQUEST_CODE_CREDENTIALS) { // Challenge completed, proceed with using cipher if (resultCode == RESULT_OK) { doSomeDecryptionHere(); } else { // The user canceled or didn’t complete the lock screen // operation. Go to error/cancellation flow. } }}
Authentication just got easier.
✓ You don’t even need to show an authentication screen when the user authenticated recently.
Authentication just got stronger.
✓ Authentication is now tied to app secrets (e.g. KeyStore)
✓ Credential verification in hardware (e.g. TrustZone)
Fingerprint authentication
✓ Authentication is a lot easier / faster✓ Consistent authentication flow✓ Secure lockscreen adoption on Nexus
devices went from 50% to > 90%
> Good to know:
SmartLock reduces lock screen prompts on devices without
a fingerprint scanner by 50%
Make it really easy - use fingerprints!
What you need:✓ A fingerprint reader✓ A device running Android Marshmallow or later✓ A user who has setup a secure lockscreen and
enrolled some fingerprints*
*optional: you can always force the user to enroll one
FingerprintManager
● Is a system-level service which coordinates all access to the fingerprint hardware
● Needs the normal USE_FINGERPRINT permission
mFingerprintManager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
FingerprintManager
↳ provides methods to check for device compatibility○ mFingerprintManager.isHardwareDetected();
○ mFingerprintManager.hasEnrolledFingerprints();
↳ also available as a ‘compat’ version
FingerprintManager
mFingerprintManager.authenticate(FingerprintManager.CryptoObject mCryptoObject,@Nullable CancellationSignal cancelSignal,0 /* optional flags - should be 0 */, FingerprintManager.AuthenticationCallback callback, @Nullable Handler handler);
FingerprintManager.CryptoObject
↳ a wrapper class for the crypto objects supported by the FingerprintManager○ mCryptoObject.getCipher();
○ mCryptoObject.getMac();
○ mCryptoObject.getSignature();
FingerprintManager.AuthenticationCallback
↳ provides callback structure○ onAuthenticationSucceeded(
FingerprintManager.AuthenticationResult result)○ onAuthenticationHelp(
int helpCode, CharSequence helpString)○ onAuthenticationError(
int errorCode, CharSequence errString)○ onAuthenticationFailed()
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
FingerprintManager.CryptoObject object = result.getCryptoObject();Cipher cipher = object.getCipher();
// Work with your Cipher / Mac / Signature object here...
}
Best Practices for a great UX
● Use the Keystore to check if user recently authenticated
● If a fingerprint scanner is available, use the API to test for user presence
● Use the ConfirmDeviceCredential screen as a fallback
DEMOtime
Get Safe.Available today.Only on GitHUb.
@flschweiger/SafeApp
○ https://developer.android.com/training/articles/keystore.html
○ https://source.android.com/security/
○ ‘Android Security Internals’ (covers Android <= 4.4) by +NikolayElenkov
Further reading:
Thanks!
+FrederikSchweiger | @flschweiger
Feel free to circle me on Google+ and send me your questions! You will find the slides in my Google+ stream and on SlideShare.