From 1e8278122fa261fed14b89fba903607c9c81ef55 Mon Sep 17 00:00:00 2001 From: feiniks <36756310+feiniks@users.noreply.github.com> Date: Tue, 3 Sep 2024 18:33:43 +0800 Subject: [PATCH] Set salt when use pwd_hash (#688) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use fixed repo salt * Set default value --------- Co-authored-by: 杨赫然 --- common/password-hash.c | 4 ++-- common/rpc-service.c | 4 ++-- common/seafile-crypt.c | 24 +++++++++++++++++---- common/seafile-crypt.h | 6 ++++-- server/passwd-mgr.c | 2 +- server/repo-mgr.c | 2 +- server/virtual-repo.c | 5 +++-- tests/test_password/test_password.py | 32 ++++++++++++++++++++++++++++ 8 files changed, 65 insertions(+), 14 deletions(-) diff --git a/common/password-hash.c b/common/password-hash.c index b0cd13e1..27e2bfa9 100644 --- a/common/password-hash.c +++ b/common/password-hash.c @@ -43,7 +43,7 @@ pbkdf2_sha256_derive_key (const char *data_in, int in_len, { int iteration = params->iteration; - unsigned char salt_bin[32]; + unsigned char salt_bin[32] = {0}; hex_to_rawdata (salt, salt_bin, 32); PKCS5_PBKDF2_HMAC (data_in, in_len, @@ -110,7 +110,7 @@ argon2id_derive_key (const char *data_in, int in_len, Argon2idParams *params, unsigned char *key) { - unsigned char salt_bin[32]; + unsigned char salt_bin[32] = {0}; hex_to_rawdata (salt, salt_bin, 32); argon2id_hash_raw(params->time_cost, params->memory_cost, params->parallelism, diff --git a/common/rpc-service.c b/common/rpc-service.c index d896184d..cf7e9542 100644 --- a/common/rpc-service.c +++ b/common/rpc-service.c @@ -1046,7 +1046,7 @@ seafile_change_repo_passwd (const char *repo_id, } if (repo->pwd_hash_algo) { - if (seafile_pwd_hash_verify_repo_passwd (repo_id, old_passwd, repo->salt, + if (seafile_pwd_hash_verify_repo_passwd (repo->enc_version, repo_id, old_passwd, repo->salt, repo->pwd_hash, repo->pwd_hash_algo, repo->pwd_hash_params) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Incorrect password"); return -1; @@ -1072,7 +1072,7 @@ seafile_change_repo_passwd (const char *repo_id, char new_magic[65], new_pwd_hash[65], new_random_key[97]; if (repo->pwd_hash_algo) { - seafile_generate_pwd_hash (repo_id, new_passwd, repo->salt, + seafile_generate_pwd_hash (repo->enc_version, repo_id, new_passwd, repo->salt, repo->pwd_hash_algo, repo->pwd_hash_params, new_pwd_hash); } else { seafile_generate_magic (repo->enc_version, repo_id, new_passwd, repo->salt, diff --git a/common/seafile-crypt.c b/common/seafile-crypt.c index 7e140ad9..c0d72bc7 100644 --- a/common/seafile-crypt.c +++ b/common/seafile-crypt.c @@ -158,7 +158,8 @@ seafile_generate_magic (int version, const char *repo_id, } void -seafile_generate_pwd_hash (const char *repo_id, +seafile_generate_pwd_hash (int version, + const char *repo_id, const char *passwd, const char *repo_salt, const char *algo, @@ -174,7 +175,14 @@ seafile_generate_pwd_hash (const char *repo_id, */ g_string_append_printf (buf, "%s%s", repo_id, passwd); - pwd_hash_derive_key (buf->str, buf->len, repo_salt, algo, params_str, key); + if (version <= 2) { + // use fixed repo salt + char fixed_salt[64] = {0}; + rawdata_to_hex(salt, fixed_salt, 8); + pwd_hash_derive_key (buf->str, buf->len, fixed_salt, algo, params_str, key); + } else { + pwd_hash_derive_key (buf->str, buf->len, repo_salt, algo, params_str, key); + } g_string_free (buf, TRUE); rawdata_to_hex (key, pwd_hash, 32); @@ -214,7 +222,8 @@ seafile_verify_repo_passwd (const char *repo_id, } int -seafile_pwd_hash_verify_repo_passwd (const char *repo_id, +seafile_pwd_hash_verify_repo_passwd (int version, + const char *repo_id, const char *passwd, const char *repo_salt, const char *pwd_hash, @@ -227,7 +236,14 @@ seafile_pwd_hash_verify_repo_passwd (const char *repo_id, g_string_append_printf (buf, "%s%s", repo_id, passwd); - pwd_hash_derive_key (buf->str, buf->len, repo_salt, algo, params_str, key); + if (version <= 2) { + // use fixed repo salt + char fixed_salt[64] = {0}; + rawdata_to_hex(salt, fixed_salt, 8); + pwd_hash_derive_key (buf->str, buf->len, fixed_salt, algo, params_str, key); + } else { + pwd_hash_derive_key (buf->str, buf->len, repo_salt, algo, params_str, key); + } g_string_free (buf, TRUE); rawdata_to_hex (key, hex, 32); diff --git a/common/seafile-crypt.h b/common/seafile-crypt.h index 2a11bd11..56b88436 100644 --- a/common/seafile-crypt.h +++ b/common/seafile-crypt.h @@ -78,7 +78,8 @@ seafile_generate_magic (int version, const char *repo_id, char *magic); void -seafile_generate_pwd_hash (const char *repo_id, +seafile_generate_pwd_hash (int version, + const char *repo_id, const char *passwd, const char *repo_salt, const char *algo, @@ -93,7 +94,8 @@ seafile_verify_repo_passwd (const char *repo_id, const char *repo_salt); int -seafile_pwd_hash_verify_repo_passwd (const char *repo_id, +seafile_pwd_hash_verify_repo_passwd (int version, + const char *repo_id, const char *passwd, const char *repo_salt, const char *pwd_hash, diff --git a/server/passwd-mgr.c b/server/passwd-mgr.c index 36a68af5..26cdc492 100644 --- a/server/passwd-mgr.c +++ b/server/passwd-mgr.c @@ -126,7 +126,7 @@ seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, } if (repo->pwd_hash_algo) { - if (seafile_pwd_hash_verify_repo_passwd (repo->id, passwd, repo->salt, + if (seafile_pwd_hash_verify_repo_passwd (repo->enc_version, repo->id, passwd, repo->salt, repo->pwd_hash, repo->pwd_hash_algo, repo->pwd_hash_params) < 0) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, diff --git a/server/repo-mgr.c b/server/repo-mgr.c index 205c00c0..53bd95e3 100644 --- a/server/repo-mgr.c +++ b/server/repo-mgr.c @@ -3945,7 +3945,7 @@ seaf_repo_manager_create_new_repo (SeafRepoManager *mgr, goto bad; } if (algo != NULL) { - seafile_generate_pwd_hash (repo_id, passwd, salt, algo, params, pwd_hash); + seafile_generate_pwd_hash (enc_version, repo_id, passwd, salt, algo, params, pwd_hash); } else { seafile_generate_magic (enc_version, repo_id, passwd, salt, magic); } diff --git a/server/virtual-repo.c b/server/virtual-repo.c index f825c899..7c63145e 100644 --- a/server/virtual-repo.c +++ b/server/virtual-repo.c @@ -90,7 +90,7 @@ do_create_virtual_repo (SeafRepoManager *mgr, if (origin_repo->pwd_hash_params) repo->pwd_hash_params = g_strdup (origin_repo->pwd_hash_params); if (repo->pwd_hash_algo) { - seafile_generate_pwd_hash (repo_id, passwd, repo->salt, + seafile_generate_pwd_hash (repo->enc_version, repo_id, passwd, repo->salt, repo->pwd_hash_algo, repo->pwd_hash_params, repo->pwd_hash); memcpy (repo->magic, repo->pwd_hash, 32); } else @@ -231,7 +231,8 @@ create_virtual_repo_common (SeafRepoManager *mgr, } if (origin_repo->pwd_hash_algo) { - if (seafile_pwd_hash_verify_repo_passwd (origin_repo_id, + if (seafile_pwd_hash_verify_repo_passwd (origin_repo->enc_version, + origin_repo_id, passwd, origin_repo->salt, origin_repo->pwd_hash, diff --git a/tests/test_password/test_password.py b/tests/test_password/test_password.py index d0b76b64..966ed610 100644 --- a/tests/test_password/test_password.py +++ b/tests/test_password/test_password.py @@ -47,3 +47,35 @@ def test_encrypted_repo(rpc, enc_version): assert api.is_password_set(repo.id, USER) == 0 api.remove_repo(repo_id) + +@pytest.mark.parametrize('rpc, enc_version, algo, params', + [('create_repo', 2, 'pbkdf2_sha256', '1000'), ('create_repo', 3, 'pbkdf2_sha256', '1000'), ('create_repo', 4, 'pbkdf2_sha256', '1000'), + ('create_repo', 2, 'argon2id', '2,102400,8'), ('create_repo', 3, 'argon2id', '2,102400,8'), ('create_repo', 4, 'argon2id', '2,102400,8')]) +def test_pwd_hash(rpc, enc_version, algo, params): + test_repo_name = 'test_enc_repo' + test_repo_desc = 'test_enc_repo' + test_repo_passwd = 'test_enc_repo' + repo_id = api.create_repo(test_repo_name, test_repo_desc, USER, + test_repo_passwd, enc_version, pwd_hash_algo=algo, pwd_hash_params=params) + assert repo_id + + repo = api.get_repo(repo_id) + assert repo + assert repo.enc_version == enc_version + assert len(repo.pwd_hash) == 64 + assert len(repo.random_key) == 96 + if enc_version > 2: + assert len(repo.salt) == 64 + + new_passwd = 'new password' + + assert api.set_passwd(repo.id, USER, test_repo_passwd) == 0 + assert api.get_decrypt_key(repo.id, USER) + api.change_repo_passwd(repo.repo_id, test_repo_passwd, new_passwd, USER) == 0 + assert api.set_passwd(repo.id, USER, new_passwd) == 0 + + assert api.is_password_set(repo.id, USER) + assert api.unset_passwd(repo.id, USER) == 0 + assert api.is_password_set(repo.id, USER) == 0 + + api.remove_repo(repo_id)