Java / Android
Using Themis in Android applications
- Build Themis for Android as described in Building and installing Themis
- Import Themis AAR to your application project in Android Studio or reference it in your gradle.build file. More about using libraries here.
Keypair generation
You can generate keypairs easily for secure message and secure session like this:
Keypair pair = KeypairGenerator.generateKeypair();
PrivateKey privateKey = pair.getPrivateKey();
PublicKey publicKey = pair.getPublicKey();
WARNING: When you distribute private keys to your users, make sure they are sufficiently protected. You can find guidelines here.
NOTE: When using public keys of other peers, make sure they come from trusted sources.
Usage
Secure message
Sending many messages to same recipient
-
Create SecureMessage object with your PrivateKey and recipient's PublicKey:
SecureMessage encryptor = new SecureMessage(yourPrivateKey, peerPublicKey);
-
Encrypt each outgoing message:
byte[] encryptedMessage = encryptor.wrap(messageToSend);
-
Decrypt each incoming message:
byte[] receivedMessage = encryptor.unwrap(wrappedMessage);
Sending messages to many recipients
-
Create SecureMessage object with your PrivateKey:
SecureMessage encryptor = new SecureMessage(yourPrivateKey);
-
Encrypt each outgoing message specifying recipients' PublicKey:
byte[] encryptedMessage = encryptor.wrap(messageToSend, peerPublicKey);
-
Decrypt each incoming message specifying sender's PublicKey:
byte[] receivedMessage = encryptor.unwrap(wrappedMessage, peerPublicKey);
Secure cell
-
Create SecureCell object to protect your data
SecureCell cell = new SecureCell(yourSecretByteArrayKey);
or
SecureCell cell = new SecureCell("your secret password string");
You may specify mode as well:
SecureCell cell = new SecureCell("your secret password string", SecureCell.MODE_TOKEN_PROTECT);
NOTE: If not specified, Secure Cell will use
SecureCell.MODE_SEAL
by default. More about Secure Cell modes and which to choose here. -
Protect your data:
SecureCellData cellData = cell.protect(context, data);
NOTE: Context is optional.
The result of the function call is
SecureCellData
object which is a simple container for protected data. You may get actual protected data:byte[] protectedData = cellData.getProtectedData();
Depending on the mode selected it may also have additional data (which is opaque to the user but necessary for successful decryption):
if (cellData.hasAdditionalData() { byte[] additionalData = cellData.getAdditionalData(); }
You may also use one object to encrypt different data with different keys:
SecureCellData cellData1 = cell.protect(key1, context1, data1); ... SecureCellData cellData2 = cell.protect(key2, context2, data2); ...
-
Recover your data:
byte[] data = cell.unprotect(context, cellData);
NOTE: Context should be same as in protect call for successful decryption.
Secure session
Secure sockets
If your application already uses Java sockets for communication you can easily add security by replacing them with our SecureSocket
and SecureServerSocket
- Implement
ISessionCallbacks
interface: getPublicKeyForId
which will return peer's trusted public key when needed by the system-
stateChanged
is just a notification callback. You may use it for informational purpose, to update your UI or just have a dummy (do-nothing) implementationExample using anonymous class:
ISessionCallbacks callbacks = new ISessionCallbacks() { @Override public PublicKey getPublicKeyForId(SecureSession session, byte[] id) { // get trusted PublicKey of user id PublicKey publicKey = getUserPublicKeyFromDatabaseOrOtherStorageOrSource(id); return publicKey; // or null if key is not found } @Override public void stateChanged(SecureSession session) { // update UI: for example, draw a nice lock indicating to the user that his communication is now secured } }
-
Replace all your sockets with our secure versions:
on client:
// Socket clientSocket = new Socket(...); Socket clientSocket = new SecureSocket(..., clientId, clientPrivateKey, callbacks);
on server:
// ServerSocket serverSocket = new ServerSocket(...); ServerSocket serverSocket = new SecureServerSocket(..., serverId, serverPrivateKey, callbacks);
-
Enjoy
Basic secure session
This API is useful when your application already has an established network processing path and this path is more than just using sockets. You just want to add some function calls which will wrap/unwrap outgoing/incoming buffers with data.
-
As in case with Secure sockets. Implement
ISessionCallbacks
interface:ISessionCallbacks callbacks = new ISessionCallbacks() { @Override public PublicKey getPublicKeyForId(SecureSession session, byte[] id) { // get trusted PublicKey of user id PublicKey publicKey = getUserPublicKeyFromDatabaseOrOtherStorageOrSource(id); return publicKey; // or null if key is not found } @Override public void stateChanged(SecureSession session) { // update UI: for example, draw a nice lock indicating to the user that his communication is now secured } }
-
Create
SecureSession
object:SecureSession session = new SecureSession(yourId, yourPrivateKey, callbacks);
-
On client side, initiate secure session negotiation by generating and sending connect request:
byte[] connectRequest = session.generateConnectRequest(); // send connectRequest to the server
-
On both sides begin receiving and parsing incoming data:
// receive some data and store it in receiveBuffer SecureSession.UnwrapResult result = session.unwrap(receiveBuffer); switch (result.getDataType()) { case USER_DATA: // this is actual data that was encrypted by your peer using SecureSession.wrap byte[] data = result.getData(); // process data according to your application flow for incoming data break; case PROTOCOL_DATA: // this is internal secure session protocol data. An opaque response was generated, just send it to your peer byte[] data = result.getData(); // send the data to your peer as is break; case NO_DATA: // this is internal secure session protocol data, but no response is needed (usually happens on the client side when protocol negotiation completes) // do nothing break; }
-
When protocol negotiation completes, you may send encrypted data to your peer:
byte[] wrappedData = session.wrap(yourData); // send wrappedData to your peer
Secure session with transport callbacks
This API is useful when you want to clearly decouple security and network communication in your application:
-
Implement
ITransportSessionCallbacks
interface. This interface extendsISessionCallbacks
interface, so you have to implement two additional functions:ITransportSessionCallbacks callbacks = new ITransportSessionCallbacks() { // implement getPublicKeyForId and stateChanged as in basic ISessionCallbacks ... @Override public void write(byte[] buffer) { // it will be called when secure session needs to send something to your peer // just send buffer to your peer } @Override public byte[] read() { // here you should issue read request to your underlying transport (for example, read data from socket or pipe) // return the buffer with read data } }
-
Create
SecureTransportSession
object:SecureTransportSession session = new SecureTransportSession(yourId, yourPrivateKey, callbacks);
-
On client side initiate secure session negotiation by sending connect request:
session.connect();
-
After negotiation completes you may send/receive data on both sides
// sending data session.write(dataToSend); ... // receiving data (probably, through a receive loop) byte[] receivedData = session.read();
More examples
Android testcases (in the tests directory) are simple self-describing easy-to-understand examples of our APIs usage scenarios. Feel free to explore them a bit.