Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support enc repo v5 #2687

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions common/commit-mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions common/commit-mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct _SeafCommit {
char *magic;
char *random_key;
char *salt;
int key_iter;
gboolean no_local_history;

int version;
Expand Down
28 changes: 19 additions & 9 deletions common/seafile-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand All @@ -181,14 +186,15 @@ 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
* data.
*/
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);
Expand All @@ -199,21 +205,22 @@ 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;
}

/* 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);

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand All @@ -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,
Expand Down
5 changes: 4 additions & 1 deletion common/seafile-crypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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
Expand Down
28 changes: 21 additions & 7 deletions daemon/clone-mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions daemon/clone-mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 14 additions & 4 deletions daemon/repo-mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions daemon/repo-mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading