Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

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.

License

NotificationsYou must be signed in to change notification settings

patrickfav/armadillo

Repository files navigation

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 CentralBuild StatusJavadocsCoverage StatusMaintainability

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

Features

  • No-Nonse State-of-the-Art Crypto: Authenticated Encryption withAES-GCM, key derivation functionsBcrypt andHKDF
  • 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 likeBouncyCastle orFacebook Conceal

Security Summary

  • Using itwith 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 isnot easily possible to just copy data over to another device and use it there
  • Encryption isnon-deterministic, which means even if you encrypt the same data itappears to be different
  • All encrypted data isprotected against modification by an outside attacker, so long as the encryption itself is not circumvented
  • TheAndroid 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 morebelow). 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

SharedPreferencespreferences =Armadillo.create(context,"myPrefs")    .encryptionFingerprint(context)    .build();preferences.edit().putString("key1","stringValue").commit();Strings =preferences.getString("key1",null);

Advanced Example

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

StringuserId = ...SharedPreferencespreferences =Armadillo.create(context,"myCustomPreferences")        .password("mySuperSecretPassword".toCharArray())//use user provided password        .securityProvider(Security.getProvider("BC"))//use bouncy-castle security provider        .keyStretchingFunction(newPBKDF2KeyStretcher())//use PBKDF2 as user password kdf        .contentKeyDigest(Bytes.from(getAndroidId(context)).array())//use custom content key digest salt        .secureRandom(newSecureRandom())//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 likef1a4e61ffb59c6e6a3d6ceae9a20cb5726aade06.xml willbe created with the resulting data looking something like that after thefirst put operation:

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

KitKat Support

UnfortunatelyAndroid SDK 19 (KITKAT) does not fully support AES GCM mode.Therefore a backwards compatible implementation of AES usingCBCwithEncrypt-then-MACcan be used to support this library on older devices. This should providethe same security strength as the GCM version, however the support mustbe enabled manually:

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

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

Description

Design Choices

  • AES + GCM block mode: To make sure that the data is not only keptconfidential, but it's integrity also preserved, the authenticated encryptionAES+GCM is used. GCMcan be implemented efficiently and fast and is the usually alternative toencrypt then macwith AES+CBC and HMAC. The authentication tag is appended to the message andis 16 byte long in this implementation. A downside of GCM is the requirementtonever reuseaIV with the same key,which is avoided in this lib.
  • Every put operation creates a different cipher text: Every put operationgenerates new salts, iv so the the resulting cipher text will be unrecognizablydifferent even with the same underlying data. This makes it harder to check ifthe data actually has changed.
  • KDFs with Key Stretching features for user passwords: Add brute-forceprotection to possibly weak user provided passwords (e.g. BCrypt).
  • Minimum SDK 19 (Android 4.4): A way to increase security is to cap olderimplementation. SDK 19 seems to be a good compromise where most of the oldersecurity hack fixesare not necessary anymore, but still targeting most devices.
  • Use ofJCA 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 manualupdates to have all the latest security fixes.This library however depends on the default JCA provider (although the developer may choose adifferent one). This puts trust in the device and it's implementation, whileexpecting frequent security patches. Usually the default provider since KitKat isAndroidOpenSSL provider which is fast (probably hardware accelerated for e.g. AES) andheavily 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 securedata on an Android device. Unfortunately, due to the massive fragmentationin the ecosystem properly handling and using the Android Keystore Systemis not easy and hassome major drawbacks.Due to working in a security relevant field I have a lot of experience withthis technology, therefore the decision was made to not support itfor thisimplementation i.e. to keep it simple.
  • Use of data obfuscation: To disguise the actual data format and appearas a pseudo random byte array, obfuscation is used. This deliberately usesnon 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 strongbase for a cryptographic key. Unfortunately user-based passwords are oftenweak (low-entropy). To mitigate that fact and help preventing easy brute-forcingkey derivation functionswithkey stretchingproperties are used. These functions calculate pseudo-random data from it'ssource 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 providinga customKeyStretchingFunction implementation.

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

Encryption Fingerprint

This store bases part of it's security on so called fingerprinting. Thatbasically means, during runtime entropy from e.g. the device, system or otherparts 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 ofEncryptionFingerprint whichcan only use generic data. In detail the following properties are incorporated:

  • Fingerprint of theAPK 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'sown 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 followingparts:

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 lengthwithHKDF derivation function.

Persistence Profile

Key

The key is hashed withHKDF (which usesHmac with Sha512 internally) expanded to a 20 byte hash which will be encoded withbase16 (hex). The key generationis salted by the encryption fingerprint, so different shared preferences willgenerate different hashes for the same keys.

Content

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

screenshot gallery

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

<?xml version='1.0' encoding='utf-8' standalone='yes' ?><map>    <stringname="39e3e4f83dda81c44f8a9063196b28b3d5091fca">hwbchXlqDAQcig6q3UWxdbOb2wouDGGwjUGNIzREiy0=</string>    <stringname="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: 4FDF85343912A3ABFingerprint: 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, softwaredistributed 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 andlimitations under the License.

About

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.

Topics

Resources

License

Stars

Watchers

Forks

Languages


[8]ページ先頭

©2009-2025 Movatter.jp