-
Notifications
You must be signed in to change notification settings - Fork 0
Mobile secure data storage (ENG)
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).
- 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.
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:
- Since adversary can easily access Local Storage of an application;
- (1) We need to encrypt data before writing it to LS;
- (2) We need a Master Key to encrypt LS and some secure place to store it;
- It is impossible to store MK in LS (chicken-and-egg problem);
- 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;
- 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);
- Hardcoding MK is not an option since app can be reverse engineered;
- You can not forse users to memorize MK just because an ordinary user can not remember a more or less secure key/password.
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() );
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:
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
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)
}
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.