This page will explain the specific algorithms and methods Turtl uses to encrypt, decrypt, (de)serialize, and authenticate data.
Every encrypted object in Turtl has its own key. This goes for spaces, boards, and notes. This means that every object can be decrypted independently of the profile’s master key (generated from the user’s authentication info).
Encrypted objects have the ability to store their own key in their data, encrypted via another object’s key. Sounds confusing, so the primary example would be this: Note A has its own key that will decrypt its data. Note A is in Space B. Note A’s data contains Note A’s key encrypted with Space B’s key. So if Alice shares Space B with Bob, she can share Space B’s key, and now Bob has the ability to decrypt any note in Space B (including Note A).
This is what allows objects to be sharable in Turtl without compromising the master key…sharing can be done granularly and on a per-object basis. That said the only objects that are currently sharable in Turtl are spaces.
As of v0.7.0, Turtl now handles all encryption in the Turtl core, which uses libsodium under the hood for all cryptographic operation.
When you log in, Turtl takes your email (as a salt) and your password (as the main input) and runs them through libsodium’s default key-derivation function (scryptsalsa208sha256).
The resulting key is your account’s master key.
Turtl uses libsodium for all low level encryption. Symmetric encryption uses the chacha20poly1305 (IETF) algorithm, and asymmetric crypto uses the more abstract libsodium sealed box.
Turtl packs encrypted data in the following binary format:
|-2 bytes-| |-1 byte----| |-N bytes-----------| |-1 byte-----| |-N bytes-| |-N bytes--|
| version | |desc length| |payload description| |nonce length| | nonce | |ciphertext|
The chacha20poly1305 algorithm handles payload authentication internally, which
means that the ciphertext
itself has a tag used to verify that it has not been
modified in any way.
Data encrypted with the sealed box algorithm is in the following format:
|-1 byte--| |-N bytes--|
| version | |ciphertext|
Note that because the sealed box handles the serialization for us, our own format is painfully simple, and just includes a version that lets us switch algorithms/formats later on if needed.