diff options
author | Quentin Dufour <quentin@deuxfleurs.fr> | 2024-05-29 10:14:51 +0200 |
---|---|---|
committer | Quentin Dufour <quentin@deuxfleurs.fr> | 2024-05-29 10:14:51 +0200 |
commit | b9ce5886033677f6c65a4b873e17574fdb8df31d (patch) | |
tree | 9ed1d721361027d7d6fef0ecad65d7e1b74a7ddb /doc/src/crypt-key.md | |
parent | 0dcf69f180f5a7b71b6ad2ac67e4cdd81e5154f1 (diff) | |
parent | 5954de6efbb040b8b47daf0c7663a60f3db1da6e (diff) | |
download | aerogramme-b9ce5886033677f6c65a4b873e17574fdb8df31d.tar.gz aerogramme-b9ce5886033677f6c65a4b873e17574fdb8df31d.zip |
Merge branch 'caldav'
Diffstat (limited to 'doc/src/crypt-key.md')
-rw-r--r-- | doc/src/crypt-key.md | 82 |
1 files changed, 0 insertions, 82 deletions
diff --git a/doc/src/crypt-key.md b/doc/src/crypt-key.md deleted file mode 100644 index 9fb199b..0000000 --- a/doc/src/crypt-key.md +++ /dev/null @@ -1,82 +0,0 @@ -# Cryptography & key management - -Keys that are used: - -- master secret key (for indexes) -- curve25519 public/private key pair (for incoming mail) - -Keys that are stored in K2V under PK `keys`: - -- `public`: the public curve25519 key (plain text) -- `salt`: the 32-byte salt `S` used to calculate digests that index keys below -- if a password is used, `password:<truncated(128bit) argon2 digest of password using salt S>`: - - a 32-byte salt `Skey` - - followed a secret box - - that is encrypted with a strong argon2 digest of the password (using the salt `Skey`) and a user secret (see below) - - that contains the master secret key and the curve25519 private key - -User secret: an additionnal secret that is added to the password when deriving the encryption key for the secret box. -This additionnal secret should not be stored in K2V/S3, so that just knowing a user's password isn't enough to be able -to decrypt their mailbox (supposing the attacker has a dump of their K2V/S3 bucket). -This user secret should typically be stored in the LDAP database or just in the configuration file when using -the static login provider. - -Operations: - -- **Initialize**(`user_secret`, `password`): - - if `"salt"` or `"public"` already exist, BAIL - - generate salt `S` (32 random bytes) - - generate `public`, `private` (curve25519 keypair) - - generate `master` (secretbox secret key) - - calculate `digest = argon2_S(password)` - - generate salt `Skey` (32 random bytes) - - calculate `key = argon2_Skey(user_secret + password)` - - serialize `box_contents = (private, master)` - - seal box `blob = seal_key(box_contents)` - - write `S` at `"salt"` - - write `concat(Skey, blob)` at `"password:{hex(digest[..16])}"` - - write `public` at `"public"` - -- **InitializeWithoutPassword**(`private`, `master`): - - if `"salt"` or `"public"` already exist, BAIL - - generate salt `S` (32 random bytes) - - write `S` at `"salt"` - - calculate `public` the public key associated with `private` - - write `public` at `"public"` - -- **Open**(`user_secret`, `password`): - - load `S = read("salt")` - - calculate `digest = argon2_S(password)` - - load `blob = read("password:{hex(digest[..16])}") - - set `Skey = blob[..32]` - - calculate `key = argon2_Skey(user_secret + password)` - - open secret box `box_contents = open_key(blob[32..])` - - retrieve `master` and `private` from `box_contents` - - retrieve `public = read("public")` - -- **OpenWithoutPassword**(`private`, `master`): - - load `public = read("public")` - - check that `public` is the correct public key associated with `private` - -- **AddPassword**(`user_secret`, `existing_password`, `new_password`): - - load `S = read("salt")` - - calculate `digest = argon2_S(existing_password)` - - load `blob = read("existing_password:{hex(digest[..16])}") - - set `Skey = blob[..32]` - - calculate `key = argon2_Skey(user_secret + existing_password)` - - open secret box `box_contents = open_key(blob[32..])` - - retrieve `master` and `private` from `box_contents` - - - calculate `digest_new = argon2_S(new_password)` - - generate salt `Skeynew` (32 random bytes) - - calculate `key_new = argon2_Skeynew(user_secret + new_password)` - - serialize `box_contents_new = (private, master)` - - seal box `blob_new = seal_key_new(box_contents_new)` - - write `concat(Skeynew, blob_new)` at `"new_password:{hex(digest_new[..16])}"` - -- **RemovePassword**(`password`): - - load `S = read("salt")` - - calculate `digest = argon2_S(existing_password)` - - check that `"password:{hex(digest[..16])}"` exists - - check that other passwords exist ?? (or not) - - delete `"password:{hex(digest[..16])}"` |