Skip to content

Mobile secure data storage (ENG)

Angelina edited this page Nov 10, 2017 · 6 revisions

Data Storage on a mobile device with limited access to a specific application

This article describes some basic principles of data storage and solution we found to solve this security problem by providing quick access to the local storage of mobile devices (android/ios)from a single application without the necessity to use Central Authentication Service (CAS).

Definitions

  • Local storage (LS) is a file located on a mobile device at which static application data is recorded.
  • Master key (MK) is a key we use to encrypt data on the LS.

PROBLEM

Private keys in cryptowallets or whole data bases are the kind of data requiring higher attention when launching an application. Instead of entering a key every time we try to read or write any data from data base we want user to enter it only once when starting an appplication. We beleive it a a much better approach to UI/UX. However it causes several problems:

  1. Since adversary can easily access Local Storage of an application;
  2. (1) We need to encrypt data before writing it to LS;
  3. (2) We need a Master Key to encrypt LS and some secure place to store it;
  4. It is impossible to store MK in LS (chicken-and-egg problem);
  5. We can't use CAS as it will lead to poor app's performance and will not permit us to get access to MK in case there is no Internet connection;
  6. Using local mobile certification authority adds new problems to the process of app's implementation, worsens UX, and puts all the confidential data in jeopardy (in case local CA is hacked);
  7. Hardcoding MK is not an option since app can be reverse engineered;
  8. You can not forse users to memorize MK just because an ordinary user can not remember a more or less secure key/password.

SOLUTION

Is there any sense in storing MK at all? What if MK will be generated in application just before we need it will be kept in the RAM of the device for some time and then delete itself.

We can split the task into several smaller, but specific problems in this case:

  • f1() - binding MK to the installation lifecycle;
  • f2() - binding MK to the release application certificate
  • f3() - binding MK to a specific device

That is:

MK = SHA256( f1() + f2() + f3() );

f1 () - Binding Master Key to the installation lifecycle

Why is it necessary?

Any operations with the installation/removal of an application must end with generation of a new MK. We prevent adversaries from being able to log MK by modifying the source code in this way. In other words, if an application has been uninstalled, new installation will lead to generation of a different MK as a result of f1()'s execution. It means that the data encrypted with the MK during the previous installation will be safe.

Still we should be able to update applications.

The right solution is to get an installation ID of the application that will:

  • be generated from the application's code
  • not change when updating application
  • change when deleting and reinstalling an app
  • not permit user manipulations to change/delete it

Solutions for:

f2() - Binding Master Key to the release application certificate

Why is it necessary?

We know that adversaries has an access to the source code of the application. Hence they are able to make an app with the desired modifications. But if we include a signature fact of a collected build in MK generation process then restoring MK without an acess to this certificate will be a real challenge.

And since the release certificates are kept and protected by the official developers hacking MK becomes a much more complicated process.

It means that:

f2() = SHA256(signCertificate);

Solutions for:

  • android
PackageInfo info;
    try {
        info = context.getPackageManager().getPackageInfo(
                context.getPackageName(), PackageManager.GET_SIGNATURES);

        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance(context.getString(R.string.sha));
            md.update(signature.toByteArray());
            return md.digest();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
  • ios

Identifier for Vendor (IDFV) is used as a key here.

Link to the Apple documentation about identifierForVendor.

UIDevice.current.identifierForVendor!.uuidString

f3() - binding MK to a specific device

Why is it necessary?

Assuming adversaries are able to transfer an app to other device or emulator (but such cases have not been recorded yet) means that we should be able to verify that an application is running on the device on which it has been installed before. Such popular device identifiers as EMEI, deviceID and etc are suitable instruments in this case.

But still these identifiers can be easely faked so this solution should be perceived as salt when calculating SHA256().

!!! One should understand that in case of user's interferance in these device data parameters the former MK will never be generated. Therefore, decision whether to use this function or not largely depends on the security context of the application itself.

Solutions for:

  • android
Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID)
  • ios

We use a token for push notifications for IOS platform.

func application(_ application: UIApplication, 
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        print("push token: \(token)")
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "deviceTokenNotification"),
                                        object: token)
}

CONCLUSION

This solution is a perfect one to generate a unique MK for data encryption. But it does not protect us from a dump of RAM at the moment of app's execution. In this case adversaries will have an access to the desired data no matter whether it is encryted or not.

Clone this wiki locally