If there is sensitive data to be stored when developing a mobile app, security is of utmost importance.
Developers can make hackers’ work harder, but it’s almost impossible to totally prevent a data breach if they are at it.
Key and encryption handling can be a real pain-in-the-ass. Storing encrypted data is one thing, but uploading and downloading data securely is a different problem. Storing and transferring can be partitioned into separate tasks to be done on the client and on the server side too.
ZeroKit provides a solution for both problems, called zero-knowledge. It lifts the key and encrytion management problems off the developers’ shoulders. The main concept is, that users can create tresors, after registration and login, of course. These tresors are responsible for the keys the user can use for encryption and decryption. But they aren’t stored on the device, just keeping in the cache during the session.
The user can create more tresors, and even share them directly with other users, or they can send non-specific invitations as well.
The environment consists of two Tresorit side components: the ZeroKit SDK itself, and the AdminAPI. And there is an Application side, client apps, and the backend too.
The client apps communicate with the SDK, and the backend, not directly with the AdminAPI.
The backend is responsible for approvals of the client side requests through the AdminAPI. With this solution, any authorization and/or authentication or extra security or functional step on the backend side during the flows can be integrated.
Almost all operations starting through the SDK need to be approved by the AdminAPI before they can actually modify anything.
Operations that need approval:
- User registration
- User invitation to a tresor
- Tresor creation
- Invitation link creation for a tresor
- Invitation link acceptance
- Invitation link revocation
- Kicking out a user from a tresor
Administrative queries / settings:
- Listing the user base of the tenant
- Listing the members of a tresor
- Delete tresor
- Settings user state (enabled / disabled)
- Allow / prohibit tresor sharing for a user
- Allow / prohibit tresor creation for a user
For webapps only:
- Upload custom content files (i.e. .css files)
- List custom content files
- Delete custom content files
First of all, this is an online tool, you cannot use any of the features if your device is offline. The tresors, along with their keys, are stored only in memory (precisely in the webviews session store), not in files. Therefore, the tresors cannot be reached while the app is not online.
There is also a built-in remember me option that stores a key created from the userId and the password (not the pass itself) in the Android Keystore. Next time you can log in with this key and your userId. There is also a special logout function, to keep the remember me key (can be quite handy in some cases).
The passwords are never handled as Strings, instead as Character arrays, and these are always filled with zeros when the operation is finished.
To achive this, the SDK provides custom input labels and password exporters for password handling.
ZeroKit SDK functions:
ZeroKit has an easy-to-use method (whoAmI), to check if there is any user logged in. If there is, then it returns its userId (that is needed for almost every action), otherwise null.
- Client sends an initRegistration request to the AdminAPI.
- AdminAPI responds (userId, regSessionId, regSessionVerifier).
- With the response parameters Client initiates a registration call to ZeroKit SDK.
- ZeroKit creates a fully functional userprofile, but the Client still cannot log in, however tresors can already be shared with it. Responds with regValidationVerifier.
- Client requests validation from AdminAPI (userId, regSessionId, regSessionVerifier, regValidationVerifier). Now the user profile can be used.
There is a „remember me” option. When chosen, the app won’t require login credentials when started again. If not chosen, of course the app will make the user login when starting the app.
It is just a simple round with ZeroKit SDK, no AdminAPI involved. Of course you can use your backend to retrive userId, for a given username.
It should serve to initiate ZeroKit, to get the tresors for the user.
One can share its tresorId with specified userId. The userId it is shared with can use its tresors keys to encrypt or decrypt.
Current members of a tresor can download and decrypt its keys and then use them to decrypt any data that were encrypted by that tresor at any time.
- Client calls for ZeroKit SDK to shareTresor (tresorId, userId)
- SDK responds with a shareId
- With this shareId the client sends an approveShare request to the AdminAPI
One can create an invitation (not specific to users). It can be created with or without a password (it is recommended to use password though).
- Client calls for ZeroKit SDK to createInvitationLinkNoPassword („link”, tresorId, message)
- SDK responds with an id and a url (contains a secret, ZeroKit needs this secret for the identification of the invitation – so as the developer, you can find out whether this invite had a message and/ora password to show)
- With this id the client sends an approveCreateInvitationLink request to the AdminAPI
- Then the url is shareable (additional password, and not storing the url are recommended)
It’s worth mentionining that this so-called “link” can be used as a deeplink that can be used for in-app navigation.
- Client calls for ZeroKit SDK to getInvitationLinkInfo (url secret)
- SDK responds with info about the invitation along with a token
- With this token Client calls for ZeroKit SDK to acceptInvitationLinkNoPassword
- SDK responds with a unnamed string for approval
- With this string the client sends an approveInvitationLinkAcception request to the AdminAPI
Then the Client can use – for the tresors he is invited to – keys, to encrypt or decrypt.
- Currently the android SDK does not clear the webview session store (where the tresors are stored) upon app termination. That’s why only the app navigation flow prevents the secret to be reached (weird). I checked it on iOS, where it works properly.
- The SDK uses an RX-like pattern, but without the RX’s indisputable adventages. Therefore I cannot chain the calls in a beautiful way, and there is no proper thread handling (That’s why there are a lot of awful runOnUiThread()…).
I mentioned my remarks to the ZeroKit dev guys, they are already working on them!
ZeroKit original sample mentions:
I found it quite complex, and complicated, but very instructive (using Dagger, MVI, DataBinding and ConstraintLayout just to mention a few). It does not cover all the main functionalities of the SDK.
For a sample app I think one should use quite easy solutions focused mainly on the goals.
Wanari’s ZeroKit Demo App:
To keep the focus on what matters, I used as few third party libraries as possible.
All the Todo lists as tables, and todos as entities are stored and synced in a Firebase realtime database.
Firebase is easy to implement, use, and maintain (To make it work offline, it’s only one line).
All the changes in the database can be almost immediately be syncronized to the clients, what keeps it quite responsive and spectacular even in my simple demo app.
In the demo app, only the Todo items are encrypted, not the tables themselves (cause it’s not a production-ready app).
Our backend is an extra layer between the app and the AdminAPI.
It has a couple of extra features, to give far better UX with the smallest effort:
- In the registration flow’s validation part, it waits for an additional username to store
- It can list the username – userId pairs (this is for the share autocomplete function)
- It can give back the userId for a presented username (this is for login)
The app stores only the last successful username – userId pair, to autofill at sigin.
It uses almost the same SignIn/SignUp solution like the Sample, but I also implemented the “Remember Me” function.
After the successful login, you can add Todo lists from a list (even created by other users), or create a new one. Creating a Todo list means you create a tresor for it to encrypt and decrypt its Todos.
You can add a new Todo, or edit one if you are a member of the Todo’s list tresor. The Todos are stored in Firebase, in an encrypted form.
If you add a list, where you aren’t a member, then you can see the Todo list, but you cannot decrypt their content.
To become a member of a Todo list, you have to be invited by a member, or the Todo list has to be shared with you:
- There is a function on the backend, to give the userId-username binding to the app. With this solution you can search for users and their ids for sharing in an autocomlete view.
- You can even create an invitation, providing a message(optional) and a password. This way the user gets an invitation link he can distribute. This link works as a deeplink.If someone taps on a deeplink, it opens up the app, and navigates through the login flow into the app, where it presents an acceptional dialog. Here, the user can read the added message, and present a password, to get the invitation.
ZeroKit is an easy-to-use SDK for increasing the security of your app.
ZeroKit’s SDK for Android currently misses some features, but it’s pretty great already. When these holes are patched, it will be a perfect solution for making secure Android apps.
For iOS, its current state seems to be in even better shape, but I haven’t taken a very detailed look. My colleague, Kruz is currently working on an iOS demo app, keep an eye out!
UPDATE: Krúz has created the iOS demo app for ZeroKit. Check it out on GitHub!
As always, I am happy to converse on this topic!
Latest posts by Gergely Szőke (see all)
- Replacing fragments with Conductors’ Controllers - May 25, 2017
- XML Drawables for Android Developers - April 12, 2017
- ZeroKit and Firebase Demo App First Look - March 9, 2017
- A Native Mobile Dev’s Favorite Libraries - July 20, 2016
- 7 Android Logging Tools Tested & Compared - June 29, 2016
- The Best Crash Report Tools for Android Developers - May 26, 2016