This document describes:
Termius uses the username and password authentication. After successful authentication, the app uses the password as a key for data encryption as described later in this article.
For authenticating in the Termius cloud, the app communicates with the server in a way that prevents sending a password or password hash over the network using a modified SRP6a protocol. The authentication process looks like this:
To complete authentication, the client and the Termius cloud must prove that each party has the same key:
The client gets a random piece of data from the Termius cloud, salt for Argon2id password hash and User Identifier.
The client sends its random data and client proof.
The client gets a server proof, an encrypted API Key and a salt.
The client validates the server proof and decrypts the API Key.
For authenticating in the Termius cloud, the app calculates the SHA256 of the password and sends it using HTTPS-protected REST API. The Termius cloud calculates PBKDF2 hash using the default Django implementation.
Termius uses hybrid (new) encryption for personal data that has been migrated to this type of encryption, and symmetric (old) encryption for other data.
The app generates a key pair for the user and syncs the private key encrypted by the user password.
Using the key pair, the app generates a personal encryption key for the user.
The app uses the personal encryption key to encrypt personal data.
Personal data that hasn't been migrated to the hybrid encryption is encrypted with the RNCryptor library.
iOS: open source one.
Android: custom one.
Desktop: custom one.
RNCryptor uses PBKDF2 with 10,000 rounds, encrypt-then-mac HMAC, and AES256-CBC with a random IV. For all data, Termius uses a single encryption key and HMAC key, both derived from the password used for authentication. Salts are generated on the sync server.
The encryption and HMAC keys are stored on the device, namely in:
Termius uses hybrid encryption for team shared data:
Each team member and the team admin has a key pair used for personal data encryption.
The team admin generates a team encryption key.
The team admin exchanges the team encryption key with each team member by encrypting the key using a team member's public key and utilizes the team admin’s private key for creating a MAC.
A team member decrypts the exchanged team encryption key with the private key and uses the team admin’s public key to verify the MAC.
The encryption of shared data and personal data uses a common schema because:
It allows implementing an option to restore an account when the password is lost.
It prevents re-encryption of the whole database on password change. The Termius team's experience shows that this is an error-prone action.
Termius uses Libsodium for encrypting team shared data and personal data that has been migrated to new encryption. Termius uses the 1.0.17 version of Libsodium and custom C++ binding for iOS, Android, and Desktop applications. Termius uses the following APIs in Libsodium:
For public-key encryption:
crypto_box_open_easy – it uses X25519 key exchange, XSalsa20 stream cipher, and Poly1305 MAC.
For secret key encryption:
crypto_secretbox_open_easy – it uses XSalsa20 stream cipher and Poly1305 MAC.
For password hashing:
crypto_pwhash with options:
MEMLIMIT_INTERACTIVE, and ARGON2ID13.
For generating a nonce:
Termius uses SPR implementation from Botan and GRPC over TLS as a transport for SRP protocol. Termius uses the 2.14.0 version of Botan and custom C++ binding for iOS, Android, and Desktop applications.
The encryption key and key pair are stored on the devices, namely in:
Android: shared preferences encrypted by a key stored in Android KeyStore.
Desktop: Electron IndexedDB encrypted by a key stored in OS Keychain when Keychain is available and in IndexedDB as a fallback.
Please, email us at [email protected].