diff --git a/common/commit-mgr.c b/common/commit-mgr.c index aae721f..2227e5f 100644 --- a/common/commit-mgr.c +++ b/common/commit-mgr.c @@ -650,8 +650,10 @@ commit_to_json_object (SeafCommit *commit) json_object_set_int_member (object, "enc_version", commit->enc_version); if (commit->enc_version >= 1) json_object_set_string_member (object, "magic", commit->magic); - if (commit->enc_version == 2) + if (commit->enc_version >= 2) json_object_set_string_member (object, "key", commit->random_key); + if (commit->enc_version >= 3) + json_object_set_string_member (object, "salt", commit->salt); } if (commit->no_local_history) json_object_set_int_member (object, "no_local_history", 1); @@ -687,6 +689,7 @@ commit_from_json_object (const char *commit_id, json_t *object) int enc_version = 0; const char *magic = NULL; const char *random_key = NULL; + const char *salt = NULL; int no_local_history = 0; int version = 0; int conflict = 0, new_merge = 0; @@ -723,8 +726,10 @@ commit_from_json_object (const char *commit_id, json_t *object) magic = json_object_get_string_member (object, "magic"); } - if (enc_version == 2) + if (enc_version >= 2) random_key = json_object_get_string_member (object, "key"); + if (enc_version >= 3) + salt = json_object_get_string_member (object, "salt"); if (json_object_has_member (object, "no_local_history")) no_local_history = json_object_get_int_member (object, "no_local_history"); @@ -762,6 +767,14 @@ commit_from_json_object (const char *commit_id, json_t *object) if (!random_key || strlen(random_key) != 96) return NULL; break; + case 3: + if (!magic || strlen(magic) != 64) + return NULL; + if (!random_key || strlen(random_key) != 96) + return NULL; + if (!salt || strlen(salt) != 64) + return NULL; + break; default: seaf_warning ("Unknown encryption version %d.\n", enc_version); return NULL; @@ -790,8 +803,10 @@ commit_from_json_object (const char *commit_id, json_t *object) commit->enc_version = enc_version; if (enc_version >= 1) commit->magic = g_strdup(magic); - if (enc_version == 2) + if (enc_version >= 2) commit->random_key = g_strdup (random_key); + if (enc_version >= 3) + commit->salt = g_strdup(salt); } if (no_local_history) commit->no_local_history = TRUE; diff --git a/common/commit-mgr.h b/common/commit-mgr.h index 6b0a246..2784230 100644 --- a/common/commit-mgr.h +++ b/common/commit-mgr.h @@ -35,6 +35,7 @@ struct _SeafCommit { int enc_version; char *magic; char *random_key; + char *salt; gboolean no_local_history; int version; diff --git a/common/common.h b/common/common.h index 959e2bb..6284ef0 100644 --- a/common/common.h +++ b/common/common.h @@ -22,7 +22,7 @@ #define EMPTY_SHA1 "0000000000000000000000000000000000000000" -#define CURRENT_ENC_VERSION 2 +#define CURRENT_ENC_VERSION 3 #define DEFAULT_PROTO_VERSION 1 #define CURRENT_PROTO_VERSION 7 diff --git a/common/rpc-service.c b/common/rpc-service.c index cf41c15..8d02bc8 100644 --- a/common/rpc-service.c +++ b/common/rpc-service.c @@ -73,8 +73,12 @@ convert_repo (SeafRepo *r) NULL); } - if (r->encrypted && r->enc_version == 2) - g_object_set (repo, "random_key", r->random_key, NULL); + if (r->encrypted) { + if (r->enc_version >= 2) + g_object_set (repo, "random_key", r->random_key, NULL); + if (r->enc_version >= 3) + g_object_set (repo, "salt", r->salt, NULL); + } g_object_set (repo, "store_id", r->store_id, "repaired", r->repaired, @@ -1502,20 +1506,29 @@ seafile_generate_magic_and_random_key(int enc_version, return NULL; } + gchar salt[65] = {0}; gchar magic[65] = {0}; gchar random_key[97] = {0}; - seafile_generate_magic (CURRENT_ENC_VERSION, repo_id, passwd, magic); - seafile_generate_random_key (passwd, random_key); + if (enc_version >= 3 && seafile_generate_repo_salt (salt) < 0) { + return NULL; + } + + seafile_generate_magic (enc_version, repo_id, passwd, salt, magic); + if (seafile_generate_random_key (passwd, enc_version, salt, random_key) < 0) { + return NULL; + } SeafileEncryptionInfo *sinfo; sinfo = g_object_new (SEAFILE_TYPE_ENCRYPTION_INFO, "repo_id", repo_id, "passwd", passwd, - "enc_version", CURRENT_ENC_VERSION, + "enc_version", enc_version, "magic", magic, "random_key", random_key, NULL); + if (enc_version >= 3) + g_object_set (sinfo, "salt", salt, NULL); return (GObject *)sinfo; @@ -1830,7 +1843,8 @@ retry: return -1; } - if (seafile_verify_repo_passwd (repo_id, old_passwd, repo->magic, 2) < 0) { + if (seafile_verify_repo_passwd (repo_id, old_passwd, repo->magic, + repo->enc_version, repo->salt) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Incorrect password"); return -1; } @@ -1847,9 +1861,10 @@ retry: char new_magic[65], new_random_key[97]; - seafile_generate_magic (2, repo_id, new_passwd, new_magic); + seafile_generate_magic (repo->enc_version, repo_id, new_passwd, repo->salt, new_magic); if (seafile_update_random_key (old_passwd, repo->random_key, - new_passwd, new_random_key) < 0) { + new_passwd, new_random_key, + repo->enc_version, repo->salt) < 0) { ret = -1; goto out; } @@ -3886,6 +3901,7 @@ seafile_create_repo (const char *repo_name, const char *repo_desc, const char *owner_email, const char *passwd, + int enc_version, GError **error) { if (!repo_name || !repo_desc || !owner_email) { @@ -3899,6 +3915,7 @@ seafile_create_repo (const char *repo_name, repo_name, repo_desc, owner_email, passwd, + enc_version, error); return repo_id; } @@ -3910,6 +3927,7 @@ seafile_create_enc_repo (const char *repo_id, const char *owner_email, const char *magic, const char *random_key, + const char *salt, int enc_version, GError **error) { @@ -3921,10 +3939,10 @@ seafile_create_enc_repo (const char *repo_id, char *ret; ret = seaf_repo_manager_create_enc_repo (seaf->repo_mgr, - repo_id, repo_name, repo_desc, - owner_email, - magic, random_key, enc_version, - error); + repo_id, repo_name, repo_desc, + owner_email, + magic, random_key, salt, enc_version, + error); return ret; } diff --git a/common/seafile-crypt.c b/common/seafile-crypt.c index c7d1702..d856c92 100644 --- a/common/seafile-crypt.c +++ b/common/seafile-crypt.c @@ -37,9 +37,25 @@ seafile_crypt_new (int version, unsigned char *key, unsigned char *iv) int seafile_derive_key (const char *data_in, int in_len, int version, + const char *repo_salt, unsigned char *key, unsigned char *iv) { - if (version == 2) { + if (version == 3) { + unsigned char repo_salt_bin[32]; + hex_to_rawdata (repo_salt, repo_salt_bin, 32); + + PKCS5_PBKDF2_HMAC (data_in, in_len, + repo_salt_bin, sizeof(repo_salt_bin), + KEYGEN_ITERATION2, + EVP_sha256(), + 32, key); + PKCS5_PBKDF2_HMAC ((char *)key, 32, + repo_salt_bin, sizeof(repo_salt_bin), + 10, + EVP_sha256(), + 16, iv); + return 0; + } else if (version == 2) { PKCS5_PBKDF2_HMAC (data_in, in_len, salt, sizeof(salt), KEYGEN_ITERATION2, @@ -71,8 +87,27 @@ seafile_derive_key (const char *data_in, int in_len, int version, iv); /* IV, initial vector */ } -void -seafile_generate_random_key (const char *passwd, char *random_key) +int +seafile_generate_repo_salt (char *repo_salt) +{ + unsigned char repo_salt_bin[32]; + + int rc = RAND_bytes (repo_salt_bin, sizeof(repo_salt_bin)); + if (rc != 1) { + seaf_warning ("Failed to generate salt for repo encryption.\n"); + return -1; + } + + rawdata_to_hex (repo_salt_bin, repo_salt, 32); + + return 0; +} + +int +seafile_generate_random_key (const char *passwd, + int version, + const char *repo_salt, + char *random_key) { SeafileCrypt *crypt; unsigned char secret_key[32], *rand_key; @@ -81,14 +116,13 @@ seafile_generate_random_key (const char *passwd, char *random_key) int rc = RAND_bytes (secret_key, sizeof(secret_key)); if (rc != 1) { - seaf_warning ("Failed to generate secret key for repo encryption " - "with RAND_bytes(), use RAND_pseudo_bytes().\n"); - RAND_pseudo_bytes (secret_key, sizeof(secret_key)); + seaf_warning ("Failed to generate secret key for repo encryption.\n"); + return -1; } - seafile_derive_key (passwd, strlen(passwd), 2, key, iv); + seafile_derive_key (passwd, strlen(passwd), version, repo_salt, key, iv); - crypt = seafile_crypt_new (2, key, iv); + crypt = seafile_crypt_new (version, key, iv); seafile_encrypt ((char **)&rand_key, &outlen, (char *)secret_key, sizeof(secret_key), crypt); @@ -97,11 +131,15 @@ seafile_generate_random_key (const char *passwd, char *random_key) g_free (crypt); g_free (rand_key); + + return 0; } void seafile_generate_magic (int version, const char *repo_id, - const char *passwd, char *magic) + const char *passwd, + const char *repo_salt, + char *magic) { GString *buf = g_string_new (NULL); unsigned char key[32], iv[16]; @@ -112,7 +150,7 @@ seafile_generate_magic (int version, const char *repo_id, */ g_string_append_printf (buf, "%s%s", repo_id, passwd); - seafile_derive_key (buf->str, buf->len, version, key, iv); + seafile_derive_key (buf->str, buf->len, version, repo_salt, key, iv); g_string_free (buf, TRUE); rawdata_to_hex (key, magic, 32); @@ -122,13 +160,14 @@ int seafile_verify_repo_passwd (const char *repo_id, const char *passwd, const char *magic, - int version) + int version, + const char *repo_salt) { GString *buf = g_string_new (NULL); unsigned char key[32], iv[16]; char hex[65]; - if (version != 1 && version != 2) { + if (version != 1 && version != 2 && version != 3) { seaf_warning ("Unsupported enc_version %d.\n", version); return -1; } @@ -136,10 +175,10 @@ seafile_verify_repo_passwd (const char *repo_id, /* Recompute the magic and compare it with the one comes with the repo. */ g_string_append_printf (buf, "%s%s", repo_id, passwd); - seafile_derive_key (buf->str, buf->len, version, key, iv); + seafile_derive_key (buf->str, buf->len, version, repo_salt, key, iv); g_string_free (buf, TRUE); - if (version == 2) + if (version >= 2) rawdata_to_hex (key, hex, 32); else rawdata_to_hex (key, hex, 16); @@ -153,17 +192,18 @@ seafile_verify_repo_passwd (const char *repo_id, int seafile_decrypt_repo_enc_key (int enc_version, const char *passwd, const char *random_key, + const char *repo_salt, unsigned char *key_out, unsigned char *iv_out) { unsigned char key[32], iv[16]; - seafile_derive_key (passwd, strlen(passwd), enc_version, key, iv); + seafile_derive_key (passwd, strlen(passwd), enc_version, repo_salt, key, iv); if (enc_version == 1) { memcpy (key_out, key, 16); memcpy (iv_out, iv, 16); return 0; - } else if (enc_version == 2) { + } else if (enc_version >= 2) { unsigned char enc_random_key[48], *dec_random_key; int outlen; SeafileCrypt *crypt; @@ -186,7 +226,8 @@ seafile_decrypt_repo_enc_key (int enc_version, g_free (crypt); seafile_derive_key ((char *)dec_random_key, 32, enc_version, - key, iv); + repo_salt, + key, iv); memcpy (key_out, key, 32); memcpy (iv_out, iv, 16); @@ -199,7 +240,8 @@ seafile_decrypt_repo_enc_key (int enc_version, int seafile_update_random_key (const char *old_passwd, const char *old_random_key, - const char *new_passwd, char *new_random_key) + const char *new_passwd, char *new_random_key, + int enc_version, const char *repo_salt) { unsigned char key[32], iv[16]; unsigned char random_key_raw[48], *secret_key, *new_random_key_raw; @@ -207,11 +249,12 @@ seafile_update_random_key (const char *old_passwd, const char *old_random_key, SeafileCrypt *crypt; /* First, use old_passwd to decrypt secret key from old_random_key. */ - seafile_derive_key (old_passwd, strlen(old_passwd), 2, key, iv); + seafile_derive_key (old_passwd, strlen(old_passwd), enc_version, + repo_salt, key, iv); hex_to_rawdata (old_random_key, random_key_raw, 48); - crypt = seafile_crypt_new (2, key, iv); + crypt = seafile_crypt_new (enc_version, key, iv); if (seafile_decrypt ((char **)&secret_key, &secret_key_len, (char *)random_key_raw, 48, crypt) < 0) { @@ -222,9 +265,10 @@ seafile_update_random_key (const char *old_passwd, const char *old_random_key, g_free (crypt); /* Second, use new_passwd to encrypt secret key. */ - seafile_derive_key (new_passwd, strlen(new_passwd), 2, key, iv); + seafile_derive_key (new_passwd, strlen(new_passwd), enc_version, + repo_salt, key, iv); - crypt = seafile_crypt_new (2, key, iv); + crypt = seafile_crypt_new (enc_version, key, iv); seafile_encrypt ((char **)&new_random_key_raw, &random_key_len, (char *)secret_key, secret_key_len, crypt); diff --git a/common/seafile-crypt.h b/common/seafile-crypt.h index 2d5756c..1d2ce4a 100644 --- a/common/seafile-crypt.h +++ b/common/seafile-crypt.h @@ -54,33 +54,46 @@ seafile_crypt_new (int version, unsigned char *key, unsigned char *iv); int seafile_derive_key (const char *data_in, int in_len, int version, + const char *repo_salt, unsigned char *key, unsigned char *iv); +/* @salt must be an char array of size 65 bytes. */ +int +seafile_generate_repo_salt (char *repo_salt); + /* * Generate the real key used to encrypt data. * The key 32 bytes long and encrpted with @passwd. */ -void -seafile_generate_random_key (const char *passwd, char *random_key); +int +seafile_generate_random_key (const char *passwd, + int version, + const char *repo_salt, + char *random_key); void seafile_generate_magic (int version, const char *repo_id, - const char *passwd, char *magic); + const char *passwd, + const char *repo_salt, + char *magic); int seafile_verify_repo_passwd (const char *repo_id, const char *passwd, const char *magic, - int version); + int version, + const char *repo_salt); int seafile_decrypt_repo_enc_key (int enc_version, - const char *passwd, const char *random_key, - unsigned char *key_out, unsigned char *iv_out); + const char *passwd, const char *random_key, + const char *repo_salt, + unsigned char *key_out, unsigned char *iv_out); int seafile_update_random_key (const char *old_passwd, const char *old_random_key, - const char *new_passwd, char *new_random_key); + const char *new_passwd, char *new_random_key, + int enc_version, const char *repo_salt); int seafile_encrypt (char **data_out, diff --git a/include/seafile-rpc.h b/include/seafile-rpc.h index 6fe02f5..9214599 100644 --- a/include/seafile-rpc.h +++ b/include/seafile-rpc.h @@ -905,6 +905,7 @@ seafile_create_repo (const char *repo_name, const char *repo_desc, const char *owner_email, const char *passwd, + int enc_version, GError **error); char * @@ -914,6 +915,7 @@ seafile_create_enc_repo (const char *repo_id, const char *owner_email, const char *magic, const char *random_key, + const char *salt, int enc_version, GError **error); diff --git a/lib/repo.vala b/lib/repo.vala index 482b384..9b6acd3 100644 --- a/lib/repo.vala +++ b/lib/repo.vala @@ -55,6 +55,7 @@ public class Repo : Object { public string magic { get; set; } public int enc_version { get; set; } public string random_key { get; set; } + public string salt { get; set; } // Section 3: Client only information // Should be set for all client repo objects @@ -200,6 +201,7 @@ public class EncryptionInfo: Object { public int enc_version { get; set; } public string magic { get; set; } public string random_key { get; set; } + public string salt { get; set; } } } // namespace diff --git a/lib/rpc_table.py b/lib/rpc_table.py index f696d50..55aa4e3 100644 --- a/lib/rpc_table.py +++ b/lib/rpc_table.py @@ -63,6 +63,7 @@ func_table = [ [ "string", ["string", "string", "string", "string", "string", "string", "int64"] ], [ "string", ["string", "string", "string", "string", "string", "string", "int64", "int"] ], [ "string", ["string", "string", "string", "string", "string", "string", "string"] ], + [ "string", ["string", "string", "string", "string", "string", "string", "string", "int"] ], [ "string", ["string", "string", "string", "string", "string", "string", "string", "int64"] ], [ "string", ["string", "string", "string", "string", "string", "string", "string", "string", "string"] ], [ "string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int", "string"] ], diff --git a/python/seafile/rpcclient.py b/python/seafile/rpcclient.py index 5349db4..027e48e 100644 --- a/python/seafile/rpcclient.py +++ b/python/seafile/rpcclient.py @@ -324,13 +324,13 @@ class SeafServerThreadedRpcClient(ccnet.RpcClientBase): *args, **kwargs) # repo manipulation - @searpc_func("string", ["string", "string", "string", "string"]) - def seafile_create_repo(name, desc, owner_email, passwd): + @searpc_func("string", ["string", "string", "string", "string", "int"]) + def seafile_create_repo(name, desc, owner_email, passwd, enc_version): pass create_repo = seafile_create_repo - @searpc_func("string", ["string", "string", "string", "string", "string", "string", "int"]) - def seafile_create_enc_repo(repo_id, name, desc, owner_email, magic, random_key, enc_version): + @searpc_func("string", ["string", "string", "string", "string", "string", "string", "string", "int"]) + def seafile_create_enc_repo(repo_id, name, desc, owner_email, magic, random_key, salt, enc_version): pass create_enc_repo = seafile_create_enc_repo @@ -789,7 +789,7 @@ class SeafServerThreadedRpcClient(ccnet.RpcClientBase): set_passwd = seafile_set_passwd @searpc_func("int", ["string", "string"]) - def seafile_unset_passwd(repo_id, user, passwd): + def seafile_unset_passwd(repo_id, user): pass unset_passwd = seafile_unset_passwd diff --git a/python/seaserv/api.py b/python/seaserv/api.py index ef7e50d..4de7466 100644 --- a/python/seaserv/api.py +++ b/python/seaserv/api.py @@ -79,19 +79,19 @@ class SeafileAPI(object): def set_passwd(self, repo_id, user, passwd): return seafserv_threaded_rpc.set_passwd(repo_id, user, passwd) - def unset_passwd(self, repo_id, user, passwd): - return seafserv_threaded_rpc.unset_passwd(repo_id, user, passwd) + def unset_passwd(self, repo_id, user): + return seafserv_threaded_rpc.unset_passwd(repo_id, user) def generate_magic_and_random_key(self, enc_version, repo_id, password): return seafserv_threaded_rpc.generate_magic_and_random_key(enc_version, repo_id, password) # repo manipulation - def create_repo(self, name, desc, username, passwd): - return seafserv_threaded_rpc.create_repo(name, desc, username, passwd) + def create_repo(self, name, desc, username, passwd, enc_version=2): + return seafserv_threaded_rpc.create_repo(name, desc, username, passwd, enc_version) - def create_enc_repo(self, repo_id, name, desc, username, magic, random_key, enc_version): - return seafserv_threaded_rpc.create_enc_repo(repo_id, name, desc, username, magic, random_key, enc_version) + def create_enc_repo(self, repo_id, name, desc, username, magic, random_key, salt, enc_version): + return seafserv_threaded_rpc.create_enc_repo(repo_id, name, desc, username, magic, random_key, salt, enc_version) def get_repo(self, repo_id): """ diff --git a/server/passwd-mgr.c b/server/passwd-mgr.c index 3fcc0ab..729a035 100644 --- a/server/passwd-mgr.c +++ b/server/passwd-mgr.c @@ -118,7 +118,7 @@ seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, return -1; } - if (repo->enc_version != 1 && repo->enc_version != 2) { + if (repo->enc_version != 1 && repo->enc_version != 2 && repo->enc_version != 3) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Unsupported encryption version"); @@ -126,7 +126,7 @@ seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, } if (seafile_verify_repo_passwd (repo->id, passwd, - repo->magic, repo->enc_version) < 0) { + repo->magic, repo->enc_version, repo->salt) < 0) { seaf_repo_unref (repo); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); @@ -142,7 +142,7 @@ seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr, return -1; } - if (seafile_decrypt_repo_enc_key (repo->enc_version, passwd, repo->random_key, + if (seafile_decrypt_repo_enc_key (repo->enc_version, passwd, repo->random_key, repo->salt, crypt_key->key, crypt_key->iv) < 0) { seaf_repo_unref (repo); g_free (crypt_key); @@ -220,7 +220,7 @@ seaf_passwd_manager_get_decrypt_key (SeafPasswdManager *mgr, return NULL; } - if (crypt_key->enc_version == 2) { + if (crypt_key->enc_version >= 2) { rawdata_to_hex (crypt_key->key, key_hex, 32); rawdata_to_hex (crypt_key->iv, iv_hex, 16); } else if (crypt_key->enc_version == 1) { @@ -258,7 +258,7 @@ seaf_passwd_manager_get_decrypt_key_raw (SeafPasswdManager *mgr, if (crypt_key->enc_version == 1) { memcpy (key_out, crypt_key->key, 16); memcpy (iv_out, crypt_key->iv, 16); - } else if (crypt_key->enc_version == 2) { + } else if (crypt_key->enc_version >= 2) { memcpy (key_out, crypt_key->key, 32); memcpy (iv_out, crypt_key->iv, 16); } diff --git a/server/processors/check-tx-slave-v2-proc.c b/server/processors/check-tx-slave-v2-proc.c index 14d26bd..f71e9ab 100644 --- a/server/processors/check-tx-slave-v2-proc.c +++ b/server/processors/check-tx-slave-v2-proc.c @@ -179,7 +179,7 @@ decrypt_token (CcnetProcessor *processor) seafile_derive_key (priv->session_key, strlen(priv->session_key), - 1, key, iv); + 1, NULL, 0, key, iv); crypt = seafile_crypt_new (1, key, iv); if (seafile_decrypt (&token, &token_len, encrypted_token, diff --git a/server/repo-mgr.c b/server/repo-mgr.c index 8b82573..fb9df0c 100644 --- a/server/repo-mgr.c +++ b/server/repo-mgr.c @@ -142,6 +142,10 @@ seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit) else if (repo->enc_version == 2) { memcpy (repo->magic, commit->magic, 64); memcpy (repo->random_key, commit->random_key, 96); + } else if (repo->enc_version == 3) { + memcpy (repo->magic, commit->magic, 64); + memcpy (repo->random_key, commit->random_key, 96); + memcpy (repo->salt, commit->salt, 64); } } repo->no_local_history = commit->no_local_history; @@ -163,6 +167,10 @@ seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit) else if (commit->enc_version == 2) { commit->magic = g_strdup (repo->magic); commit->random_key = g_strdup (repo->random_key); + } else if (commit->enc_version == 3) { + commit->magic = g_strdup (repo->magic); + commit->random_key = g_strdup (repo->random_key); + commit->salt = g_strdup (repo->salt); } } commit->no_local_history = repo->no_local_history; @@ -3476,6 +3484,7 @@ create_repo_common (SeafRepoManager *mgr, const char *user, const char *magic, const char *random_key, + const char *salt, int enc_version, GError **error) { @@ -3484,14 +3493,14 @@ create_repo_common (SeafRepoManager *mgr, SeafBranch *master = NULL; int ret = -1; - if (enc_version != 2 && enc_version != -1) { + if (enc_version != 3 && enc_version != 2 && enc_version != -1) { seaf_warning ("Unsupported enc version %d.\n", enc_version); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Unsupported encryption version"); return -1; } - if (enc_version == 2) { + if (enc_version >= 2) { if (!magic || strlen(magic) != 64) { seaf_warning ("Bad magic.\n"); g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, @@ -3505,16 +3514,26 @@ create_repo_common (SeafRepoManager *mgr, return -1; } } + if (enc_version >= 3) { + if (!salt || strlen(salt) != 64) { + seaf_warning ("Bad salt.\n"); + g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, + "Bad salt"); + return -1; + } + } repo = seaf_repo_new (repo_id, repo_name, repo_desc); repo->no_local_history = TRUE; - if (enc_version == 2) { + if (enc_version >= 2) { repo->encrypted = TRUE; repo->enc_version = enc_version; memcpy (repo->magic, magic, 64); memcpy (repo->random_key, random_key, 96); } + if (enc_version >= 3) + memcpy (repo->salt, salt, 64); repo->version = CURRENT_REPO_VERSION; memcpy (repo->store_id, repo_id, 36); @@ -3576,25 +3595,31 @@ seaf_repo_manager_create_new_repo (SeafRepoManager *mgr, const char *repo_desc, const char *owner_email, const char *passwd, + int enc_version, GError **error) { char *repo_id = NULL; - char magic[65], random_key[97]; + char salt[65], magic[65], random_key[97]; repo_id = gen_uuid (); if (passwd && passwd[0] != 0) { - seafile_generate_magic (2, repo_id, passwd, magic); - seafile_generate_random_key (passwd, random_key); + if (seafile_generate_repo_salt (salt) < 0) { + goto bad; + } + seafile_generate_magic (enc_version, repo_id, passwd, salt, magic); + if (seafile_generate_random_key (passwd, enc_version, salt, random_key) < 0) { + goto bad; + } } int rc; if (passwd) rc = create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email, - magic, random_key, CURRENT_ENC_VERSION, error); + magic, random_key, salt, enc_version, error); else rc = create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email, - NULL, NULL, -1, error); + NULL, NULL, NULL, -1, error); if (rc < 0) goto bad; @@ -3621,6 +3646,7 @@ seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr, const char *owner_email, const char *magic, const char *random_key, + const char *salt, int enc_version, GError **error) { @@ -3639,7 +3665,7 @@ seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr, } if (create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email, - magic, random_key, enc_version, error) < 0) + magic, random_key, salt, enc_version, error) < 0) return NULL; if (seaf_repo_manager_set_repo_owner (mgr, repo_id, owner_email) < 0) { diff --git a/server/repo-mgr.h b/server/repo-mgr.h index 8f73d93..ccc06b0 100644 --- a/server/repo-mgr.h +++ b/server/repo-mgr.h @@ -34,6 +34,7 @@ struct _SeafRepo { int enc_version; gchar magic[65]; /* hash(repo_id + passwd), key stretched. */ gchar random_key[97]; + gchar salt[65]; gboolean no_local_history; gint64 last_modify; gint64 size; @@ -498,6 +499,7 @@ seaf_repo_manager_create_new_repo (SeafRepoManager *mgr, const char *repo_desc, const char *owner_email, const char *passwd, + int enc_version, GError **error); char * @@ -508,6 +510,7 @@ seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr, const char *owner_email, const char *magic, const char *random_key, + const char *salt, int enc_version, GError **error); diff --git a/server/seaf-server.c b/server/seaf-server.c index b9df5e7..d02851d 100644 --- a/server/seaf-server.c +++ b/server/seaf-server.c @@ -266,12 +266,12 @@ static void start_rpc_service (CcnetClient *client, int cloud_mode) searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_create_repo, "seafile_create_repo", - searpc_signature_string__string_string_string_string()); + searpc_signature_string__string_string_string_string_int()); searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_create_enc_repo, "seafile_create_enc_repo", - searpc_signature_string__string_string_string_string_string_string_int()); + searpc_signature_string__string_string_string_string_string_string_string_int()); searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_get_commit, diff --git a/server/seafile-session.c b/server/seafile-session.c index 04155f5..8e91133 100644 --- a/server/seafile-session.c +++ b/server/seafile-session.c @@ -414,7 +414,7 @@ create_system_default_repo (void *data) "My Library Template", "Template for creating 'My Library' for users", "System", - NULL, NULL); + NULL, -1, NULL); if (!repo_id) { seaf_warning ("Failed to create system default repo.\n"); return data; diff --git a/server/virtual-repo.c b/server/virtual-repo.c index fbe2b1e..745dbf0 100644 --- a/server/virtual-repo.c +++ b/server/virtual-repo.c @@ -84,8 +84,10 @@ do_create_virtual_repo (SeafRepoManager *mgr, if (passwd != NULL && passwd[0] != '\0') { repo->encrypted = TRUE; repo->enc_version = origin_repo->enc_version; - seafile_generate_magic (repo->enc_version, repo_id, passwd, repo->magic); - if (repo->enc_version == 2) + if (repo->enc_version >= 3) + memcpy (repo->salt, origin_repo->salt, 64); + seafile_generate_magic (repo->enc_version, repo_id, passwd, repo->salt, repo->magic); + if (repo->enc_version >= 2) memcpy (repo->random_key, origin_repo->random_key, 96); } @@ -222,7 +224,8 @@ create_virtual_repo_common (SeafRepoManager *mgr, if (seafile_verify_repo_passwd (origin_repo_id, passwd, origin_repo->magic, - origin_repo->enc_version) < 0) { + origin_repo->enc_version, + origin_repo->salt) < 0) { g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL, "Incorrect password"); seaf_repo_unref (origin_repo); diff --git a/tests/test_password/test_password.py b/tests/test_password/test_password.py index c61a5c0..ae8b2d1 100644 --- a/tests/test_password/test_password.py +++ b/tests/test_password/test_password.py @@ -1,17 +1,44 @@ import pytest +from tests.config import USER from seaserv import seafile_api as api -def test_password (encrypted_repo): +@pytest.mark.parametrize('rpc, enc_version', + [('create_repo', 2), ('create_repo', 3), + ('create_enc_repo', 2), ('create_enc_repo', 3)]) +def test_encrypted_repo(rpc, enc_version): + test_repo_name = 'test_enc_repo' + test_repo_desc = 'test_enc_repo' + test_repo_passwd = 'test_enc_repo' + if rpc == 'create_repo': + repo_id = api.create_repo(test_repo_name, test_repo_desc, USER, + test_repo_passwd, enc_version) + assert repo_id + else: + repo_id = 'd17bf8ca-3019-40ee-8fdb-0258c89fb762' + enc_info = api.generate_magic_and_random_key(enc_version, repo_id, test_repo_passwd) + assert enc_info + ret_repo_id = api.create_enc_repo(repo_id, test_repo_name, test_repo_desc, + USER, enc_info.magic, enc_info.random_key, + enc_info.salt, enc_version) + assert ret_repo_id == repo_id - old_passwd = '123' - new_passwd = '456' + repo = api.get_repo(repo_id) + assert repo + assert repo.enc_version == enc_version + assert len(repo.magic) == 64 + assert len(repo.random_key) == 96 + if enc_version == 3: + assert len(repo.salt) == 64 + + new_passwd = 'new password' - assert api.set_passwd(encrypted_repo.id, encrypted_repo.name, old_passwd) == 0 - assert api.get_decrypt_key(encrypted_repo.id, encrypted_repo.name) - api.change_repo_passwd(encrypted_repo.repo_id, old_passwd, new_passwd, encrypted_repo.name) == 0 - assert api.set_passwd(encrypted_repo.id, encrypted_repo.name, new_passwd) == 0 + 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(encrypted_repo.id, encrypted_repo.name) - assert api.unset_passwd(encrypted_repo.id, encrypted_repo.name, new_passwd) == 0 - assert api.is_password_set(encrypted_repo.id, encrypted_repo.name) == 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) diff --git a/tests/test_repo_manipulation/test_repo_manipulation.py b/tests/test_repo_manipulation/test_repo_manipulation.py index 76dd5b6..63a7822 100644 --- a/tests/test_repo_manipulation/test_repo_manipulation.py +++ b/tests/test_repo_manipulation/test_repo_manipulation.py @@ -62,7 +62,7 @@ def test_repo_manipulation(): magic_and_random_key = api.generate_magic_and_random_key (t_enc_version, t_enc_repo_id, t_passwd) t_magic = magic_and_random_key.magic t_random_key = magic_and_random_key.random_key - t_enc_repo_id = api.create_enc_repo (t_enc_repo_id, 'test_encrypted_repo', '', USER, t_magic, t_random_key, t_enc_version) + t_enc_repo_id = api.create_enc_repo (t_enc_repo_id, 'test_encrypted_repo', '', USER, t_magic, t_random_key, None, t_enc_version) assert t_enc_repo_id == '826d1b7b-f110-46f2-8d5e-7b5ac3e11f4d' #test get_repo_list