• Stars
    star
    273
  • Rank 145,763 (Top 3 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created over 6 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A shared preference implementation for confidential data in Android. Per default uses AES-GCM, BCrypt and HKDF as cryptographic primitives. Uses the concept of device fingerprinting combined with optional user provided passwords and strong password hashes.

Armadillo - Encrypted Shared Preference

Armadillo Logo

A shared preference implementation for secret data providing confidentiality, integrity and authenticity. Per default uses AES-GCM, BCrypt and HKDF as cryptographic primitives.

Maven Central Build Status Javadocs Coverage Status Maintainability

Important Notice: If you migrate to v0.6.0 and use a user password and default key stretching function migration is needed due to a security issue. See migration guide in the changelog for v0.6.0

Features

  • No-Nonse State-of-the-Art Crypto: Authenticated Encryption with AES-GCM, key derivation functions Bcrypt and HKDF
  • Flexible: Tons of nobs and switches while having sane defaults
  • Modular: use your own implementation of symmetric cipher, key stretching, data obfuscation, etc.
  • Lightweight: No massive dependencies required like BouncyCastle or Facebook Conceal

Security Summary

  • Using it with a user provided password (and strong password hash, like the default BCrypt): your data is strongly encrypted
  • Using it without a user provided password: your data is obfuscated and cannot be easily altered or read by an attacker with access to the device
  • By using fingerprinting, it is not easily possible to just copy data over to another device and use it there
  • Encryption is non-deterministic, which means even if you encrypt the same data it appears to be different
  • All encrypted data is protected against modification by an outside attacker, so long as the encryption itself is not circumvented
  • The Android Keystore System is not used, since it proved to be unreliable and hard to handle in production due to device fragmentation and poor driver support (read more below). This implementation is a good fallback solution for a system that uses the aforementioned.

Quick Start

Add the following to your dependencies (add jcenter to your repositories if you haven't)

compile 'at.favre.lib:armadillo:x.y.z'

A very minimal example

SharedPreferences preferences = Armadillo.create(context, "myPrefs")
    .encryptionFingerprint(context)
    .build();

preferences.edit().putString("key1", "stringValue").commit();
String s = preferences.getString("key1", null);

Advanced Example

The following example shows some of the configurations available to the developer:

String userId = ...
SharedPreferences preferences = Armadillo.create(context, "myCustomPreferences")
        .password("mySuperSecretPassword".toCharArray()) //use user provided password
        .securityProvider(Security.getProvider("BC")) //use bouncy-castle security provider
        .keyStretchingFunction(new PBKDF2KeyStretcher()) //use PBKDF2 as user password kdf
        .contentKeyDigest(Bytes.from(getAndroidId(context)).array()) //use custom content key digest salt
        .secureRandom(new SecureRandom()) //provide your own secure random for salt/iv generation
        .encryptionFingerprint(context, userId.getBytes(StandardCharsets.UTF_8)) //add the user id to fingerprint
        .supportVerifyPassword(true) //enables optional password validation support `.isValidPassword()`
        .enableKitKatSupport(true) //enable optional kitkat support
        .enableDerivedPasswordCache(true) //enable caching for derived password making consecutive getters faster
        .build();

A xml file named like f1a4e61ffb59c6e6a3d6ceae9a20cb5726aade06.xml will be created with the resulting data looking something like that after the first put operation:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <!-- storage random salt -->
    <string name="585d6f0f415682ace841fb50d5980d60ed23a2ef">riIPjrL2WRfoh8QJXu7fWk4GGeAKlQoJl9ofABHZKlc=</string>
    <!-- 'key1':'stringValue' -->
    <string name="152b866fd2d63899678c21f247bb6df0d2e38072">AAAAABD/8an1zfovjJB/2MFOT9ncAAAAJaf+Z9xgzwXzp1BqTsVMnRZxR/HfRcO8lEhyKpL17QmZ5amwAYQ=</string>
</map>

KitKat Support

Unfortunately Android SDK 19 (KITKAT) does not fully support AES GCM mode. Therefore a backwards compatible implementation of AES using CBC with Encrypt-then-MAC can be used to support this library on older devices. This should provide the same security strength as the GCM version, however the support must be enabled manually:

SharedPreferences preferences = Armadillo.create(context, "myCustomPreferences")
        .enableKitKatSupport(true)
        ...
        .build();

In this mode, if on a KitKat device the backwards-compatible implementation is used, the default AES-GCM version otherwise. Upgrading to a newer OS version the content should still be decryptable, while newer content will then be encrypted with the AES-GCM version.

Description

Design Choices

  • AES + GCM block mode: To make sure that the data is not only kept confidential, but it's integrity also preserved, the authenticated encryption AES+GCM is used. GCM can be implemented efficiently and fast and is the usually alternative to encrypt then mac with AES+CBC and HMAC. The authentication tag is appended to the message and is 16 byte long in this implementation. A downside of GCM is the requirement to never reuse a IV with the same key, which is avoided in this lib.
  • Every put operation creates a different cipher text: Every put operation generates new salts, iv so the the resulting cipher text will be unrecognizably different even with the same underlying data. This makes it harder to check if the data actually has changed.
  • KDFs with Key Stretching features for user passwords: Add brute-force protection to possibly weak user provided passwords (e.g. BCrypt).
  • Minimum SDK 19 (Android 4.4): A way to increase security is to cap older implementation. SDK 19 seems to be a good compromise where most of the older security hack fixes are not necessary anymore, but still targeting most devices.
  • Use of JCA as Provider for cryptographic primitives: Various security frameworks exists in Java: BouncyCastle, Conscrypt, Facebook Conceal. The problem is that these libraries are usually huge and require manual updates to have all the latest security fixes. This library however depends on the default JCA provider (although the developer may choose a different one). This puts trust in the device and it's implementation, while expecting frequent security patches. Usually the default provider since KitKat is AndroidOpenSSL provider which is fast (probably hardware accelerated for e.g. AES) and heavily used by e.g. TLS implementation.
  • Android Keystore System is not used: In my humble opinion, the Android Keystore is the best possible way to secure data on an Android device. Unfortunately, due to the massive fragmentation in the ecosystem properly handling and using the Android Keystore System is not easy and has some major drawbacks. Due to working in a security relevant field I have a lot of experience with this technology, therefore the decision was made to not support it for this implementation i.e. to keep it simple.
  • Use of data obfuscation: To disguise the actual data format and appear as a pseudo random byte array, obfuscation is used. This deliberately uses non standard ways to make it a bit harder to reverse engineer.

User provided Passwords

A high entropy value not known to any system but the user is a good and strong base for a cryptographic key. Unfortunately user-based passwords are often weak (low-entropy). To mitigate that fact and help preventing easy brute-forcing key derivation functions with key stretching properties are used. These functions calculate pseudo-random data from it's source material which requires mandatory work.

The following implementations are available:

  • BCrypt: based on blowfish, has a variable cpu cost parameter and a fixed memory cost parameter (default)
  • PBKDF2: applies a pseudorandom function, such as hash-based message authentication code (HMAC), to the input password or passphrase along with a salt value and repeats the process many times to produce a derived key; no memory hardness

It is possible to provide any KDF implementation to the storage with providing a custom KeyStretchingFunction implementation.

Note, if you use key stretching put/get operations will get very slow (depeding on the work factor of course), so consider accessing the store in a background thread.

Encryption Fingerprint

This store bases part of it's security on so called fingerprinting. That basically means, during runtime entropy from e.g. the device, system or other parts are used to create a cryptographic key with which the data is encrypted. It basically is encryption with a semi-secret key.

This has the following benefits:

  • Binding the data to the executing runtime (ie. making it harder to lift the data and trying to read it in a different environment)
  • Strongly obfuscating the data bordering actual encryption when the used fingerprint is infeasible to guess
  • Be able to scope the data to a specific environment (e.g. when using the Android OS image build number, every update invalidates the data)

This store has a default implementation of EncryptionFingerprint which can only use generic data. In detail the following properties are incorporated:

  • Fingerprint of the APK signature
  • Android ID : a 64-bit number (expressed as a hexadecimal string) byte random value; on SDK 26 and higher, unique to each combination of app-signing key, user, and device - on SDK 25 lower only unique to user and device
  • Application package name, brand, model and name of the device
  • 32 byte hardcoded static random value

Enhancing the Strength of the Encryption Fingerprint

The security of this mechanism increases considerably if the user adds it's own data. Here are some suggestions:

  • Random values hardcoded, locally generated or provided by a remote service
  • Unique user-id (if the application has the concept of login)
  • Device Serial (requires dangerous permission SDK > 25)
  • Sim-ID/ICCID (if changing the sim should/can invalidate the data)
  • Android OS image build fingerprint (if you want to invalidate the data after OS update)

Key Derivation Process

The cryptographic key used to encrypt the data is composed of the following parts:

screenshot key derivation

  • User password (optional): provided by the caller and stretched with e.g. Bcrypt
  • Encryption Fingerprint (see section above)
  • Entry Key: the hashed version of the key passed by the caller; this will bind the data to that specific entry key
  • Entry Salt: a random 16 byte value unique to that specific entry that will be created on every put operation (will also be used for the key stretching function)
  • Storage Salt: a random 32 byte value unique to that specific storage, created on first creation of the storage

The concatenated key material will be derived and stretched to the desired length with HKDF derivation function.

Persistence Profile

Key

The key is hashed with HKDF (which uses Hmac with Sha512 internally) expanded to a 20 byte hash which will be encoded with base16 (hex). The key generation is salted by the encryption fingerprint, so different shared preferences will generate different hashes for the same keys.

Content

The diagram below illustrates the used data format. To disguise the format a little bit it will be obfuscated by a simple xor cipher.

screenshot gallery

The resulting data will be encoded with base64 and looks like this in the shared preferences xml:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="39e3e4f83dda81c44f8a9063196b28b3d5091fca">hwbchXlqDAQcig6q3UWxdbOb2wouDGGwjUGNIzREiy0=</string>
    <string name="62ef41ac992322bdd669e96799c12a66a2cce111">AAAAABAAajtOaVCq5yqu1TPxgLu2AAAAqUTxgPcAM6lyNTGgy7ZAoCjqcCdtxT6T</string>
</map>

Digital Signatures

Signed Commits

All tags and commits by me are signed with git with my private key:

GPG key ID: 4FDF85343912A3AB
Fingerprint: 2FB392FB05158589B767960C4FDF85343912A3AB

Build

Assemble the lib with the following command

./gradlew :armadillo:assemble

The .aar files can then be found in /armadillo/build/outputs/aar folder

Libraries & Credits

Similar Projects:

Further Reading

License

Copyright 2017 Patrick Favre-Bulle

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

More Repositories

1

uber-apk-signer

A cli tool that helps signing and zip aligning single or multiple Android application packages (APKs) with either debug or provided release certificates. It supports v1, v2 and v3 Android signing scheme has an embedded debug keystore and auto verifies after signing.
Java
1,734
star
2

Dali

Dali is an image blur library for Android. It contains several modules for static blurring, live blurring and animations.
Java
1,053
star
3

bcrypt

A Java standalone implementation of the bcrypt password hash function. Based on the Blowfish cipher it is the default password hash algorithm for OpenBSD and other systems including some Linux distributions. Includes a CLI Tool.
Java
449
star
4

BlurTestAndroid

This is a simple App to test some blur algorithms on their visual quality and performance.
Java
416
star
5

density-converter

A multi platform image density converting tool converting single or batches of images to Android, iOS, Windows or CSS specific formats and density versions given the source scale factor or width/height in dp. It has a graphical and command line interface and supports many image types (svg, psd, 9-patch, etc.) aswell as some lossless compressors like pngcrush.
Java
244
star
6

under-the-hood

Under the Hood is a flexible and powerful Android debug view library. It uses a modular template system that can be easily extended to your needs, although coming with many useful elements built-in.
Java
217
star
7

uber-adb-tools

A tool that enables advanced features through adb installing and uninstalling apps like wildcards and multi device support. Useful if you want to clean your test device from all company apks or install a lot of apks in one go. Written in Java so it should run on your platform.
Java
154
star
8

bytes-java

Bytes is a utility library that makes it easy to create, parse, transform, validate and convert byte arrays in Java. It supports endianness as well as immutability and mutability, so the caller may decide to favor performance.
Java
150
star
9

pihole-unbound-docker

A docker-compose setup that maintaines a Pi-hole DNS with an with an upstream Unbound recursive DNS all hosted locally.
Dockerfile
89
star
10

hkdf

A standalone Java 7 implementation of HMAC-based key derivation function (HKDF) defined in RFC 5869 first described by Hugo Krawczyk. HKDF follows the "extract-then-expand" paradigm which is compatible to NIST 800-56C Rev. 1 two step KDF
Java
60
star
11

id-mask

IDMask is a Java library for masking internal ids (e.g. from your DB) when they need to be published to hide their actual value and to prevent forging. It has support optional randomisation has a wide support for various Java types including long, UUID and BigInteger.
Java
59
star
12

indoor-positioning

A full-featured indoor positioning system that was developed during my master thesis. It has a javascript based rich UI and has a server-client architecture.
Java
50
star
13

planb-android

A crash recovery library for Android. It allows tracking and handling crashes with different rules for debugging and production.
Java
34
star
14

slf4j-timber

SLF4J binding for Timber - a logger with a small, extensible API which provides utility on top of Android's normal Log class.
Java
26
star
15

rocketchat-exporter

A simple script exporting chats from a rocket chat instance using the public REST API. Useful if no administrative access is possible.
Java
24
star
16

dice

A cryptographically secure pseudorandom number generator cli tool printing in a wide variety of byte encodings (hex, base64,..) and for many programming languages (c, java, c#, php, etc.) using NIST SP800-90Ar1 HMAC-DRBG. Supports external seeding from various true random services.
Java
13
star
17

singlestep-kdf

Implementation of the single-step key derivation function (KDF) as described in NIST Special Publication 800-56C Rev1 supporting messages digest and HMAC.
Java
8
star
18

morseme

A very simple Android app that can morse given input through audio, vibration and light flash. Also can morse your SMS.
Java
4
star
19

base122-java

A Base122 byte-to-text encoder using format referenced in http://blog.kevinalbs.com/base122
Java
4
star
20

checkstyle-config

Global checkstyle config to be reused in different projects. These include my own personal rules so your milage may vary.
3
star
21

mvn-common-parent

A maven configuration which can be used as a commons config parent for POM files
2
star
22

smart-video-tagger

A tool to normalize filenames for movies and series/shows database so that they all would have the same format making it easier to parse it for other services
Java
2
star
23

bkdf

BCrypt based key derivation function to improve BCrypt as a cryptographic primitive for password hashing and key derivation
Java
2
star
24

bankathon16-inso

This is the prototype developed during the "Bankathon16" hackathon hosted by INSO. It was a 2 day event, 3 developer worked on the project. This project achieved 2nd place in the ranking.
Java
2
star
25

tuwien

Miscellaneous projects done during my studies in computer science at the Vienna University of Technology from about 2009 to 2011.
Java
1
star