Skip to main content

Android Keystore Monitoring

The Android keystore allows developers to create and store encryption keys. These keys are stored inside of specialized, secure hardware such as the Trusted Execution Element (TEE). Android then provides APIs to interact with the TEE and obtain the results from the cryptographic operations. During a mobile test, it is a good idea to evaluate the security of the Keystore to ensure that the cryptographic functions in use are secure.

Some of the common vulnerabilities associated with the keystore include:

  • Keystore type (there are several types of keystores, the AndroidKeystore type should be in use)
  • If biometrics is in use, does the Keystore allow use of newly enrolled biometrics (the Keystore should lock until the device passcode is entered)
  • Weak algorithms
  • Hard coded encryption information being used

Dynamic Analysis

For dynamic analysis, use Frida to trace the Keystore functions while the app is in use. There are a few Frida scripts available to perform this action.

FRIDA

Using the preferred script, run it so that Frida will spawn the app from a non-running state. If you are currently logged into the app, logout first so that you can capture the whole process.

The example below uses the android-crypto-intercept.js script to trace the cryptographic functions:

frida -U -l android-script-name.js -f com.appname.app –no-pause
OptionDescription
-UUse the USB cable to connect to the device
-l Load the script
-f Spawn the app (for early instrumentation)
com.appname.appPackage name of the app you're testing
--no-pauseImmediately start the process once the app is hooked

Keystore Tracer

The keystore tracer allows you to obtain the following information:

  • Keystore type that is in use
  • If the Keystore is of ‘AndroidKeystore’ type, dump the information
  • Determines if biometrics can be bypassed

Frida Script: android-keystore-tracer.js:

% frida -U -l android-keystore-tracer.js -f com.example.app --no-pause

[Pixel 4a::com.example.app ]-> ListAliasesAndroid()
[Keystore.getInstance()]: type: AndroidKeyStore
[Keystore.load(LoadStoreParameter)]: keystoreType: AndroidKeyStore, param: null
[
"'_androidx_security_master_key_'"
]

[Pixel 4a::com.example.app ]-> AliasInfo('_androidx_security_master_key_')
[Keystore.getInstance()]: type: AndroidKeyStore
[Keystore.load(LoadStoreParameter)]: keystoreType: AndroidKeyStore, param: null
[Keystore.getKey()]: alias: _androidx_security_master_key_, password: '(null)'
{
"blockModes": [
"GCM"
],
"digests": [],
"encryptionPaddings": [
"NoPadding"
],
"isInsideSecureHardware": true,
"isInvalidatedByBiometricEnrollment": false,
"isTrustedUserPresenceRequired": false,
"isUserAuthenticationRequired": false,
"isUserAuthenticationRequirementEnforcedBySecureHardware": false,
"isUserAuthenticationValidWhileOnBody": false,
"isUserConfirmationRequired": false,
"keyAlgorithm": "AES",
"keySize": 256,
"keyValidityForConsumptionEnd": null,
"keyValidityForOriginationEnd": null,
"keyValidityStart": null,
"keystoreAlias": "_androidx_security_master_key_",
"origin": 1,
"purposes": 3,
"signaturePaddings": [],
"userAuthenticationValidityDurationSeconds": 0
}
[Pixel 4a::com.example.app ]->

Some interesting keys to review:

  • isInsideSecureHardware – determines if the TEE is in use
  • isInvalidatedByBiometricEnrollment – biometrics should be disabled when new biometrics are enrolled
  • isUserAuthenticationRequired – is the user required to authenticate on use
  • Encryption information: block modes, digest, key size & algorithm

Cipher Tracer

The cipher tracer will hook into the Android Cipher API to obtain information such as:

  • Encryption mode
  • Algorithm & Key size
  • (This will capture crypto operations for the Keystore and any other uses within the app!)

Frida Script: android-cipher-tracer.js:

% frida -U -l android-cipher-tracer.js -f com.example.app --no-pause 

[Cipher.getInstance()]: type: AES/GCM/NoPadding
[Cipher.getInstance()]: cipherObj: javax.crypto.Cipher@b65d488
[Cipher.init()]: mode: Decrypt mode, secretKey: android.security.keystore.AndroidKeyStoreSecretKey spec:[object Object] , cipherObj: javax.crypto.Cipher@b65d488
[Cipher.doFinal5()]: cipherObj: javax.crypto.Cipher@b65d488
In buffer (cipher: AES/GCM/NoPadding):

Offset 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 16 B9 A8 CB 98 19 58 40 67 EB AC 93 6F EC 7D 5B ......X@g...o.}[
00000010 0F B0 14 1E 78 F6 38 0D 68 F4 22 B4 C2 D0 C6 58 ....x.8.h."....X
00000020 00 8B E3 53 22 DB 5F 57 1D 31 C1 5F 13 DF D1 CC ...S"._W.1._....
00000030 6A C4 3B 08 6A 23 D8 DE 59 41 74 56 D9 9B 2A CB j.;.j#..YAtV..*.
00000040 64 8D 1E D2 EA 84 D2 3A AA 31 8F E9 21 59 76 6D d......:.1..!Yvm
00000050 5C CC 2D EF 67 35 36 31 31 80 3D E8 0A 51 06 24 \.-.g5611.=..Q.$
00000060 BE AC 22 7F DC F6 02 12 E3 1A 82 EF 6A 13 79 2A .."........j.y*
00000070 B1 DE 62 AF E5 16 69 D1 16 84 B5 22 43 3F 35 BE ..b...i...."C?5.
00000080 58 96 83 91 59 50 C1 DE 47 B6 4A 24 52 2C 90 9F X...YP..G.J$R,..
00000090 1B 41 D2 A3 36 FC D1 31 E9 20 85 86 BF 65 E4 5B .A..6..1. ...e.[
000000A0 E9 F4 D9 C0 75 FD 08 8D B6 ....u....

Out buffer (cipher: AES/GCM/NoPadding):

Offset 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 08 B2 8A DB D9 03 12 84 01 0A 78 0A 30 74 79 70 ..........x.0typ
00000010 65 2E 67 6F 6F 67 6C 65 61 70 69 73 2E 63 6F 6D e.googleapis.com
00000020 2F 67 6F 6F 67 6C 65 2E 63 72 79 70 74 6F 2E 74 /google.crypto.t
00000030 69 6E 6B 2E 41 65 73 53 69 76 4B 65 79 12 42 12 ink.AesSivKey.B.
00000040 40 CE 77 8B A8 72 4D FC 17 66 84 75 25 53 2F 23 @.w..rM..f.u%S/#
00000050 9C 80 24 07 CE 59 7F F4 F6 A7 2F 37 5A 36 62 87 ..$..Y.../7Z6b.
00000060 3B 04 21 C3 11 23 5C 35 77 02 46 3D F6 14 99 8B ;.!..#\5w.F=....
00000070 55 4B 86 5D 54 D0 04 3F 0E CB 37 41 8C 4D 1D 41 UK.]T..?..7A.M.A
00000080 A6 18 01 10 01 18 B2 8A DB D9 03 20 01 ........... .

Some interesting information:

  • cipherObj
  • cipher (algorithm/blockmode/padding)
  • Encrypted info such as usernames and passwords