End-to-End Encryption
This topic includes details on using end-to-end encryption in the Vonage Video Android client SDK:
- Setting the encryption secret
- Events and errors
- Setting a secret in a session without end-to-end encryption
For an overview of end-to-end encryption, see this topic.
Setting the encryption secret
End-to-end encrypted sessions are created using server APIs (see Enabling encryption using the REST API).
Before the client publishes or subscribes, call the Session.setEncryptionSecret() method:
session.setEncryptionSecret("encryption-secret");
session.connect(TOKEN);
A valid secret is a string between 8 and 256 characters. You can change the secret by calling the Session.setEncryptionSecret() function again.
Setting an invalid secret will result in an InvalidEncryptionSecret error.
Events and errors
Events and errors are essential to managing the behavior of user-driven encryption behavior. End-to-end encryption uses the shared secret model: everyone in the session is expected to use the same secret to encrypt their media and decrypt everyone else's.
If a client tries to connect to an end-to-end encrypted session without setting an encryption secret, the SessionListener.onError() event handler is called with an error code set to ErrorCode.EncryptionSecretMissing:
// Implementation of SessionListener.onError():
@Override
public void onError(Session session, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionSecretMissing) {
// Notify the user that they cannot join the session
}
}
session.connect(token);
If a user tries to publish in an end-to-end encrypted session without having specified an encryption secret, calling the Session.publish() method results in the PublisherListener.onError() event handler being called with an error that has the code set to ErrorCode.EncryptionSecretMissing. For the best user experience, the application should validate a user-supplied secret before calling the Session.publish() method:
// Implementation of PublisherListener.onError():
@Override
public void onError(PublisherKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionInternalError) {
// The application should communicate that the secret was not set.
}
}
session.publish(publisher);
If a subscriber is unable to decode a stream's media due to an incorrect encryption secret, the SubscriberListener.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionSecretMismatch. It is important to communicate to the user that media is not being received due to an encryption mismatch and not due to a connection failure or audio/video issue:
// Implementation of Subscriber.onError():
@Override
public void onError(SubscriberKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionSecretMismatch) {
// Activate a UI element communicating that there's been an encryption secret mismatch.
}
}
session.subscribe(subscriber);
If the application tries to subscribe without setting an encryption secret, the Subscriber.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionSecretMissing.
If a subscriber encounters an internal error while decrypting a packet, the Subscriber.onError() event handler is called with an error that has the code set to ErrorCode.DecryptionInternalError.
Setting a secret in a session without end-to-end encryption
Note: This behavior is available starting with version 2.36.0 of the SDK.
If a session was not created with end-to-end encryption enabled, setting an encryption secret for it results in an ErrorCode.EncryptionNotEnabled error. Where the error surfaces depends on when the secret is set relative to connecting, publishing, and subscribing.
Setting the secret before connecting
Whether a session has end-to-end encryption enabled is only known once the client connects. If you call Session.setEncryptionSecret() before connecting, the call succeeds and the session connects normally. The error is reported when the client publishes or subscribes: calling Session.publish() or Session.subscribe() results in the SessionListener.onError() event handler being called with an error that has the code set to ErrorCode.EncryptionNotEnabled:
// Implementation of SessionListener.onError():
@Override
public void onError(Session session, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionNotEnabled) {
// The application should communicate that end-to-end encryption
// is not enabled for this session.
}
}
session.setEncryptionSecret("encryption-secret");
session.connect(TOKEN);
// ...
session.publish(publisher);
Setting the secret after connecting
If you call Session.setEncryptionSecret() after the client has connected to a session without end-to-end encryption, the secret is not set and the SessionListener.onError() event handler is called with an error that has the code set to ErrorCode.EncryptionNotEnabled.
Setting the secret while publishing or subscribing
If you call Session.setEncryptionSecret() while the client is already publishing or subscribing, the call fails as described above, and every active publisher and subscriber is also removed from the session. Each one reports the error through its own onError() event handler — PublisherListener.onError() for publishers and SubscriberListener.onError() for subscribers — with the code set to ErrorCode.EncryptionNotEnabled:
// Implementation of PublisherListener.onError():
@Override
public void onError(PublisherKit publisher, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionNotEnabled) {
// The publisher has been removed from the session.
}
}
// Implementation of SubscriberListener.onError():
@Override
public void onError(SubscriberKit subscriber, OpentokError opentokError) {
if (opentokError.getErrorCode() == ErrorCode.EncryptionNotEnabled) {
// The subscriber has been removed from the session.
}
}
Recovering from the error
The session remains valid after any of these errors. To publish or subscribe again, clear the secret by calling Session.setEncryptionSecret() with null. The same PublisherKit object can then be passed to Session.publish() again:
session.setEncryptionSecret(null);
session.publish(publisher);