aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2022-05-23 17:31:53 +0200
committerAlex Auvolat <alex@adnab.me>2022-05-23 17:31:53 +0200
commitcb9b64a184470c7f332eb2c20bf64d53e84406f1 (patch)
tree992ae5d5cc8c22d7e9a4974028f914e9b3ba50ce /README.md
parent378cbd76d0ce97e24941a81ff57c210c0342bd01 (diff)
downloadaerogramme-cb9b64a184470c7f332eb2c20bf64d53e84406f1.tar.gz
aerogramme-cb9b64a184470c7f332eb2c20bf64d53e84406f1.zip
Add user secret in mix to encrypt keys with password
Diffstat (limited to 'README.md')
-rw-r--r--README.md22
1 files changed, 14 insertions, 8 deletions
diff --git a/README.md b/README.md
index 8880183..48d1088 100644
--- a/README.md
+++ b/README.md
@@ -61,19 +61,25 @@ Keys that are stored in K2V under PK `keys`:
- 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`)
+ - 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**(`password`):
+- **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(password)`
+ - calculate `key = argon2_Skey(user_secret + password)`
- serialize `box_contents = (private, master)`
- seal box `blob = seal_key(box_contents)`
- write `S` at `"salt"`
@@ -87,12 +93,12 @@ Operations:
- calculate `public` the public key associated with `private`
- write `public` at `"public"`
-- **Open**(`password`):
+- **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(password)`
+ - 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")`
@@ -101,18 +107,18 @@ Operations:
- load `public = read("public")`
- check that `public` is the correct public key associated with `private`
-- **AddPassword**(`existing_password`, `new_password`):
+- **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(existing_password)`
+ - 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(new_password)`
+ - 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])}"`