mirror of
https://github.com/haiwen/seafile.git
synced 2025-01-07 03:17:13 +08:00
Support enc repo v5
This commit is contained in:
parent
90a2bc6e30
commit
ccfa22ee2c
@ -636,6 +636,8 @@ commit_to_json_object (SeafCommit *commit)
|
||||
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->enc_version >= 5)
|
||||
json_object_set_int_member (object, "key_iter", commit->key_iter);
|
||||
}
|
||||
if (commit->no_local_history)
|
||||
json_object_set_int_member (object, "no_local_history", 1);
|
||||
@ -672,6 +674,7 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
const char *magic = NULL;
|
||||
const char *random_key = NULL;
|
||||
const char *salt = NULL;
|
||||
int key_iter;
|
||||
int no_local_history = 0;
|
||||
int version = 0;
|
||||
int conflict = 0, new_merge = 0;
|
||||
@ -712,6 +715,8 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
random_key = json_object_get_string_member (object, "key");
|
||||
if (enc_version >= 3)
|
||||
salt = json_object_get_string_member (object, "salt");
|
||||
if (enc_version >= 5)
|
||||
key_iter = json_object_get_int_member (object, "key_iter");
|
||||
|
||||
if (json_object_has_member (object, "no_local_history"))
|
||||
no_local_history = json_object_get_int_member (object, "no_local_history");
|
||||
@ -765,6 +770,16 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
if (!salt || strlen(salt) != 64)
|
||||
return NULL;
|
||||
break;
|
||||
case 5:
|
||||
if (!magic || strlen(magic) != 64)
|
||||
return NULL;
|
||||
if (!random_key || strlen(random_key) != 96)
|
||||
return NULL;
|
||||
if (!salt || strlen(salt) != 64)
|
||||
return NULL;
|
||||
if (key_iter <= 0)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
seaf_warning ("Unknown encryption version %d.\n", enc_version);
|
||||
return NULL;
|
||||
@ -797,6 +812,8 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
commit->random_key = g_strdup (random_key);
|
||||
if (enc_version >= 3)
|
||||
commit->salt = g_strdup(salt);
|
||||
if (enc_version >= 5)
|
||||
commit->key_iter = key_iter;
|
||||
}
|
||||
if (no_local_history)
|
||||
commit->no_local_history = TRUE;
|
||||
|
@ -36,6 +36,7 @@ struct _SeafCommit {
|
||||
char *magic;
|
||||
char *random_key;
|
||||
char *salt;
|
||||
int key_iter;
|
||||
gboolean no_local_history;
|
||||
|
||||
int version;
|
||||
|
@ -49,6 +49,7 @@ 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,
|
||||
int iter,
|
||||
unsigned char *key, unsigned char *iv)
|
||||
{
|
||||
#ifdef USE_GPL_CRYPTO
|
||||
@ -64,13 +65,16 @@ seafile_derive_key (const char *data_in, int in_len, int version,
|
||||
return 0;
|
||||
#else
|
||||
if (version >= 3) {
|
||||
int key_iter = KEYGEN_ITERATION2;
|
||||
if (version >= 5)
|
||||
key_iter = iter;
|
||||
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,
|
||||
key_iter,
|
||||
EVP_sha256(),
|
||||
32, key);
|
||||
PKCS5_PBKDF2_HMAC ((char *)key, 32,
|
||||
@ -145,6 +149,7 @@ seafile_generate_random_key (const char *passwd,
|
||||
unsigned char secret_key[32], *rand_key;
|
||||
int outlen;
|
||||
unsigned char key[32], iv[16];
|
||||
int iter = KEYGEN_ITERATION2;
|
||||
|
||||
#ifdef USE_GPL_CRYPTO
|
||||
if (gnutls_rnd (GNUTLS_RND_RANDOM, secret_key, sizeof(secret_key)) < 0) {
|
||||
@ -158,7 +163,7 @@ seafile_generate_random_key (const char *passwd,
|
||||
}
|
||||
#endif
|
||||
|
||||
seafile_derive_key (passwd, strlen(passwd), version, repo_salt, key, iv);
|
||||
seafile_derive_key (passwd, strlen(passwd), version, repo_salt, iter, key, iv);
|
||||
|
||||
crypt = seafile_crypt_new (version, key, iv);
|
||||
|
||||
@ -181,6 +186,7 @@ seafile_generate_magic (int version, const char *repo_id,
|
||||
{
|
||||
GString *buf = g_string_new (NULL);
|
||||
unsigned char key[32], iv[16];
|
||||
int iter = KEYGEN_ITERATION2;
|
||||
|
||||
/* Compute a "magic" string from repo_id and passwd.
|
||||
* This is used to verify the password given by user before decrypting
|
||||
@ -188,7 +194,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, repo_salt, key, iv);
|
||||
seafile_derive_key (buf->str, buf->len, version, repo_salt, iter, key, iv);
|
||||
|
||||
g_string_free (buf, TRUE);
|
||||
rawdata_to_hex (key, magic, 32);
|
||||
@ -199,13 +205,14 @@ seafile_verify_repo_passwd (const char *repo_id,
|
||||
const char *passwd,
|
||||
const char *magic,
|
||||
int version,
|
||||
const char *repo_salt)
|
||||
const char *repo_salt,
|
||||
int iter)
|
||||
{
|
||||
GString *buf = g_string_new (NULL);
|
||||
unsigned char key[32], iv[16];
|
||||
char hex[65];
|
||||
|
||||
if (version != 1 && version != 2 && version != 3 && version != 4) {
|
||||
if (version != 1 && version != 2 && version != 3 && version != 4 && version != 5) {
|
||||
seaf_warning ("Unsupported enc_version %d.\n", version);
|
||||
return -1;
|
||||
}
|
||||
@ -213,7 +220,7 @@ 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, repo_salt, key, iv);
|
||||
seafile_derive_key (buf->str, buf->len, version, repo_salt, iter, key, iv);
|
||||
|
||||
g_string_free (buf, TRUE);
|
||||
|
||||
@ -232,11 +239,12 @@ int
|
||||
seafile_decrypt_repo_enc_key (int enc_version,
|
||||
const char *passwd, const char *random_key,
|
||||
const char *repo_salt,
|
||||
int iter,
|
||||
unsigned char *key_out, unsigned char *iv_out)
|
||||
{
|
||||
unsigned char key[32], iv[16];
|
||||
|
||||
seafile_derive_key (passwd, strlen(passwd), enc_version, repo_salt, key, iv);
|
||||
seafile_derive_key (passwd, strlen(passwd), enc_version, repo_salt, iter, key, iv);
|
||||
|
||||
if (enc_version == 1) {
|
||||
memcpy (key_out, key, 16);
|
||||
@ -266,6 +274,7 @@ seafile_decrypt_repo_enc_key (int enc_version,
|
||||
|
||||
seafile_derive_key ((char *)dec_random_key, 32, enc_version,
|
||||
repo_salt,
|
||||
iter,
|
||||
key, iv);
|
||||
memcpy (key_out, key, 32);
|
||||
memcpy (iv_out, iv, 16);
|
||||
@ -286,10 +295,11 @@ seafile_update_random_key (const char *old_passwd, const char *old_random_key,
|
||||
unsigned char random_key_raw[48], *secret_key, *new_random_key_raw;
|
||||
int secret_key_len, random_key_len;
|
||||
SeafileCrypt *crypt;
|
||||
int iter = KEYGEN_ITERATION2;
|
||||
|
||||
/* First, use old_passwd to decrypt secret key from old_random_key. */
|
||||
seafile_derive_key (old_passwd, strlen(old_passwd), enc_version,
|
||||
repo_salt, key, iv);
|
||||
repo_salt, iter, key, iv);
|
||||
|
||||
hex_to_rawdata (old_random_key, random_key_raw, 48);
|
||||
|
||||
@ -305,7 +315,7 @@ seafile_update_random_key (const char *old_passwd, const char *old_random_key,
|
||||
|
||||
/* Second, use new_passwd to encrypt secret key. */
|
||||
seafile_derive_key (new_passwd, strlen(new_passwd), enc_version,
|
||||
repo_salt, key, iv);
|
||||
repo_salt, iter, key, iv);
|
||||
crypt = seafile_crypt_new (enc_version, key, iv);
|
||||
|
||||
seafile_encrypt ((char **)&new_random_key_raw, &random_key_len,
|
||||
|
@ -43,6 +43,7 @@ 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,
|
||||
int iter,
|
||||
unsigned char *key, unsigned char *iv);
|
||||
|
||||
/* @salt must be an char array of size 65 bytes. */
|
||||
@ -70,12 +71,14 @@ seafile_verify_repo_passwd (const char *repo_id,
|
||||
const char *passwd,
|
||||
const char *magic,
|
||||
int version,
|
||||
const char *repo_salt);
|
||||
const char *repo_salt,
|
||||
int iter);
|
||||
|
||||
int
|
||||
seafile_decrypt_repo_enc_key (int enc_version,
|
||||
const char *passwd, const char *random_key,
|
||||
const char *repo_salt,
|
||||
int iter,
|
||||
unsigned char *key_out, unsigned char *iv_out);
|
||||
|
||||
int
|
||||
|
@ -631,6 +631,7 @@ save_task_to_db (SeafCloneManager *mgr, CloneTask *task)
|
||||
json_object_set_new (object, "is_readonly", json_integer (task->is_readonly));
|
||||
if (task->server_url)
|
||||
json_object_set_new (object, "server_url", json_string(task->server_url));
|
||||
json_object_set_new (object, "key_iter", json_integer (task->key_iter));
|
||||
|
||||
info = json_dumps (object, 0);
|
||||
json_decref (object);
|
||||
@ -1030,6 +1031,8 @@ add_task_common (SeafCloneManager *mgr,
|
||||
task->repo_salt = g_strdup (json_string_value (repo_salt));
|
||||
integer = json_object_get (object, "resync_enc_repo");
|
||||
task->resync_enc_repo = json_integer_value (integer);
|
||||
integer = json_object_get (object, "key_iter");
|
||||
task->key_iter = json_integer_value (integer);
|
||||
json_decref (object);
|
||||
}
|
||||
|
||||
@ -1056,7 +1059,7 @@ add_task_common (SeafCloneManager *mgr,
|
||||
|
||||
static gboolean
|
||||
check_encryption_args (const char *magic, int enc_version, const char *random_key,
|
||||
const char *repo_salt,
|
||||
const char *repo_salt, int key_iter,
|
||||
GError **error)
|
||||
{
|
||||
if (!magic) {
|
||||
@ -1065,7 +1068,7 @@ check_encryption_args (const char *magic, int enc_version, const char *random_ke
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (enc_version != 1 && enc_version != 2 && enc_version != 3 && enc_version != 4) {
|
||||
if (enc_version != 1 && enc_version != 2 && enc_version != 3 && enc_version != 4 && enc_version != 5) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
|
||||
"Unsupported enc version");
|
||||
return FALSE;
|
||||
@ -1082,6 +1085,11 @@ check_encryption_args (const char *magic, int enc_version, const char *random_ke
|
||||
"Repo salt not specified");
|
||||
return FALSE;
|
||||
}
|
||||
if (enc_version >= 5 && key_iter <= 0) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
|
||||
"Repo key iteration times not specified");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -1117,6 +1125,7 @@ seaf_clone_manager_add_task (SeafCloneManager *mgr,
|
||||
char *ret = NULL;
|
||||
gboolean sync_wt_name = FALSE;
|
||||
char *repo_salt = NULL;
|
||||
int key_iter;
|
||||
gboolean resync_enc_repo = FALSE;
|
||||
|
||||
if (!seaf->started) {
|
||||
@ -1147,11 +1156,13 @@ seaf_clone_manager_add_task (SeafCloneManager *mgr,
|
||||
repo_salt = g_strdup (json_string_value (string));
|
||||
json_t *integer = json_object_get (object, "resync_enc_repo");
|
||||
resync_enc_repo = json_integer_value (integer);
|
||||
integer = json_object_get (object, "key_iter");
|
||||
key_iter = json_integer_value (integer);
|
||||
json_decref (object);
|
||||
}
|
||||
|
||||
if (passwd &&
|
||||
!check_encryption_args (magic, enc_version, random_key, repo_salt, error)) {
|
||||
!check_encryption_args (magic, enc_version, random_key, repo_salt, key_iter, error)) {
|
||||
goto out;
|
||||
}
|
||||
/* After a repo was unsynced, the sync task may still be blocked in the
|
||||
@ -1181,7 +1192,7 @@ seaf_clone_manager_add_task (SeafCloneManager *mgr,
|
||||
}
|
||||
|
||||
if (passwd &&
|
||||
seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version, repo_salt) < 0) {
|
||||
seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version, repo_salt, key_iter) < 0) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
goto out;
|
||||
@ -1269,6 +1280,7 @@ seaf_clone_manager_add_download_task (SeafCloneManager *mgr,
|
||||
char *worktree = NULL;
|
||||
char *ret = NULL;
|
||||
char *repo_salt = NULL;
|
||||
int key_iter;
|
||||
|
||||
if (!seaf->started) {
|
||||
seaf_message ("System not started, skip adding clone task.\n");
|
||||
@ -1296,11 +1308,13 @@ seaf_clone_manager_add_download_task (SeafCloneManager *mgr,
|
||||
json_t *string = json_object_get (object, "repo_salt");
|
||||
if (string)
|
||||
repo_salt = g_strdup (json_string_value (string));
|
||||
json_decref (object);
|
||||
json_t *integer = json_object_get (object, "key_iter");
|
||||
key_iter = json_integer_value (integer);
|
||||
json_decref (object);
|
||||
}
|
||||
|
||||
if (passwd &&
|
||||
!check_encryption_args (magic, enc_version, random_key, repo_salt, error)) {
|
||||
!check_encryption_args (magic, enc_version, random_key, repo_salt, key_iter, error)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1331,7 +1345,7 @@ seaf_clone_manager_add_download_task (SeafCloneManager *mgr,
|
||||
}
|
||||
|
||||
if (passwd &&
|
||||
seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version, repo_salt) < 0) {
|
||||
seafile_verify_repo_passwd(repo_id, passwd, magic, enc_version, repo_salt, key_iter) < 0) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
goto out;
|
||||
|
@ -47,6 +47,7 @@ struct _CloneTask {
|
||||
char *repo_salt;
|
||||
char *random_key;
|
||||
gboolean resync_enc_repo;
|
||||
int key_iter;
|
||||
char root_id[41];
|
||||
gboolean is_readonly;
|
||||
/* Set to true when the local folder name is the same as library name.
|
||||
|
@ -1184,11 +1184,15 @@ seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
memcpy (repo->magic, commit->magic, 64);
|
||||
memcpy (repo->random_key, commit->random_key, 96);
|
||||
memcpy (repo->salt, commit->salt, 64);
|
||||
}
|
||||
else if (repo->enc_version == 4) {
|
||||
} else if (repo->enc_version == 4) {
|
||||
memcpy (repo->magic, commit->magic, 64);
|
||||
memcpy (repo->random_key, commit->random_key, 96);
|
||||
memcpy (repo->salt, commit->salt, 64);
|
||||
} else if (repo->enc_version == 5) {
|
||||
memcpy (repo->magic, commit->magic, 64);
|
||||
memcpy (repo->random_key, commit->random_key, 96);
|
||||
memcpy (repo->salt, commit->salt, 64);
|
||||
repo->key_iter = commit->key_iter;
|
||||
}
|
||||
}
|
||||
repo->no_local_history = commit->no_local_history;
|
||||
@ -1213,11 +1217,15 @@ seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
commit->magic = g_strdup (repo->magic);
|
||||
commit->random_key = g_strdup (repo->random_key);
|
||||
commit->salt = g_strdup (repo->salt);
|
||||
}
|
||||
else if (commit->enc_version == 4) {
|
||||
} else if (commit->enc_version == 4) {
|
||||
commit->magic = g_strdup (repo->magic);
|
||||
commit->random_key = g_strdup (repo->random_key);
|
||||
commit->salt = g_strdup (repo->salt);
|
||||
} else if (commit->enc_version == 5) {
|
||||
commit->magic = g_strdup (repo->magic);
|
||||
commit->random_key = g_strdup (repo->random_key);
|
||||
commit->salt = g_strdup (repo->salt);
|
||||
commit->key_iter = repo->key_iter;
|
||||
}
|
||||
}
|
||||
commit->no_local_history = repo->no_local_history;
|
||||
@ -5902,6 +5910,7 @@ seaf_repo_fetch_and_checkout (HttpTxTask *http_task, const char *remote_head_id)
|
||||
passwd,
|
||||
remote_head->random_key,
|
||||
remote_head->salt,
|
||||
remote_head->key_iter,
|
||||
enc_key, enc_iv);
|
||||
crypt = seafile_crypt_new (remote_head->enc_version,
|
||||
enc_key, enc_iv);
|
||||
@ -7343,6 +7352,7 @@ seaf_repo_manager_set_repo_passwd (SeafRepoManager *manager,
|
||||
|
||||
if (seafile_decrypt_repo_enc_key (repo->enc_version, passwd, repo->random_key,
|
||||
repo->salt,
|
||||
repo->key_iter,
|
||||
repo->enc_key, repo->enc_iv) < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -45,6 +45,7 @@ struct _SeafRepo {
|
||||
gchar salt[65];
|
||||
gchar magic[65]; /* hash(repo_id + passwd), key stretched. */
|
||||
gchar random_key[97]; /* key length is 48 after encryption */
|
||||
int key_iter;
|
||||
gboolean no_local_history;
|
||||
gint64 last_modify;
|
||||
|
||||
|
@ -1397,6 +1397,7 @@ resync_repo (SeafRepo *repo)
|
||||
rawdata_to_hex (repo->enc_iv, iv, 16);
|
||||
}
|
||||
json_object_set_int_member (obj, "resync_enc_repo", TRUE);
|
||||
json_object_set_int_member (obj, "key_iter", repo->key_iter);
|
||||
}
|
||||
|
||||
more_info = json_dumps (obj, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user