Installation and usage

We provide Java bindings for Android through a Maven repository. Patch the build.gradle file at the top project to add the Maven repository used by Tanker:

allprojects {
  repositories {
    // ...
    maven {
      url 'https://storage.googleapis.com/maven.tanker.io'
    }
  }
}

Add the Tanker bindings to the list of dependencies in your application's build.gradle file:

dependencies {
    implementation 'io.tanker:tanker-bindings:2.0.0'
}

To use Tanker in your application:

import io.tanker.api.Tanker;
import io.tanker.api.TankerOptions;


String writablePath = getApplicationContext().getFilesDir().getAbsolutePath();
TankerOptions options = new TankerOptions();
options.setAppId("your-app-id")
       .setWritablePath(writablePath);
Tanker tanker = new Tanker(options);

Note

The writablePath should be a writable folder: this is where persistent data will be stored.

Supported platforms

The Tanker Client SDK uses native code, and the binaries we provide are compatible with all the architectures officially supported by the latest Android NDK:

  • armeabi-v7a
  • arm64-v8a
  • x86
  • x86_64

Error handling

private static final String TAG = "YourActivity";

TankerFuture<Unit> future = tanker.open(...);
future.then((future) -> {
    try {
        future.get();
    } catch (TankerException e) {
        if (e.getErrorCode() == TankerErrorCode.INVALID_ARGUMENT)
            Log.e(TAG, "An error occurred", e);
    }
});

All errors thrown from Tanker use the TankerException class, which contains an error code and a message. Here is the list of possible errors:

Error Description
INVALID_ARGUMENT Developer error, one of the function's argument is invalid
INTERNAL_ERROR Tanker internal error, thrown as a last resort
NETWORK_ERROR Network error, e.g. connection lost or the Tanker server is not reachable
PRECONDITION_FAILED Developer error, a function's precondition was violated
OPERATION_CANCELED An asynchronous operation was canceled when Tanker stopped
DECRYPTION_FAILED A decryption operation failed
INVALID_GROUP_TOO_BIG The group would exceed the maximum member limit (1000)
INVALID_VERIFICATION An invalid identity verification was provided
TOO_MANY_ATTEMPTS An operation was attempted too many times, please try again later
EXPIRED_VERIFICATION The identity verification is expired
DEVICE_REVOKED The device has been revoked
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

Version

This is a static method returning the SDK version as a String.

String version = Tanker.getVersionString();

Constructor

String writablePath = getApplicationContext().getFilesDir().getAbsolutePath();
TankerOptions options = new TankerOptions();
options.setAppId("your-app-id")
        .setWritablePath(writablePath);
Tanker tanker = new Tanker(options);
Options
writablePath: String The path where persistent data will be stored
appID: String The app ID

Session management

start

Starts a Tanker session and returns a status. See the guide for more information on treating the status.

The Tanker status must be STOPPED.

@NotNull
public TankerFuture<Status> start(@NotNull String identity)
Parameters
identity: String A Tanker identity
Returns
TankerFuture<READY> The session is ready and fully operational
TankerFuture<IDENTITY_REGISTRATION_NEEDED> First use of the identity. registerIdentity() must be called.
TankerFuture<IDENTITY_VERIFICATION_NEEDED> New device for this identity. verifyIdentity() must be called.
Errors Description
INVALID_ARGUMENT An argument is ill-formed
PRECONDITION_FAILED The session is not STOPPED

stop

Stops the current Tanker session.

@NotNull
public TankerFuture<Unit> stop()
Returns
TankerFuture<Unit> The future is fulfilled once the stop operation is done

getStatus

The following constants are available to check the status value:

Status Description
Status.STOPPED The session is stopped. start() can be called on it.
Status.READY The session is ready and fully operational
Status.IDENTITY_VERIFICATION_NEEDED The session needs the identity to be verified to become Status.READY
Status.IDENTITY_REGISTRATION_NEEDED This identity is not associated with any verification method. One must be registered.

You can read the status of the Tanker session using:

@NotNull
public Status getStatus()

Identity verification

Verification

The Verification abstract class can be instantiated by the classes with these constructors:

public PassphraseVerification(@NotNull String passphrase)
public VerificationKeyVerification(@NotNull String verificationKey)
public EmailVerification(@NotNull String email, @NotNull String verificationCode)
public OIDCIDTokenVerificationMethod(@NotNull String oidcIDToken)

A Verification object is typically used to perform an identity verification, or to register a new identity verification method.

VerificationMethod

The VerificationMethod abstract class provides information about available verification methods through the following concrete types:

public class PassphraseVerificationMethod extends VerificationMethod { }
public class VerificationKeyVerificationMethod extends VerificationMethod { }
public class EmailVerificationMethod extends VerificationMethod {
    @NotNull
    public String getEmail()
}

These objects are returned by functions that list verification methods available for an upcoming identity verification, e.g. getVerificationMethods() and attachProvisionalIdentity().

registerIdentity

Registers the user's identity with which start() has been called, and starts the session.

The Tanker status must be IDENTITY_REGISTRATION_NEEDED.

@NotNull
public TankerFuture<Unit> registerIdentity(@NotNull Verification verification)
Parameters
verification: Verification The verification to use for identity registration
Returns
TankerFuture<Unit> Resolves when the registration is done
Errors Description
PRECONDITION_FAILED The status is not IDENTITY_REGISTRATION_NEEDED
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.

verifyIdentity

Verifies the user's identity with which start has been called, and starts the session.

The Tanker status must be IDENTITY_VERIFICATION_NEEDED.

@NotNull
public TankerFuture<Unit> verifyIdentity(@NotNull Verification verification)

This function verifies the user's identity based on the provided verification. It must be called when the user has started a Tanker session on a new device.

Parameters
verification: Verification The verification to use
Returns
TankerFuture<Unit> Resolves once the verification is complete
Errors Description
PRECONDITION_FAILED The status is not IDENTITY_VERIFICATION_NEEDED
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

setVerificationMethod

Adds or overrides a verification method.

The Tanker status must be READY.

@NotNull
public TankerFuture<Unit> setVerificationMethod(@NotNull Verification verification)
Parameters
verification: Verification The verification to use
Returns
TankerFuture<Unit> Resolves once the verification method has been set or updated
Errors Description
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
PRECONDITION_FAILED The status is not READY
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
DEVICE_REVOKED The device has been revoked

getVerificationMethods

Returns the list of registered verification methods.

The Tanker status must be either IDENTITY_VERIFICATION_NEEDED or READY.

@NotNull
public TankerFuture<List<VerificationMethod>> getVerificationMethods()
Returns
TankerFuture<List<VerificationMethod>> The list of VerificationMethods already set
Errors Description
PRECONDITION_FAILED The status is neither IDENTITY_VERIFICATION_NEEDED nor READY
DEVICE_REVOKED The device has been revoked

generateVerificationKey

Generates a verification key, registers its public part on Tanker's servers, and returns its private part, which is required to verify the user's identity.

The Tanker status must be IDENTITY_REGISTRATION_NEEDED.

@NotNull
public TankerFuture<String> generateVerificationKey()

Once the verification key has been generated, it is not possible to set up high-level verification methods (e.g. email/passphrase).

The opposite is also true: no high-level verification method must have been set up before calling this function.

It is NOT possible to generate several verification keys.

Warning

This is a low level function for specific use-cases only, as it can have severe security implications. Use it only if high-level identity verification doesn't fit your needs, and you fully understand how it works. Don't hesitate to contact us for help.

Returns
TankerFuture<String> The generated verification key
Errors Description
PRECONDITION_FAILED The session is not in the IDENTITY_REGISTRATION_NEEDED state

Device management

getDeviceId

Retrieves the current device's ID.

@NotNull
public TankerFuture<String> getDeviceId()

Each device has its own ID and can be identified as such.

Returns
TankerFuture<String> Resolves with the current device's ID
Errors Description
PRECONDITION_FAILED The status is not READY

getDeviceList

Retrieves the user's devices list.

The Tanker status must be READY.

@NotNull
public TankerFuture<List<DeviceInfo>> getDeviceList()
Returns
TankerFuture<List<DeviceInfo>> The list of devices

Each DeviceInfo is an object describing a device, with the following methods:

Method Description
String getDeviceId() The device ID of the device
Boolean isRevoked() true if the device has been revoked
Errors Description
PRECONDITION_FAILED The status is not READY
DEVICE_REVOKED The device has been revoked

revokeDevice

Revokes one of the user's devices.

@NotNull
public TankerFuture<Unit> revokeDevice(@NotNull String deviceId)
Parameters
deviceId: String The device ID of the device to be revoked
Returns
TankerFuture<Unit> Resolves when the revocation operation completes
Errors Description
PRECONDITION_FAILED The status is not READY
INVALID_ARGUMENT The specified device was not found
INVALID_ARGUMENT Cannot revoke another user's device
DEVICE_REVOKED The device has been revoked
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

Encryption

encrypt

Encrypts a byte[] of raw data and returns the result in a future.

@NotNull
public TankerFuture<byte[]> encrypt(
  @NotNull byte[] data,
  @Nullable EncryptOptions encryptionOptions
)

The resulting encrypted resource will be shared with either or both individual users and groups specified using the EncryptOptions.

Parameters
data: byte[] The clear data to be encrypted. Can be either a java byte[] or a Kotlin ByteArray.
options: EncryptOptions Encryption and sharing options (optional)
Returns
TankerFuture<byte[]> The encrypted data
Errors Description
INVALID_ARGUMENT A recipient (user or group) was not found
PRECONDITION_FAILED The status is not READY
DEVICE_REVOKED The device has been revoked

encrypt (channels)

Constructs an encryption channel wrapping clearChannel, and returns it in a future.

@NotNull
public TankerFuture<TankerAsynchronousByteChannel> encrypt(
  @NotNull TankerAsynchronousByteChannel clearChannel,
  @Nullable EncryptOptions encryptionOptions
)

The resource produced by the channel will be shared with either or both individual users and groups specified using the EncryptOptions.

Warning

After calling this function, clearChannel must not be used!

Parameters
clearChannel: TankerAsynchronousByteChannel The channel to be encrypted
options: EncryptOptions Encryption and sharing options (optional)
Returns
TankerFuture The encryption channel
Errors Description
INVALID_ARGUMENT A recipient (user or group) was not found
PRECONDITION_FAILED The status is not READY
DEVICE_REVOKED The device has been revoked

EncryptOptions

The EncryptOptions allows you to specify who will be able to decrypt the resource through the shareWithUsers() and shareWithGroups() methods.

If neither are specified, only the resource creator will be able to decrypt it.

In general, if you need to share a resource with multiple users, it is advised to create groups and use shareWithGroups().

Method Default value Description
shareWithUsers(String[] publicIdentities) new String[]{} User public identities to share with (the current user's identity will be automatically appended)
shareWithGroups(String[] groupIDs) new String[]{} Group IDs to share with

decrypt

Decrypts a resource and returns the original clear data.

@NotNull
public TankerFuture<byte[]> decrypt(@NotNull byte[] data)
Parameters
data: byte[] The encrypted data to be decrypted
Returns
TankerFuture<byte[]> The decrypted data
Errors Description
PRECONDITION_FAILED The status is not READY
DECRYPTION_FAILED The encrypted data is corrupted
DEVICE_REVOKED The device has been revoked

decrypt (channels)

Constructs a decryption channel wrapping encryptedChannel, and returns it in a future.

@NotNull
public TankerFuture<TankerAsynchronousByteChannel> decrypt(
  @NotNull TankerAsynchronousByteChannel encryptedChannel
)

Note

encryptedChannel's content must have been encrypted by an encryption channel

Warning

After calling this function, encryptedChannel must not be used!

Parameters
encryptedChannel: TankerAsynchronousByteChannel The channel containing data to decrypt
Returns
TankerFuture<TankerAsynchronousByteChannel> The decryption channel
Errors Description
PRECONDITION_FAILED The status is not READY
DECRYPTION_FAILED The encrypted data is corrupted
DEVICE_REVOKED The device has been revoked

Groups management

createGroup

Creates a group with users' public identities, and returns its ID.

@NotNull
public TankerFuture<String> createGroup(@NotNull String[] publicIdentities)

Note

The maximum number of users per group is 1000.

Parameters
publicIdentities: Array<String> Group members' public identities
Returns
TankerFuture<String> A future of the newly created group's ID
Errors Description
INVALID_ARGUMENT Some recipients (groups or users) have not been found. The whole operation is canceled.
PRECONDITION_FAILED The status is not READY
DEVICE_REVOKED The device has been revoked

updateGroupMembers

Add members to an existing group.

@NotNull
public TankerFuture<Unit> updateGroupMembers(@NotNull String groupId, @NotNull String[] usersToAdd)

The new group members will automatically get access to all resources previously shared with the group.

Parameters
groupId: string Group ID to modify
usersToAdd: Array<String> Public identities of users to add to the group
Returns
TankerFuture<Unit> A future that resolves when the operation completes
Errors Description
INVALID_ARGUMENT One of the arguments is ill-formed
PRECONDITION_FAILED The status is not READY
DEVICE_REVOKED The device has been revoked
CONFLICT There was a conflict with a concurrent operation from another device/user, try again

Sharing

Sharing a resource can be done during encryption, using the encryption options.

getResourceID

Retrieves an encrypted resource's ID.

@NotNull
public String getResourceID(@NotNull byte[] encryptedData)

The resource ID can then be used to call share.

Note

This function does not have any requirement on Tanker's status.

Parameters
encryptedData: byte[] The encrypted resource from which you want the ID
Returns
String The ID of the given encrypted resource
Errors Description
INVALID_ARGUMENT The argument is an invalid resource

share

Shares resources with users and groups.

@NotNull
public TankerFuture<Unit> share(
  @NotNull String[] resourceIDs,
  @NotNull ShareOptions shareOptions
)

This function either fully succeeds or fails. In this case, it does not share with any recipient.

Parameters
resourceIds: Array<String> Resource IDs to share
options: ShareOptions Sharing options
Returns
TankerFuture<Unit> A future that resolves when the data has been shared
Errors Description
PRECONDITION_FAILED The status is not READY
INVALID_ARGUMENT Some recipients (groups or users) have not been found
INVALID_ARGUMENT Some resource IDs have not been found
DEVICE_REVOKED The device has been revoked

ShareOptions

The ShareOptions class allows you to specify who will be able to decrypt the resource through the shareWithUsers() and shareWithGroups() methods.

In general, if you need to share a resource with multiple users, it is advised to create groups and use shareWithGroups().

Method Default value Description
shareWithUsers(String[] publicIdentities) new String[]{} Public tanker identities of users to share with (the current user's identity will be automatically appended)
shareWithGroups(String[] groupIDs) new String[]{} Group IDs to share with

Pre-registration sharing

attachProvisionalIdentity

Attaches a provisional identity to the user.

@NotNull
public TankerFuture<AttachResult> attachProvisionalIdentity(@NotNull String provisionalIdentity)

Depending on the result, verifying the provisional identity with verifyProvisionalIdentity might be necessary.

Parameters
provisionalIdentity: String A provisional identity
Returns
TankerFuture<AttachResult> An AttachResult
Errors Description
INVALID_ARGUMENT The provided provisional identity is invalid
PRECONDITION_FAILED The status is not READY
DEVICE_REVOKED The device has been revoked

AttachResult

The attachProvisionalIdentity function returns a type with the following properties:

Method Description
Status getStatus() The provisional identity's status. Either READY or IDENTITY_VERIFICATION_NEEDED
VerificationMethod getMethod() A verification method containing the email matching the created provisional identity

verifyProvisionalIdentity

Verifies an attached provisional identity.

@NotNull
public TankerFuture<Unit> verifyProvisionalIdentity(@NotNull Verification verification)

Once the provisional identity is verified, every resource shared with it can now be decrypted by the user, who also joins every group in which the provisional identity was a member.

Parameters
verification: Verification A verification containing the provisional identity's email, and the verification code
Returns
TankerFuture<Unit> A future that resolves when the verification is done
Errors
PRECONDITION_FAILED The status of the current session is not READY
PRECONDITION_FAILED The status of the attach result is not IDENTITY_VERIFICATION_NEEDED
EXPIRED_VERIFICATION The verification expired
INVALID_VERIFICATION The verification is invalid
TOO_MANY_ATTEMPTS Too many verification attempts occurred. Please retry later.
DEVICE_REVOKED The device has been revoked

Events

Tanker defines a set of functions and callback handlers to handle events. Call connect${eventName}Handler() with your callback to subscribe to the event.

You can unsubscribe from the event by calling disconnectHandler with your callback.

TankerDeviceRevokedHandler handler = () -> {
    // Handle event
};
TankerConnection connection = tanker.connectHandler(handler);

//...

tanker.disconnectHandler(handler);

deviceRevoked

Emitted when the current device has been revoked. The revocation can be initiated on any device the user has registered, including the current device.

@NotNull
public TankerConnection connectDeviceRevokedHandler(@NotNull TankerDeviceRevokedHandler eventHandler)

Utilities

Those functions are extra utilities included in the Tanker SDK, they can be imported individually as follows:

import io.tanker.api.Tanker;

Channels

While the channels package is available from API level 1, AsynchronousByteChannel and a few other interfaces are only available in API level 26.

Tanker supports API level 19, therefore it cannot use the newest APIs directly. Instead, it exposes very similar interfaces.

TankerCompletionHandler

package io.tanker.api;

public interface TankerCompletionHandler<V, A> {
  public void completed(
    @NotNull V result,
    @NotNull A attachment
  );

  public void failed(
    @NotNull Throwable result,
    @NotNull A attachment
  );
}

API level 19-compatible CompletionHandler.

TankerAsynchronousByteChannel

API level 19-compatible AsynchronousByteChannel.

package io.tanker.api;

public interface TankerAsynchronousByteChannel {
  public <A> void read(
    @NotNull ByteBuffer dst,
    @NotNull A attachment,
    @NotNull TankerCompletionHandler<Integer, ? super A> handler
  );
}

Note

There are other functions in the API 26 version, but TankerAsynchronousByteChannel has no use for them.

Helper functions

Tanker provides helpers to:

  • convert streams to Tanker channels and vice versa
  • convert Tanker channels to API level 26 channels and vice versa
// available from io.tanker.api.TankerChannels

public class TankerChannels {
  @NotNull
  public static InputStream toInputStream(
    @NotNull
    TankerAsynchronousByteChannel channel
  );

  @NotNull
  public static TankerAsynchronousByteChannel fromInputStream(
    @NotNull InputStream stream
  );

  @RequiresApi(26)
  @NotNull
  public static AsynchronousByteChannel toAsynchronousByteChannel(
    @NotNull
    TankerAsynchronousByteChannel channel
  );

  @RequiresApi(26)
  @NotNull
  public static TankerAsynchronousByteChannel fromAsynchronousByteChannel(
    @NotNull
    AsynchronousByteChannel channel
  );
}

prehashPassword

Utility function to hash a password client side.

@NotNull
public String prehashPassword(@NotNull String password)

This function is only useful in the specific case described in the verification by passphrase guide.