Lab 7 - Cryptography

Objectives

  • Protect the app's data using encryption
  • Use Android's Keystore to generate and store cryptographic keys

Lab's task

In this lab we create an app that stores our pins and/or passwords.

It must have the following features and UI components:

  • Allow the user to input the description (purpose) of the pin/password
  • Allow the user to input the pin/password
  • A button to save the input data
  • A button to show the description and the value of the saved pin/password
    • optional - save more than one description & pin pair and show them in a list
  • Can be used only if the device is protected by a Lock Screen

Target API >= 23. - the reason is provided in the Android Keystore section

Keyguard

If you are Android users you might have noticed that certain apps require you to setup a lock screen for your device if you don't have one already.

Android's Keyguard handles the lock/unlocking of the device. The SDK offers the KeyguardManager system service using which you can check if the device is secured with a screen lock and if it's locked or not.

To interact with this service, you need to obtain it using the Context's method getSystemService and providing it a string representing the service, in this case the Context.KEYGUARD_SERVICE constant. You have done something similar, in a previous lab for obtaining Connectivity Service.

// assuming this is called from an Activity, which is a Context
keyguardService = (KeyguardService) getSystemService(Context.KEYGUARD_SERVICE); 

Task 1 - Extra security (2p)

To improve the app's security allow access to the app only if the device is protected by a Lock screen. Don't allow the use of the app unless it is set.

  • Hint: use KeyguardManager.isDeviceSecure method
  • Show an Alert Dialog (tutorial) informing the users that they need to setup their Lock screen.
    • for the setPositiveButton send an implicit intent with the action DevicePolicyManager.ACTION_SET_NEW_PASSWORD
    • for the setNegativeButton close the app (call finish())
  • You can perform this check when the activity is resuming.

If you skip this task and your phone is not secured, the decryption from the other tasks might throw an Exception unless you set a flag like in this solution.

Android Keystore

The Android Keystore system (tutorial, documentation) provides mechanisms for securing storage and for generating the cryptographic keys needed by an app. Its role as a security container is guaranteed by the fact that the keys cannot be extracted from the application's process and from the device.

Why do we need this?

  • user authentication
  • use the keys to secure data stored in internal storage or shared preferences
  • hold the keys needed for the communication between the app and a remote device/server, e.g. if we encrypt the communication between the app and a wearable device.

The Android M (Marshmallow, API Level 23) release introduced several security related improvements and features: runtime permissions, different SSL library and updates for its Keystore API, which is now supporting also symmetric keys in addition to the asymmetric available from API 18. The way we generate these keys also changed from this level, now using KeyGenParameterSpec instead of the KeyPairGeneratorSpec.

Terminology and classes related to the Keystore system, some of them from Java Cryptography API:

    • implementation of the Java Security API features: algorithms, key related operations
    • although we can have multiple providers, we need to use only one when creating the keystore
    • “AndroidKeyStore” is the provider introduced in API 18
    • we must specify a provider when using the Android Keystore system
  • KeyPairGenerator - generates the keys based on a given algorithm and using a given provider.
  • Cipher - cipher transformations
    • used for encryption, decryption, signing
    • the transformation is configured by specifying the algorithm or the combination of algorithm + mode + padding
  • SecretKey — a symmetric key
  • Certificate - represents certificates and also provides the public key
  • PrivateKey — the key from the asymmetric algorithms
  • Alias - the name of the key as we identify it inside the keystore. We provide this alias when storing the key and when retrieving it.

Keystore initialization

  1. Obtain a Keystore instance with a given Provider. In our examples we will use the “AndroidKeyStore” provider.
  2. Call one of the load methods, depending if we use a password for the keystore or not. If we use no password we can just call load(null). This password is unrelated to the device password if a LockScreen is setup.
 keyStore = KeyStore.getInstance("AndroidKeyStore");
 keyStore.load(inputStream, password);

Managing keys

To obtain the keys:

:!: If you have not provided a password to the Keystore, when you get the keys just provide null as the password parameter.

To generate the keys (API > 23):

  1. Obtain a KeyPairGenerator with a given algorithm and provider (list of supported algorithms)
  2. Create a KeyGenParameterSpec for configuring all the parameters need for the keys (e.g. size, dates, purpose)
    • ! we can limit the usage of a key by providing a specific purpose (available purposes are defined in Builder docs)
  3. Provide the key specification to the key generator using one of the initialize methods
  4. Obtain a KeyPair object by calling the KeyPairGenerator's generateKeyPair method
// (1)
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
// instead of using hardcoded strings, we can also use the KeyProperties.KEY_ALGORITHM_* variables.
 
// (2) create keys only used for signing
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_SIGN)
                .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                .setSignaturePaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .build();
// (3)                   
generator.initialize(keyGenParameterSpec);
 
// (4)
generator.generateKeyPair();

To store the keys:

  • No need to call anything explicitly, they are automatically saved by the generateKeyPair() of the KeyPairGenerator.

Task 2 - Keystore (3p)

When the app starts, initialize the Keystore and generate a pair of keys if they don't exist yet.

  • Generate a pair of asymmetric keys with the following configuration:
    • purposes: ENCRYPT, DECRYPT
    • RSA
    • key size 2048
    • encryption paddings: RSA_PCKS1 (use setEncryptionPaddings)
  • Generate the keys only once, not every time you start the app
    • check if the keys exist using the containsAlias method provided by the KeyStore
  • Use the AndroidKeyStore provider when initializing the Keystore, like in the we showed in this section.
  • Design Advice: separate the crypto logic from the UI logic. In MainActivity just call methods of a separate class, that handles the initialization of the keystore, the generation of keys etc.

Encrypt and decrypt data

Using the keys obtained from the Keystore, we can perform cryptographic transformations on our data using the Cipher class.

In the following example we encrypt and decrypt data using a symmetric key algorithm. For an asymmetric-key algorithm the code is similar, it differs just the initialization of the Cipher and that we provide the public key for encryption and the private one for decryption.

// The KeyPairGenerator was configured with the spec:
// * KeyProperties.KEY_ALGORITHM_RSA (asymmetric-key algorithm)
// * KeyProperties. ENCRYPTION_PADDING_RSA_PKCS1
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); //<-- provide the same configuration!
 
// Encrypt
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytes = cipher.doFinal(data);
String encodedData = Base64.encodeToString(bytes, Base64.DEFAULT);
 
// Decrypt
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedData = Base64.decode(encodedData, Base64.DEFAULT);
String data = new String(cipher.doFinal(encryptedData));

Task 3 - Encryption (2.5p)

  • When the user presses the “Save” button encrypt the data provided by the user and store them as SharedPreferences
  • Initialise the Cipher with the following algorithm/mode/padding string: “RSA/ECB/PKCS1Padding”

Task 4 - Decryption (2.5p)

  • When the user presses the “Show pin” button load the data from SharedPreferences and decrypt it

Task 5 (2p - optional)

  • Save more than one description & pin pair and show them in a list.

If you generate the keys with a certain parameter configuration and then you change it, you need to clear the application's data in order for the encryption/decryption to work because you reuse the keys already existing in the keystore. You can also uninstall the app in order to clear the data. Running the app from the Android Studio's run button won't clear the app's data.

smd/laboratoare/07.txt · Last modified: 2020/04/26 15:37 by vlad.traista
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0