mirror of
https://github.com/haiwen/seafile-server.git
synced 2025-05-08 16:16:32 +00:00
Support argon2id password hash algo (#637)
* Support argon2id password hash algo * CI install argon2 deps * Go support argonid algo * RPC add pwd_hash_algo and pwd_hash_params * Support password hash algo * Don't set magic when pwd_hash is set * Fix ci error --------- Co-authored-by: 杨赫然 <heran.yang@seafile.com>
This commit is contained in:
parent
9f5fcdfe4d
commit
96996b79e3
ci
common
Makefile.amcommit-mgr.ccommit-mgr.hpassword-hash.cpassword-hash.hrpc-service.cseafile-crypt.cseafile-crypt.h
configure.acfileserver
fuse
include
lib
python
server
@ -12,7 +12,7 @@ sudo systemctl start mysql.service
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y intltool libarchive-dev libcurl4-openssl-dev libevent-dev \
|
||||
libfuse-dev libglib2.0-dev libjansson-dev libmysqlclient-dev libonig-dev \
|
||||
sqlite3 libsqlite3-dev libtool net-tools uuid-dev valac
|
||||
sqlite3 libsqlite3-dev libtool net-tools uuid-dev valac libargon2-dev
|
||||
sudo systemctl start mysql.service
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
@ -7,6 +7,7 @@ proc_headers = \
|
||||
noinst_HEADERS = \
|
||||
diff-simple.h \
|
||||
seafile-crypt.h \
|
||||
password-hash.h \
|
||||
common.h \
|
||||
branch-mgr.h \
|
||||
fs-mgr.h \
|
||||
|
@ -170,6 +170,9 @@ seaf_commit_free (SeafCommit *commit)
|
||||
g_free (commit->client_version);
|
||||
g_free (commit->magic);
|
||||
g_free (commit->random_key);
|
||||
g_free (commit->pwd_hash);
|
||||
g_free (commit->pwd_hash_algo);
|
||||
g_free (commit->pwd_hash_params);
|
||||
g_free (commit);
|
||||
}
|
||||
|
||||
@ -633,12 +636,18 @@ commit_to_json_object (SeafCommit *commit)
|
||||
|
||||
if (commit->encrypted) {
|
||||
json_object_set_int_member (object, "enc_version", commit->enc_version);
|
||||
if (commit->enc_version >= 1)
|
||||
// If pwd_hash is set, the magic field is no longer included in the commit of the newly created repo.
|
||||
if (commit->enc_version >= 1 && !commit->pwd_hash)
|
||||
json_object_set_string_member (object, "magic", commit->magic);
|
||||
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->pwd_hash) {
|
||||
json_object_set_string_member (object, "pwd_hash", commit->pwd_hash);
|
||||
json_object_set_string_member (object, "pwd_hash_algo", commit->pwd_hash_algo);
|
||||
json_object_set_string_member (object, "pwd_hash_params", commit->pwd_hash_params);
|
||||
}
|
||||
}
|
||||
if (commit->no_local_history)
|
||||
json_object_set_int_member (object, "no_local_history", 1);
|
||||
@ -675,6 +684,9 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
const char *magic = NULL;
|
||||
const char *random_key = NULL;
|
||||
const char *salt = NULL;
|
||||
const char *pwd_hash = NULL;
|
||||
const char *pwd_hash_algo = NULL;
|
||||
const char *pwd_hash_params = NULL;
|
||||
int no_local_history = 0;
|
||||
int version = 0;
|
||||
int conflict = 0, new_merge = 0;
|
||||
@ -709,6 +721,9 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
&& json_object_has_member (object, "enc_version")) {
|
||||
enc_version = json_object_get_int_member (object, "enc_version");
|
||||
magic = json_object_get_string_member (object, "magic");
|
||||
pwd_hash = json_object_get_string_member (object, "pwd_hash");
|
||||
pwd_hash_algo = json_object_get_string_member (object, "pwd_hash_algo");
|
||||
pwd_hash_params = json_object_get_string_member (object, "pwd_hash_params");
|
||||
}
|
||||
|
||||
if (enc_version >= 2)
|
||||
@ -739,6 +754,10 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
(second_parent_id && !is_object_id_valid(second_parent_id)))
|
||||
return commit;
|
||||
|
||||
// If pwd_hash is set, the magic field is no longer included in the commit of the newly created repo.
|
||||
if (!magic)
|
||||
magic = pwd_hash;
|
||||
|
||||
switch (enc_version) {
|
||||
case 0:
|
||||
break;
|
||||
@ -794,12 +813,17 @@ commit_from_json_object (const char *commit_id, json_t *object)
|
||||
|
||||
if (commit->encrypted) {
|
||||
commit->enc_version = enc_version;
|
||||
if (enc_version >= 1)
|
||||
if (enc_version >= 1 && !pwd_hash)
|
||||
commit->magic = g_strdup(magic);
|
||||
if (enc_version >= 2)
|
||||
commit->random_key = g_strdup (random_key);
|
||||
if (enc_version >= 3)
|
||||
commit->salt = g_strdup(salt);
|
||||
if (pwd_hash) {
|
||||
commit->pwd_hash = g_strdup (pwd_hash);
|
||||
commit->pwd_hash_algo = g_strdup (pwd_hash_algo);
|
||||
commit->pwd_hash_params = g_strdup (pwd_hash_params);
|
||||
}
|
||||
}
|
||||
if (no_local_history)
|
||||
commit->no_local_history = TRUE;
|
||||
|
@ -36,6 +36,9 @@ struct _SeafCommit {
|
||||
char *magic;
|
||||
char *random_key;
|
||||
char *salt;
|
||||
char *pwd_hash;
|
||||
char *pwd_hash_algo;
|
||||
char *pwd_hash_params;
|
||||
gboolean no_local_history;
|
||||
|
||||
int version;
|
||||
|
167
common/password-hash.c
Normal file
167
common/password-hash.c
Normal file
@ -0,0 +1,167 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <argon2.h>
|
||||
#include "password-hash.h"
|
||||
#include "seafile-crypt.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "log.h"
|
||||
|
||||
// pbkdf2
|
||||
typedef struct Pbkdf2Params {
|
||||
int iteration;
|
||||
} Pbkdf2Params;
|
||||
|
||||
static Pbkdf2Params *
|
||||
parse_pbkdf2_sha256_params (const char *params_str)
|
||||
{
|
||||
Pbkdf2Params *params = NULL;
|
||||
if (!params_str) {
|
||||
params = g_new0 (Pbkdf2Params, 1);
|
||||
params->iteration = 1000;
|
||||
return params;
|
||||
}
|
||||
int iteration;
|
||||
iteration = atoi (params_str);
|
||||
if (iteration <= 0) {
|
||||
iteration = 1000;
|
||||
}
|
||||
|
||||
params = g_new0 (Pbkdf2Params, 1);
|
||||
params->iteration = iteration;
|
||||
return params;
|
||||
}
|
||||
|
||||
static int
|
||||
pbkdf2_sha256_derive_key (const char *data_in, int in_len,
|
||||
const char *salt,
|
||||
Pbkdf2Params *params,
|
||||
unsigned char *key)
|
||||
{
|
||||
int iteration = params->iteration;
|
||||
|
||||
unsigned char salt_bin[32];
|
||||
hex_to_rawdata (salt, salt_bin, 32);
|
||||
|
||||
PKCS5_PBKDF2_HMAC (data_in, in_len,
|
||||
salt_bin, sizeof(salt_bin),
|
||||
iteration,
|
||||
EVP_sha256(),
|
||||
32, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// argon2id
|
||||
typedef struct Argon2idParams{
|
||||
gint64 time_cost;
|
||||
gint64 memory_cost;
|
||||
gint64 parallelism;
|
||||
} Argon2idParams;
|
||||
|
||||
// The arguments to argon2 are separated by commas.
|
||||
// Example arguments format:
|
||||
// 2,102400,8
|
||||
// The parameters are time_cost, memory_cost, parallelism from left to right.
|
||||
static Argon2idParams *
|
||||
parse_argon2id_params (const char *params_str)
|
||||
{
|
||||
char **params;
|
||||
Argon2idParams *argon2_params = g_new0 (Argon2idParams, 1);
|
||||
if (params_str)
|
||||
params = g_strsplit (params_str, ",", 3);
|
||||
if (!params_str || g_strv_length(params) != 3) {
|
||||
if (params_str)
|
||||
g_strfreev (params);
|
||||
argon2_params->time_cost = 2; // 2-pass computation
|
||||
argon2_params->memory_cost = 102400; // 100 mebibytes memory usage
|
||||
argon2_params->parallelism = 8; // number of threads and lanes
|
||||
return argon2_params;
|
||||
}
|
||||
|
||||
char *p = NULL;
|
||||
p = g_strstrip (params[0]);
|
||||
argon2_params->time_cost = atoll (p);
|
||||
if (argon2_params->time_cost <= 0) {
|
||||
argon2_params->time_cost = 2;
|
||||
}
|
||||
|
||||
p = g_strstrip (params[1]);
|
||||
argon2_params->memory_cost = atoll (p);
|
||||
if (argon2_params->memory_cost <= 0) {
|
||||
argon2_params->memory_cost = 102400;
|
||||
}
|
||||
|
||||
p = g_strstrip (params[2]);
|
||||
argon2_params->parallelism = atoll (p);
|
||||
if (argon2_params->parallelism <= 0) {
|
||||
argon2_params->parallelism = 8;
|
||||
}
|
||||
|
||||
g_strfreev (params);
|
||||
return argon2_params;
|
||||
}
|
||||
|
||||
static int
|
||||
argon2id_derive_key (const char *data_in, int in_len,
|
||||
const char *salt,
|
||||
Argon2idParams *params,
|
||||
unsigned char *key)
|
||||
{
|
||||
unsigned char salt_bin[32];
|
||||
hex_to_rawdata (salt, salt_bin, 32);
|
||||
|
||||
argon2id_hash_raw(params->time_cost, params->memory_cost, params->parallelism,
|
||||
data_in, in_len,
|
||||
salt_bin, sizeof(salt_bin),
|
||||
key, 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// parse_pwd_hash_params is used to parse default pwd hash algorithms.
|
||||
void
|
||||
parse_pwd_hash_params (const char *algo, const char *params_str, PwdHashParams *params)
|
||||
{
|
||||
if (g_strcmp0 (algo, PWD_HASH_PDKDF2) == 0) {
|
||||
params->algo = g_strdup (PWD_HASH_PDKDF2);
|
||||
if (params_str)
|
||||
params->params_str = g_strdup (params_str);
|
||||
else
|
||||
params->params_str = g_strdup ("1000");
|
||||
} else if (g_strcmp0 (algo, PWD_HASH_ARGON2ID) == 0) {
|
||||
params->algo = g_strdup (PWD_HASH_ARGON2ID);
|
||||
if (params_str)
|
||||
params->params_str = g_strdup (params_str);
|
||||
else
|
||||
params->params_str = g_strdup ("2,102400,8");
|
||||
} else {
|
||||
params->algo = NULL;
|
||||
}
|
||||
|
||||
seaf_message ("password hash algorithms: %s, params: %s\n ", params->algo, params->params_str);
|
||||
}
|
||||
|
||||
int
|
||||
pwd_hash_derive_key (const char *data_in, int in_len,
|
||||
const char *salt,
|
||||
const char *algo, const char *params_str,
|
||||
unsigned char *key)
|
||||
{
|
||||
int ret = 0;
|
||||
if (g_strcmp0 (algo, PWD_HASH_ARGON2ID) == 0) {
|
||||
Argon2idParams *algo_params = parse_argon2id_params (params_str);
|
||||
ret = argon2id_derive_key (data_in, in_len,
|
||||
salt, algo_params, key);
|
||||
g_free (algo_params);
|
||||
return ret;
|
||||
} else {
|
||||
Pbkdf2Params *algo_params = parse_pbkdf2_sha256_params (params_str);
|
||||
ret = pbkdf2_sha256_derive_key (data_in, in_len,
|
||||
salt, algo_params, key);
|
||||
g_free (algo_params);
|
||||
return ret;
|
||||
}
|
||||
}
|
23
common/password-hash.h
Normal file
23
common/password-hash.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
#ifndef _PASSWORD_HASH_H
|
||||
#define _PASSWORD_HASH_H
|
||||
|
||||
#define PWD_HASH_PDKDF2 "pbkdf2_sha256"
|
||||
#define PWD_HASH_ARGON2ID "argon2id"
|
||||
|
||||
typedef struct _PwdHashParams {
|
||||
char *algo;
|
||||
char *params_str;
|
||||
} PwdHashParams;
|
||||
|
||||
void
|
||||
parse_pwd_hash_params (const char *algo, const char *params_str, PwdHashParams *params);
|
||||
|
||||
int
|
||||
pwd_hash_derive_key (const char *data_in, int in_len,
|
||||
const char *repo_salt,
|
||||
const char *algo, const char *params_str,
|
||||
unsigned char *key);
|
||||
|
||||
#endif
|
@ -55,6 +55,8 @@ convert_repo (SeafRepo *r)
|
||||
g_object_set (repo, "id", r->id, "name", r->name,
|
||||
"desc", r->desc, "encrypted", r->encrypted,
|
||||
"magic", r->magic, "enc_version", r->enc_version,
|
||||
"pwd_hash", r->pwd_hash,
|
||||
"pwd_hash_algo", r->pwd_hash_algo, "pwd_hash_params", r->pwd_hash_params,
|
||||
"head_cmmt_id", r->head ? r->head->commit_id : NULL,
|
||||
"root", r->root_id,
|
||||
"version", r->version, "last_modify", r->last_modify,
|
||||
@ -705,25 +707,47 @@ seafile_generate_magic_and_random_key(int enc_version,
|
||||
|
||||
gchar salt[65] = {0};
|
||||
gchar magic[65] = {0};
|
||||
gchar pwd_hash[65] = {0};
|
||||
gchar random_key[97] = {0};
|
||||
|
||||
if (enc_version >= 3 && seafile_generate_repo_salt (salt) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seafile_generate_magic (enc_version, repo_id, passwd, salt, magic);
|
||||
const char *algo = NULL;
|
||||
const char *params = NULL;
|
||||
algo = seafile_crypt_get_default_pwd_hash_algo ();
|
||||
params = seafile_crypt_get_default_pwd_hash_params ();
|
||||
|
||||
if (algo != NULL) {
|
||||
seafile_generate_pwd_hash (repo_id, passwd, salt, algo, params, pwd_hash);
|
||||
} else {
|
||||
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", enc_version,
|
||||
"magic", magic,
|
||||
"random_key", random_key,
|
||||
NULL);
|
||||
if (algo != NULL) {
|
||||
sinfo = g_object_new (SEAFILE_TYPE_ENCRYPTION_INFO,
|
||||
"repo_id", repo_id,
|
||||
"passwd", passwd,
|
||||
"enc_version", enc_version,
|
||||
"pwd_hash", pwd_hash,
|
||||
"pwd_hash_algo", algo,
|
||||
"pwd_hash_params", params,
|
||||
"random_key", random_key,
|
||||
NULL);
|
||||
} else {
|
||||
sinfo = g_object_new (SEAFILE_TYPE_ENCRYPTION_INFO,
|
||||
"repo_id", repo_id,
|
||||
"passwd", passwd,
|
||||
"enc_version", enc_version,
|
||||
"magic", magic,
|
||||
"random_key", random_key,
|
||||
NULL);
|
||||
}
|
||||
if (enc_version >= 3)
|
||||
g_object_set (sinfo, "salt", salt, NULL);
|
||||
|
||||
@ -1040,10 +1064,18 @@ retry:
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
if (repo->pwd_hash_algo) {
|
||||
if (seafile_pwd_hash_verify_repo_passwd (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;
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
parent = seaf_commit_manager_get_commit (seaf->commit_mgr,
|
||||
@ -1056,9 +1088,15 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
|
||||
char new_magic[65], new_random_key[97];
|
||||
char new_magic[65], new_pwd_hash[65], new_random_key[97];
|
||||
|
||||
seafile_generate_magic (repo->enc_version, repo_id, new_passwd, repo->salt, new_magic);
|
||||
if (repo->pwd_hash_algo) {
|
||||
seafile_generate_pwd_hash (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,
|
||||
new_magic);
|
||||
}
|
||||
if (seafile_update_random_key (old_passwd, repo->random_key,
|
||||
new_passwd, new_random_key,
|
||||
repo->enc_version, repo->salt) < 0) {
|
||||
@ -1066,7 +1104,11 @@ retry:
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (repo->magic, new_magic, 64);
|
||||
if (repo->pwd_hash_algo) {
|
||||
memcpy (repo->pwd_hash, new_pwd_hash, 64);
|
||||
} else {
|
||||
memcpy (repo->magic, new_magic, 64);
|
||||
}
|
||||
memcpy (repo->random_key, new_random_key, 96);
|
||||
|
||||
commit = seaf_commit_new (NULL,
|
||||
@ -3064,6 +3106,9 @@ seafile_create_enc_repo (const char *repo_id,
|
||||
const char *random_key,
|
||||
const char *salt,
|
||||
int enc_version,
|
||||
const char *pwd_hash,
|
||||
const char *pwd_hash_algo,
|
||||
const char *pwd_hash_params,
|
||||
GError **error)
|
||||
{
|
||||
if (!repo_id || !repo_name || !repo_desc || !owner_email) {
|
||||
@ -3076,7 +3121,9 @@ seafile_create_enc_repo (const char *repo_id,
|
||||
ret = seaf_repo_manager_create_enc_repo (seaf->repo_mgr,
|
||||
repo_id, repo_name, repo_desc,
|
||||
owner_email,
|
||||
magic, random_key, salt, enc_version,
|
||||
magic, random_key, salt,
|
||||
enc_version,
|
||||
pwd_hash, pwd_hash_algo, pwd_hash_params,
|
||||
error);
|
||||
return ret;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "seafile-crypt.h"
|
||||
#include "password-hash.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "utils.h"
|
||||
@ -22,6 +23,14 @@
|
||||
/* Should generate random salt for each repo. */
|
||||
static unsigned char salt[8] = { 0xda, 0x90, 0x45, 0xc3, 0x06, 0xc7, 0xcc, 0x26 };
|
||||
|
||||
static PwdHashParams default_params;
|
||||
|
||||
void
|
||||
seafile_crypt_init (const char *algo, const char *params)
|
||||
{
|
||||
parse_pwd_hash_params (algo, params, &default_params);
|
||||
}
|
||||
|
||||
SeafileCrypt *
|
||||
seafile_crypt_new (int version, unsigned char *key, unsigned char *iv)
|
||||
{
|
||||
@ -35,6 +44,18 @@ seafile_crypt_new (int version, unsigned char *key, unsigned char *iv)
|
||||
return crypt;
|
||||
}
|
||||
|
||||
const char *
|
||||
seafile_crypt_get_default_pwd_hash_algo ()
|
||||
{
|
||||
return default_params.algo;
|
||||
}
|
||||
|
||||
const char *
|
||||
seafile_crypt_get_default_pwd_hash_params ()
|
||||
{
|
||||
return default_params.params_str;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_derive_key (const char *data_in, int in_len, int version,
|
||||
const char *repo_salt,
|
||||
@ -156,6 +177,29 @@ seafile_generate_magic (int version, const char *repo_id,
|
||||
rawdata_to_hex (key, magic, 32);
|
||||
}
|
||||
|
||||
void
|
||||
seafile_generate_pwd_hash (const char *repo_id,
|
||||
const char *passwd,
|
||||
const char *repo_salt,
|
||||
const char *algo,
|
||||
const char *params_str,
|
||||
char *pwd_hash)
|
||||
{
|
||||
GString *buf = g_string_new (NULL);
|
||||
unsigned char key[32];
|
||||
|
||||
/* Compute a "pwd_hash" 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int
|
||||
seafile_verify_repo_passwd (const char *repo_id,
|
||||
const char *passwd,
|
||||
@ -189,6 +233,31 @@ seafile_verify_repo_passwd (const char *repo_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_pwd_hash_verify_repo_passwd (const char *repo_id,
|
||||
const char *passwd,
|
||||
const char *repo_salt,
|
||||
const char *pwd_hash,
|
||||
const char *algo,
|
||||
const char *params_str)
|
||||
{
|
||||
GString *buf = g_string_new (NULL);
|
||||
unsigned char key[32];
|
||||
char hex[65];
|
||||
|
||||
g_string_append_printf (buf, "%s%s", repo_id, passwd);
|
||||
|
||||
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);
|
||||
|
||||
if (g_strcmp0 (hex, pwd_hash) == 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
seafile_decrypt_repo_enc_key (int enc_version,
|
||||
const char *passwd, const char *random_key,
|
||||
|
@ -27,9 +27,18 @@ struct SeafileCrypt {
|
||||
|
||||
typedef struct SeafileCrypt SeafileCrypt;
|
||||
|
||||
void
|
||||
seafile_crypt_init (const char *algo, const char *params);
|
||||
|
||||
SeafileCrypt *
|
||||
seafile_crypt_new (int version, unsigned char *key, unsigned char *iv);
|
||||
|
||||
const char *
|
||||
seafile_crypt_get_default_pwd_hash_algo ();
|
||||
|
||||
const char *
|
||||
seafile_crypt_get_default_pwd_hash_params ();
|
||||
|
||||
/*
|
||||
Derive key and iv used by AES encryption from @data_in.
|
||||
key and iv is 16 bytes for version 1, and 32 bytes for version 2.
|
||||
@ -77,6 +86,14 @@ seafile_generate_magic (int version, const char *repo_id,
|
||||
const char *repo_salt,
|
||||
char *magic);
|
||||
|
||||
void
|
||||
seafile_generate_pwd_hash (const char *repo_id,
|
||||
const char *passwd,
|
||||
const char *repo_salt,
|
||||
const char *algo,
|
||||
const char *params_str,
|
||||
char *pwd_hash);
|
||||
|
||||
int
|
||||
seafile_verify_repo_passwd (const char *repo_id,
|
||||
const char *passwd,
|
||||
@ -84,6 +101,14 @@ seafile_verify_repo_passwd (const char *repo_id,
|
||||
int version,
|
||||
const char *repo_salt);
|
||||
|
||||
int
|
||||
seafile_pwd_hash_verify_repo_passwd (const char *repo_id,
|
||||
const char *passwd,
|
||||
const char *repo_salt,
|
||||
const char *pwd_hash,
|
||||
const char *algo,
|
||||
const char *params_str);
|
||||
|
||||
int
|
||||
seafile_decrypt_repo_enc_key (int enc_version,
|
||||
const char *passwd, const char *random_key,
|
||||
|
@ -274,6 +274,10 @@ PKG_CHECK_MODULES(JWT, [libjwt])
|
||||
AC_SUBST(JWT_CFLAGS)
|
||||
AC_SUBST(JWT_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(ARGON2, [libargon2])
|
||||
AC_SUBST(ARGON2_CFLAGS)
|
||||
AC_SUBST(ARGON2_LIBS)
|
||||
|
||||
if test x${compile_python} = xyes; then
|
||||
AM_PATH_PYTHON([2.6])
|
||||
if test "$bwin32" = true; then
|
||||
|
@ -36,6 +36,9 @@ type Commit struct {
|
||||
Magic string `json:"magic,omitempty"`
|
||||
RandomKey string `json:"key,omitempty"`
|
||||
Salt string `json:"salt,omitempty"`
|
||||
PwdHash string `json:"pwd_hash,omitempty"`
|
||||
PwdHashAlgo string `json:"pwd_hash_algo,omitempty"`
|
||||
PwdHashParams string `json:"pwd_hash_params,omitempty"`
|
||||
Version int `json:"version,omitempty"`
|
||||
Conflict int `json:"conflict,omitempty"`
|
||||
NewMerge int `json:"new_merge,omitempty"`
|
||||
|
@ -37,12 +37,15 @@ type Repo struct {
|
||||
StoreID string
|
||||
|
||||
// Encrypted repo info
|
||||
IsEncrypted bool
|
||||
EncVersion int
|
||||
Magic string
|
||||
RandomKey string
|
||||
Salt string
|
||||
Version int
|
||||
IsEncrypted bool
|
||||
EncVersion int
|
||||
Magic string
|
||||
RandomKey string
|
||||
Salt string
|
||||
PwdHash string
|
||||
PwdHashAlgo string
|
||||
PwdHashParams string
|
||||
Version int
|
||||
}
|
||||
|
||||
// VRepoInfo contains virtual repo information.
|
||||
@ -132,20 +135,25 @@ func Get(id string) *Repo {
|
||||
if commit.Encrypted == "true" {
|
||||
repo.IsEncrypted = true
|
||||
repo.EncVersion = commit.EncVersion
|
||||
if repo.EncVersion == 1 {
|
||||
if repo.EncVersion == 1 && commit.PwdHash == "" {
|
||||
repo.Magic = commit.Magic
|
||||
} else if repo.EncVersion == 2 {
|
||||
repo.Magic = commit.Magic
|
||||
repo.RandomKey = commit.RandomKey
|
||||
} else if repo.EncVersion == 3 {
|
||||
repo.Magic = commit.Magic
|
||||
repo.RandomKey = commit.RandomKey
|
||||
repo.Salt = commit.Salt
|
||||
} else if repo.EncVersion == 4 {
|
||||
repo.Magic = commit.Magic
|
||||
repo.RandomKey = commit.RandomKey
|
||||
repo.Salt = commit.Salt
|
||||
}
|
||||
if repo.EncVersion >= 2 && commit.PwdHash == "" {
|
||||
repo.Magic = commit.Magic
|
||||
}
|
||||
if commit.PwdHash != "" {
|
||||
repo.PwdHash = commit.PwdHash
|
||||
repo.PwdHashAlgo = commit.PwdHashAlgo
|
||||
repo.PwdHashParams = commit.PwdHashParams
|
||||
}
|
||||
}
|
||||
|
||||
return repo
|
||||
@ -158,20 +166,25 @@ func RepoToCommit(repo *Repo, commit *commitmgr.Commit) {
|
||||
if repo.IsEncrypted {
|
||||
commit.Encrypted = "true"
|
||||
commit.EncVersion = repo.EncVersion
|
||||
if repo.EncVersion == 1 {
|
||||
if repo.EncVersion == 1 && repo.PwdHash == "" {
|
||||
commit.Magic = repo.Magic
|
||||
} else if repo.EncVersion == 2 {
|
||||
commit.Magic = repo.Magic
|
||||
commit.RandomKey = repo.RandomKey
|
||||
} else if repo.EncVersion == 3 {
|
||||
commit.Magic = repo.Magic
|
||||
commit.RandomKey = repo.RandomKey
|
||||
commit.Salt = repo.Salt
|
||||
} else if repo.EncVersion == 4 {
|
||||
commit.Magic = repo.Magic
|
||||
commit.RandomKey = repo.RandomKey
|
||||
commit.Salt = repo.Salt
|
||||
}
|
||||
if repo.EncVersion >= 2 && repo.PwdHash == "" {
|
||||
commit.Magic = repo.Magic
|
||||
}
|
||||
if repo.PwdHash != "" {
|
||||
commit.PwdHash = repo.PwdHash
|
||||
commit.PwdHashAlgo = repo.PwdHashAlgo
|
||||
commit.PwdHashParams = repo.PwdHashParams
|
||||
}
|
||||
} else {
|
||||
commit.Encrypted = "false"
|
||||
}
|
||||
@ -260,6 +273,15 @@ func GetEx(id string) *Repo {
|
||||
repo.Magic = commit.Magic
|
||||
repo.RandomKey = commit.RandomKey
|
||||
repo.Salt = commit.Salt
|
||||
} else if repo.EncVersion == 4 {
|
||||
repo.Magic = commit.Magic
|
||||
repo.RandomKey = commit.RandomKey
|
||||
repo.Salt = commit.Salt
|
||||
}
|
||||
if commit.PwdHash != "" {
|
||||
repo.PwdHash = commit.PwdHash
|
||||
repo.PwdHashAlgo = commit.PwdHashAlgo
|
||||
repo.PwdHashParams = commit.PwdHashParams
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,11 +36,12 @@ seaf_fuse_SOURCES = seaf-fuse.c \
|
||||
../common/obj-store.c \
|
||||
../common/obj-backend-fs.c \
|
||||
../common/obj-backend-riak.c \
|
||||
../common/seafile-crypt.c
|
||||
../common/seafile-crypt.c \
|
||||
../common/password-hash.c
|
||||
|
||||
seaf_fuse_LDADD = @GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ \
|
||||
-lsqlite3 @LIBEVENT_LIBS@ \
|
||||
$(top_builddir)/common/cdc/libcdc.la \
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ @FUSE_LIBS@ @ZLIB_LIBS@ \
|
||||
@LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3
|
||||
@LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3 @ARGON2_LIBS@
|
||||
|
||||
|
@ -923,6 +923,9 @@ seafile_create_enc_repo (const char *repo_id,
|
||||
const char *random_key,
|
||||
const char *salt,
|
||||
int enc_version,
|
||||
const char *pwd_hash,
|
||||
const char *pwd_hash_algo,
|
||||
const char *pwd_hash_params,
|
||||
GError **error);
|
||||
|
||||
char *
|
||||
|
@ -56,6 +56,9 @@ public class Repo : Object {
|
||||
public int enc_version { get; set; }
|
||||
public string random_key { get; set; }
|
||||
public string salt { get; set; }
|
||||
public string pwd_hash { get; set; }
|
||||
public string pwd_hash_algo { get; set; }
|
||||
public string pwd_hash_params { get; set; }
|
||||
|
||||
// Section 3: Client only information
|
||||
// Should be set for all client repo objects
|
||||
@ -202,6 +205,9 @@ public class EncryptionInfo: Object {
|
||||
public string magic { get; set; }
|
||||
public string random_key { get; set; }
|
||||
public string salt { get; set; }
|
||||
public string pwd_hash { get; set; }
|
||||
public string pwd_hash_algo { get; set; }
|
||||
public string pwd_hash_params { get; set; }
|
||||
}
|
||||
|
||||
public class UserQuotaUsage: Object {
|
||||
|
@ -68,6 +68,7 @@ func_table = [
|
||||
[ "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", "string", "string", "string", "string", "string", "string", "int", "string", "string", "string"] ],
|
||||
[ "string", ["string", "int", "string", "string", "string", "string", "string", "string", "string", "string", "string", "string", "int", "string"] ],
|
||||
[ "string", ["string", "int", "string", "int", "int"] ],
|
||||
[ "string", ["string", "int", "string", "string", "string"] ],
|
||||
@ -103,6 +104,7 @@ func_table = [
|
||||
[ "object", ["string", "string", "string"] ],
|
||||
[ "object", ["string", "int", "string"] ],
|
||||
[ "object", ["int", "string", "string"] ],
|
||||
[ "object", ["int", "string", "string", "string", "string"] ],
|
||||
[ "object", ["string", "string", "int", "int"] ],
|
||||
[ "object", ["string", "string", "string", "int"] ],
|
||||
[ "object", ["string", "string", "string", "string", "string", "string", "string", "int", "int"] ],
|
||||
|
@ -11,8 +11,8 @@ class SeafServerThreadedRpcClient(NamedPipeClient):
|
||||
pass
|
||||
create_repo = seafile_create_repo
|
||||
|
||||
@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):
|
||||
@searpc_func("string", ["string", "string", "string", "string", "string", "string", "string", "int", "string", "string", "string"])
|
||||
def seafile_create_enc_repo(repo_id, name, desc, owner_email, magic, random_key, salt, enc_version, pwd_hash, pwd_hash_algo, pwd_hash_params):
|
||||
pass
|
||||
create_enc_repo = seafile_create_enc_repo
|
||||
|
||||
|
@ -89,8 +89,8 @@ class SeafileAPI(object):
|
||||
def create_repo(self, name, desc, username, passwd=None, enc_version=2, storage_id=None):
|
||||
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, salt, enc_version):
|
||||
return seafserv_threaded_rpc.create_enc_repo(repo_id, name, desc, username, magic, random_key, salt, enc_version)
|
||||
def create_enc_repo(self, repo_id, name, desc, username, magic, random_key, salt, enc_version, pwd_hash=None, pwd_hash_algo=None, pwd_hash_params=None):
|
||||
return seafserv_threaded_rpc.create_enc_repo(repo_id, name, desc, username, magic, random_key, salt, enc_version, pwd_hash, pwd_hash_algo, pwd_hash_params)
|
||||
|
||||
def get_repos_by_id_prefix(self, id_prefix, start=-1, limit=-1):
|
||||
"""
|
||||
|
@ -69,6 +69,7 @@ seaf_server_SOURCES = \
|
||||
../common/obj-store.c \
|
||||
../common/obj-backend-fs.c \
|
||||
../common/seafile-crypt.c \
|
||||
../common/password-hash.c \
|
||||
../common/diff-simple.c \
|
||||
../common/mq-mgr.c \
|
||||
../common/user-mgr.c \
|
||||
@ -86,4 +87,4 @@ seaf_server_LDADD = $(top_builddir)/lib/libseafile_common.la \
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \
|
||||
@LIBARCHIVE_LIBS@ @LIB_ICONV@ \
|
||||
@LDAP_LIBS@ @MYSQL_LIBS@ -lsqlite3 \
|
||||
@CURL_LIBS@ @JWT_LIBS@
|
||||
@CURL_LIBS@ @JWT_LIBS@ @ARGON2_LIBS@
|
||||
|
@ -36,6 +36,7 @@ common_sources = \
|
||||
../../common/obj-store.c \
|
||||
../../common/obj-backend-fs.c \
|
||||
../../common/seafile-crypt.c \
|
||||
../../common/password-hash.c \
|
||||
../../common/config-mgr.c
|
||||
|
||||
seafserv_gc_SOURCES = \
|
||||
@ -48,7 +49,7 @@ seafserv_gc_LDADD = $(top_builddir)/common/cdc/libcdc.la \
|
||||
$(top_builddir)/lib/libseafile_common.la \
|
||||
@GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \
|
||||
@MYSQL_LIBS@ -lsqlite3
|
||||
@MYSQL_LIBS@ -lsqlite3 @ARGON2_LIBS@
|
||||
|
||||
seaf_fsck_SOURCES = \
|
||||
seaf-fsck.c \
|
||||
@ -59,4 +60,4 @@ seaf_fsck_LDADD = $(top_builddir)/common/cdc/libcdc.la \
|
||||
$(top_builddir)/lib/libseafile_common.la \
|
||||
@GLIB2_LIBS@ @GOBJECT_LIBS@ @SSL_LIBS@ @LIB_RT@ @LIB_UUID@ -lsqlite3 @LIBEVENT_LIBS@ \
|
||||
@SEARPC_LIBS@ @JANSSON_LIBS@ ${LIB_WS32} @ZLIB_LIBS@ \
|
||||
@MYSQL_LIBS@ -lsqlite3
|
||||
@MYSQL_LIBS@ -lsqlite3 @ARGON2_LIBS@
|
||||
|
@ -125,12 +125,23 @@ seaf_passwd_manager_set_passwd (SeafPasswdManager *mgr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (seafile_verify_repo_passwd (repo->id, passwd,
|
||||
repo->magic, repo->enc_version, repo->salt) < 0) {
|
||||
seaf_repo_unref (repo);
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
return -1;
|
||||
if (repo->pwd_hash_algo) {
|
||||
if (seafile_pwd_hash_verify_repo_passwd (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,
|
||||
"Incorrect password");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (seafile_verify_repo_passwd (repo->id, passwd,
|
||||
repo->magic,
|
||||
repo->enc_version, repo->salt) < 0) {
|
||||
seaf_repo_unref (repo);
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
crypt_key = g_new0 (DecryptKey, 1);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "fs-mgr.h"
|
||||
#include "seafile-error.h"
|
||||
#include "seafile-crypt.h"
|
||||
#include "password-hash.h"
|
||||
|
||||
#include "seaf-db.h"
|
||||
#include "seaf-utils.h"
|
||||
@ -89,6 +90,8 @@ seaf_repo_free (SeafRepo *repo)
|
||||
if (repo->virtual_info)
|
||||
seaf_virtual_repo_info_free (repo->virtual_info);
|
||||
g_free (repo->last_modifier);
|
||||
g_free (repo->pwd_hash_algo);
|
||||
g_free (repo->pwd_hash_params);
|
||||
g_free (repo);
|
||||
}
|
||||
|
||||
@ -137,20 +140,25 @@ seaf_repo_from_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
memcpy (repo->root_id, commit->root_id, 40);
|
||||
if (repo->encrypted) {
|
||||
repo->enc_version = commit->enc_version;
|
||||
if (repo->enc_version == 1)
|
||||
if (repo->enc_version == 1 && !commit->pwd_hash_algo)
|
||||
memcpy (repo->magic, commit->magic, 32);
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
if (repo->enc_version >= 2 && !commit->pwd_hash_algo) {
|
||||
memcpy (repo->magic, commit->magic, 64);
|
||||
}
|
||||
if (commit->pwd_hash_algo) {
|
||||
memcpy (repo->pwd_hash, commit->pwd_hash, 64);
|
||||
repo->pwd_hash_algo = g_strdup (commit->pwd_hash_algo);
|
||||
repo->pwd_hash_params = g_strdup (commit->pwd_hash_params);
|
||||
}
|
||||
}
|
||||
repo->no_local_history = commit->no_local_history;
|
||||
repo->version = commit->version;
|
||||
@ -166,20 +174,25 @@ seaf_repo_to_commit (SeafRepo *repo, SeafCommit *commit)
|
||||
commit->repaired = repo->repaired;
|
||||
if (commit->encrypted) {
|
||||
commit->enc_version = repo->enc_version;
|
||||
if (commit->enc_version == 1)
|
||||
if (commit->enc_version == 1 && !repo->pwd_hash_algo)
|
||||
commit->magic = g_strdup (repo->magic);
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
if (commit->enc_version >= 2 && !repo->pwd_hash_algo) {
|
||||
commit->magic = g_strdup (repo->magic);
|
||||
}
|
||||
if (repo->pwd_hash_algo) {
|
||||
commit->pwd_hash = g_strdup (repo->pwd_hash);
|
||||
commit->pwd_hash_algo = g_strdup (repo->pwd_hash_algo);
|
||||
commit->pwd_hash_params = g_strdup (repo->pwd_hash_params);
|
||||
}
|
||||
}
|
||||
commit->no_local_history = repo->no_local_history;
|
||||
commit->version = repo->version;
|
||||
@ -3728,16 +3741,37 @@ seaf_repo_manager_is_valid_filename (SeafRepoManager *mgr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct _RepoCryptCompat {
|
||||
const char *magic;
|
||||
const char *pwd_hash;
|
||||
const char *pwd_hash_algo;
|
||||
const char *pwd_hash_params;
|
||||
} RepoCryptInfo;
|
||||
|
||||
static
|
||||
RepoCryptInfo *
|
||||
repo_crypt_info_new (const char *magic, const char *pwd_hash,
|
||||
const char *algo, const char *params)
|
||||
{
|
||||
RepoCryptInfo *crypt_info = g_new0 (RepoCryptInfo, 1);
|
||||
crypt_info->magic = magic;
|
||||
crypt_info->pwd_hash = pwd_hash;
|
||||
crypt_info->pwd_hash_algo = algo;
|
||||
crypt_info->pwd_hash_params = params;
|
||||
|
||||
return crypt_info;
|
||||
}
|
||||
|
||||
static int
|
||||
create_repo_common (SeafRepoManager *mgr,
|
||||
const char *repo_id,
|
||||
const char *repo_name,
|
||||
const char *repo_desc,
|
||||
const char *user,
|
||||
const char *magic,
|
||||
const char *random_key,
|
||||
const char *salt,
|
||||
int enc_version,
|
||||
RepoCryptInfo *crypt_info,
|
||||
GError **error)
|
||||
{
|
||||
SeafRepo *repo = NULL;
|
||||
@ -3751,9 +3785,27 @@ create_repo_common (SeafRepoManager *mgr,
|
||||
"Unsupported encryption version");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (crypt_info && crypt_info->pwd_hash_algo) {
|
||||
if (g_strcmp0 (crypt_info->pwd_hash_algo, PWD_HASH_PDKDF2) != 0 &&
|
||||
g_strcmp0 (crypt_info->pwd_hash_algo, PWD_HASH_ARGON2ID) !=0)
|
||||
{
|
||||
seaf_warning ("Unsupported enc algothrims %s.\n", crypt_info->pwd_hash_algo);
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
|
||||
"Unsupported encryption algothrims");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!crypt_info->pwd_hash || strlen(crypt_info->pwd_hash) != 64) {
|
||||
seaf_warning ("Bad pwd_hash.\n");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
|
||||
"Bad pwd_hash");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (enc_version >= 2) {
|
||||
if (!magic || strlen(magic) != 64) {
|
||||
if (!crypt_info->pwd_hash_algo && (!crypt_info->magic || strlen(crypt_info->magic) != 64)) {
|
||||
seaf_warning ("Bad magic.\n");
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS,
|
||||
"Bad magic");
|
||||
@ -3778,15 +3830,24 @@ create_repo_common (SeafRepoManager *mgr,
|
||||
repo = seaf_repo_new (repo_id, repo_name, repo_desc);
|
||||
|
||||
repo->no_local_history = TRUE;
|
||||
|
||||
if (enc_version >= 2) {
|
||||
repo->encrypted = TRUE;
|
||||
repo->enc_version = enc_version;
|
||||
memcpy (repo->magic, magic, 64);
|
||||
if (!crypt_info->pwd_hash_algo)
|
||||
memcpy (repo->magic, crypt_info->magic, 64);
|
||||
memcpy (repo->random_key, random_key, 96);
|
||||
}
|
||||
if (enc_version >= 3)
|
||||
memcpy (repo->salt, salt, 64);
|
||||
|
||||
if (crypt_info && crypt_info->pwd_hash_algo) {
|
||||
// set pwd_hash fields here.
|
||||
memcpy (repo->pwd_hash, crypt_info->pwd_hash, 64);
|
||||
repo->pwd_hash_algo = g_strdup (crypt_info->pwd_hash_algo);
|
||||
repo->pwd_hash_params = g_strdup (crypt_info->pwd_hash_params);
|
||||
}
|
||||
|
||||
repo->version = CURRENT_REPO_VERSION;
|
||||
memcpy (repo->store_id, repo_id, 36);
|
||||
|
||||
@ -3851,7 +3912,9 @@ seaf_repo_manager_create_new_repo (SeafRepoManager *mgr,
|
||||
GError **error)
|
||||
{
|
||||
char *repo_id = NULL;
|
||||
char salt[65], magic[65], random_key[97];
|
||||
char salt[65], magic[65], pwd_hash[65], random_key[97];
|
||||
const char *algo = seafile_crypt_get_default_pwd_hash_algo ();
|
||||
const char *params = seafile_crypt_get_default_pwd_hash_params ();
|
||||
|
||||
repo_id = gen_uuid ();
|
||||
|
||||
@ -3859,19 +3922,26 @@ seaf_repo_manager_create_new_repo (SeafRepoManager *mgr,
|
||||
if (seafile_generate_repo_salt (salt) < 0) {
|
||||
goto bad;
|
||||
}
|
||||
seafile_generate_magic (enc_version, repo_id, passwd, salt, magic);
|
||||
if (algo != NULL) {
|
||||
seafile_generate_pwd_hash (repo_id, passwd, salt, algo, params, pwd_hash);
|
||||
} else {
|
||||
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)
|
||||
if (passwd) {
|
||||
RepoCryptInfo *crypt_info = repo_crypt_info_new (magic, pwd_hash, algo, params);
|
||||
rc = create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email,
|
||||
magic, random_key, salt, enc_version, error);
|
||||
random_key, salt, enc_version, crypt_info, error);
|
||||
g_free (crypt_info);
|
||||
}
|
||||
else
|
||||
rc = create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email,
|
||||
NULL, NULL, NULL, -1, error);
|
||||
NULL, NULL, -1, NULL, error);
|
||||
if (rc < 0)
|
||||
goto bad;
|
||||
|
||||
@ -3900,6 +3970,9 @@ seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr,
|
||||
const char *random_key,
|
||||
const char *salt,
|
||||
int enc_version,
|
||||
const char *pwd_hash,
|
||||
const char *pwd_hash_algo,
|
||||
const char *pwd_hash_params,
|
||||
GError **error)
|
||||
{
|
||||
if (!repo_id || !is_uuid_valid (repo_id)) {
|
||||
@ -3916,9 +3989,13 @@ seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RepoCryptInfo *crypt_info = repo_crypt_info_new (magic, pwd_hash, pwd_hash_algo, pwd_hash_params);
|
||||
if (create_repo_common (mgr, repo_id, repo_name, repo_desc, owner_email,
|
||||
magic, random_key, salt, enc_version, error) < 0)
|
||||
random_key, salt, enc_version, crypt_info, error) < 0) {
|
||||
g_free (crypt_info);
|
||||
return NULL;
|
||||
}
|
||||
g_free (crypt_info);
|
||||
|
||||
if (seaf_repo_manager_set_repo_owner (mgr, repo_id, owner_email) < 0) {
|
||||
seaf_warning ("Failed to set repo owner.\n");
|
||||
|
@ -33,6 +33,9 @@ struct _SeafRepo {
|
||||
gboolean encrypted;
|
||||
int enc_version;
|
||||
gchar magic[65]; /* hash(repo_id + passwd), key stretched. */
|
||||
gchar pwd_hash[65]; /* hash(repo_id + passwd), key stretched. */
|
||||
gchar *pwd_hash_algo;
|
||||
gchar *pwd_hash_params;
|
||||
gchar random_key[97];
|
||||
gchar salt[65];
|
||||
gboolean no_local_history;
|
||||
@ -513,6 +516,9 @@ seaf_repo_manager_create_enc_repo (SeafRepoManager *mgr,
|
||||
const char *random_key,
|
||||
const char *salt,
|
||||
int enc_version,
|
||||
const char *pwd_hash,
|
||||
const char *pwd_hash_algo,
|
||||
const char *pwd_hash_params,
|
||||
GError **error);
|
||||
|
||||
/* Give a repo and a path in this repo, returns a list of commits, where every
|
||||
|
@ -227,7 +227,7 @@ static void start_rpc_service (const char *seafile_dir,
|
||||
searpc_server_register_function ("seafserv-threaded-rpcserver",
|
||||
seafile_create_enc_repo,
|
||||
"seafile_create_enc_repo",
|
||||
searpc_signature_string__string_string_string_string_string_string_string_int());
|
||||
searpc_signature_string__string_string_string_string_string_string_string_int_string_string_string());
|
||||
|
||||
searpc_server_register_function ("seafserv-threaded-rpcserver",
|
||||
seafile_get_commit,
|
||||
|
@ -122,6 +122,8 @@ seafile_session_new(const char *central_config_dir,
|
||||
char *notif_server = NULL;
|
||||
int notif_port = 8083;
|
||||
char *private_key = NULL;
|
||||
char *pwd_hash_algo = NULL;
|
||||
char *pwd_hash_params = NULL;
|
||||
|
||||
abs_ccnet_dir = ccnet_expand_path (ccnet_dir);
|
||||
abs_seafile_dir = ccnet_expand_path (seafile_dir);
|
||||
@ -208,6 +210,17 @@ seafile_session_new(const char *central_config_dir,
|
||||
session->private_key = private_key;
|
||||
}
|
||||
|
||||
pwd_hash_algo = g_key_file_get_string (config,
|
||||
"password_hash", "pwd_hash_algo",
|
||||
NULL);
|
||||
|
||||
pwd_hash_params = g_key_file_get_string (config,
|
||||
"password_hash", "pwd_hash_params",
|
||||
NULL);
|
||||
seafile_crypt_init (pwd_hash_algo, pwd_hash_params);
|
||||
g_free (pwd_hash_algo);
|
||||
g_free (pwd_hash_params);
|
||||
|
||||
if (load_database_config (session) < 0) {
|
||||
seaf_warning ("Failed to load database config.\n");
|
||||
goto onerror;
|
||||
@ -309,6 +322,8 @@ onerror:
|
||||
free (abs_seafile_dir);
|
||||
free (abs_ccnet_dir);
|
||||
g_free (tmp_file_dir);
|
||||
g_free (pwd_hash_algo);
|
||||
g_free (pwd_hash_params);
|
||||
g_free (session);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -85,7 +85,17 @@ do_create_virtual_repo (SeafRepoManager *mgr,
|
||||
repo->enc_version = origin_repo->enc_version;
|
||||
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 (origin_repo->pwd_hash_algo)
|
||||
repo->pwd_hash_algo = g_strdup (origin_repo->pwd_hash_algo);
|
||||
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,
|
||||
repo->pwd_hash_algo, repo->pwd_hash_params, repo->pwd_hash);
|
||||
memcpy (repo->magic, repo->pwd_hash, 32);
|
||||
} else
|
||||
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);
|
||||
}
|
||||
@ -220,15 +230,29 @@ create_virtual_repo_common (SeafRepoManager *mgr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (seafile_verify_repo_passwd (origin_repo_id,
|
||||
passwd,
|
||||
origin_repo->magic,
|
||||
origin_repo->enc_version,
|
||||
origin_repo->salt) < 0) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
seaf_repo_unref (origin_repo);
|
||||
return NULL;
|
||||
if (origin_repo->pwd_hash_algo) {
|
||||
if (seafile_pwd_hash_verify_repo_passwd (origin_repo_id,
|
||||
passwd,
|
||||
origin_repo->salt,
|
||||
origin_repo->pwd_hash,
|
||||
origin_repo->pwd_hash_algo,
|
||||
origin_repo->pwd_hash_params) < 0) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
seaf_repo_unref (origin_repo);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (seafile_verify_repo_passwd (origin_repo_id,
|
||||
passwd,
|
||||
origin_repo->magic,
|
||||
origin_repo->enc_version,
|
||||
origin_repo->salt) < 0) {
|
||||
g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
|
||||
"Incorrect password");
|
||||
seaf_repo_unref (origin_repo);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user