Exemple #1
0
void
seafile_generate_random_key (const char *passwd, char *random_key)
{
    SeafileCrypt *crypt;
    unsigned char secret_key[32], *rand_key;
    int outlen;
    unsigned char key[32], iv[16];

    if (RAND_bytes (secret_key, sizeof(secret_key)) != 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));
    }

    seafile_derive_key (passwd, strlen(passwd), 2, key, iv);

    crypt = seafile_crypt_new (2, key, iv);

    seafile_encrypt ((char **)&rand_key, &outlen,
                     (char *)secret_key, sizeof(secret_key), crypt);

    rawdata_to_hex (rand_key, random_key, 48);

    g_free (crypt);
    g_free (rand_key);
}
static int
decrypt_token (CcnetProcessor *processor)
{
    USE_PRIV;
    int hex_len, encrypted_len, token_len; 
    char *encrypted_token = NULL;
    SeafileCrypt *crypt = NULL;
    unsigned char key[16], iv[16];
    char *token = NULL;
    int ret = 0;

    /* raw data is half the length of hexidecimal */
    hex_len = strlen(priv->token);
    if (hex_len % 2 != 0) {
        seaf_warning ("[check tx slave v3] invalid length of encrypted token\n"); 
        ret = -1;
        goto out;
    }

    encrypted_len = hex_len / 2;
    encrypted_token = g_malloc (encrypted_len);
    hex_to_rawdata (priv->token,
                    (unsigned char *)encrypted_token,
                    encrypted_len);

    EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */
                    EVP_sha1(),        /* message digest */
                    NULL,              /* slat */
                    (unsigned char*)priv->session_key,
                    strlen(priv->session_key),
                    1,   /* iteration times */
                    key, /* the derived key */
                    iv); /* IV, initial vector */

    crypt = seafile_crypt_new (1, key, iv);
    
    if (seafile_decrypt (&token, &token_len, encrypted_token,
                         encrypted_len, crypt) < 0) {
        seaf_warning ("[check tx slave v3] failed to decrypt token\n");
        ret = -1;
        goto out;
    }

    g_free (priv->token);
    /* we can use the decrypted data directly, since the trailing null byte is
     * also included when encrypting in the client */
    priv->token = token;

out:
    g_free (crypt);
    g_free (encrypted_token);
    
    return ret;
}
Exemple #3
0
static int
real_merge (SeafRepo *repo, SeafCommit *head, CloneTask *task)
{
    struct merge_options opts;
    char index_path[SEAF_PATH_MAX];
    struct index_state istate;
    char *root_id = NULL;
    int clean;

    memset (&istate, 0, sizeof(istate));
    snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
    if (read_index_from (&istate, index_path) < 0) {
        seaf_warning ("Failed to load index.\n");
        return -1;
    }

    init_merge_options (&opts);
    opts.index = &istate;
    opts.worktree = task->worktree;
    opts.ancestor = "common ancestor";
    opts.branch1 = seaf->session->base.user_name;
    opts.branch2 = head->creator_name;
    opts.remote_head = head->commit_id;
    /* Don't need to check locked files on windows. */
    opts.force_merge = TRUE;
    if (repo->encrypted) {
        opts.crypt = seafile_crypt_new (repo->enc_version, 
                                        repo->enc_key, 
                                        repo->enc_iv);
    }

    /* Merge the downloaded branch with the current worktree contents.
     * EMPTY_SHA1 represents an empty common ancestor tree.
     */
    merge_recursive (&opts,
                     task->root_id, head->root_id, EMPTY_SHA1,
                     &clean, &root_id);
    g_free (root_id);

    if (update_index (&istate, index_path) < 0) {
        seaf_warning ("Failed to update index.\n");
        return -1;
    }

    /* We only update the worktree and index, but don't commit.
     * The next auto-commit cycle will check and do that for us.
     */

    discard_index (&istate);
    g_free (opts.crypt);
    clear_merge_options (&opts);

    return 0;
}
Exemple #4
0
int
seafile_update_random_key (const char *old_passwd, const char *old_random_key,
                           const char *new_passwd, char *new_random_key)
{
    unsigned char key[32], iv[16];
    unsigned char random_key_raw[48], *secret_key, *new_random_key_raw;
    int secret_key_len, random_key_len;
    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);

    hex_to_rawdata (old_random_key, random_key_raw, 48);

    crypt = seafile_crypt_new (2, key, iv);
    if (seafile_decrypt ((char **)&secret_key, &secret_key_len,
                         (char *)random_key_raw, 48,
                         crypt) < 0) {
        seaf_warning ("Failed to decrypt random key.\n");
        g_free (crypt);
        return -1;
    }
    g_free (crypt);

    /* Second, use new_passwd to encrypt secret key. */
    seafile_derive_key (new_passwd, strlen(new_passwd), 2, key, iv);

    crypt = seafile_crypt_new (2, key, iv);

    seafile_encrypt ((char **)&new_random_key_raw, &random_key_len,
                     (char *)secret_key, secret_key_len, crypt);

    rawdata_to_hex (new_random_key_raw, new_random_key, 48);

    g_free (secret_key);
    g_free (new_random_key_raw);
    g_free (crypt);

    return 0;
}
Exemple #5
0
/* token -> AES encrypt with session key -> rawdata_to_hex -> output  */
static char *
encrypt_token (CcnetProcessor *processor, const char *token)
{
    CcnetPeer *peer = NULL;
    char *enc_out = NULL;
    SeafileCrypt *crypt = NULL;
    unsigned char key[16], iv[16];
    int len;
    char *output = NULL;

    if (!token)
        goto out;

    peer = ccnet_get_peer(seaf->ccnetrpc_client, processor->peer_id);
    if (!peer || !peer->session_key) {
        seaf_warning ("[check tx v3] peer or peer session key not exist\n");
        goto out;
    }

    EVP_BytesToKey (EVP_aes_128_cbc(), /* cipher mode */
                    EVP_sha1(),        /* message digest */
                    NULL,              /* slat */
                    (unsigned char*)peer->session_key,
                    strlen(peer->session_key),
                    1,   /* iteration times */
                    key, /* the derived key */
                    iv); /* IV, initial vector */

    crypt = seafile_crypt_new (CURRENT_ENC_VERSION, key, iv);
    
    /* encrypt the token with session key, including the trailing null byte */
    if (seafile_encrypt (&enc_out, &len, token, strlen(token) + 1, crypt) < 0) {
        seaf_warning ("[check tx v3] failed to encrypt token\n");
        goto out;
    }

    output = g_malloc (len * 2 + 1);
    rawdata_to_hex ((unsigned char *)enc_out, output, len);
    output[len * 2] = '\0';

    
out:
    g_free (crypt);
    g_free (enc_out);
    if (peer)
        g_object_unref(peer);

    return output;
}
Exemple #6
0
int
seafile_decrypt_repo_enc_key (int enc_version,
                              const char *passwd, const char *random_key,
                              unsigned char *key_out, unsigned char *iv_out)
{
    unsigned char key[32], iv[16];

    seafile_derive_key (passwd, strlen(passwd), enc_version, key, iv);

    if (enc_version == 1) {
        memcpy (key_out, key, 16);
        memcpy (iv_out, iv, 16);
        return 0;
    } else if (enc_version == 2) {
        unsigned char enc_random_key[48], *dec_random_key;
        int outlen;
        SeafileCrypt *crypt;

        if (random_key == NULL || random_key[0] == 0) {
            seaf_warning ("Empty random key.\n");
            return -1;
        }

        hex_to_rawdata (random_key, enc_random_key, 48);

        crypt = seafile_crypt_new (enc_version, key, iv);
        if (seafile_decrypt ((char **)&dec_random_key, &outlen,
                             (char *)enc_random_key, 48,
                             crypt) < 0) {
            seaf_warning ("Failed to decrypt random key.\n");
            g_free (crypt);
            return -1;
        }
        g_free (crypt);

        seafile_derive_key ((char *)dec_random_key, 32, enc_version,
                                  key, iv);
        memcpy (key_out, key, 32);
        memcpy (iv_out, iv, 16);

        g_free (dec_random_key);
        return 0;
    }

    return -1;
}
Exemple #7
0
/* token -> AES encrypt with session key -> rawdata_to_hex -> output  */
static char *
encrypt_token (CcnetProcessor *processor, const char *token)
{
    CcnetPeer *peer = NULL;
    char *enc_out = NULL;
    SeafileCrypt *crypt = NULL;
    unsigned char key[16], iv[16];
    int len;
    char *output = NULL;

    if (!token)
        goto out;

    peer = ccnet_get_peer(seaf->ccnetrpc_client, processor->peer_id);
    if (!peer || !peer->session_key) {
        seaf_warning ("[check tx v2] peer or peer session key not exist\n");
        goto out;
    }

    seafile_generate_enc_key (peer->session_key,
                              strlen(peer->session_key),
                              CURRENT_ENC_VERSION, key, iv);

    crypt = seafile_crypt_new (CURRENT_ENC_VERSION, key, iv);

    /* encrypt the token with session key, including the trailing null byte */
    if (seafile_encrypt (&enc_out, &len, token, strlen(token) + 1, crypt) < 0) {
        seaf_warning ("[check tx v2] failed to encrypt token\n");
        goto out;
    }

    output = g_malloc (len * 2 + 1);
    rawdata_to_hex ((unsigned char *)enc_out, output, len);
    output[len * 2] = '\0';


out:
    g_free (crypt);
    g_free (enc_out);
    if (peer)
        g_object_unref(peer);

    return output;
}
Exemple #8
0
static int
fast_forward_checkout (SeafRepo *repo, SeafCommit *head, CloneTask *task)
{
    SeafRepoManager *mgr = repo->manager;
    char index_path[SEAF_PATH_MAX];
    struct tree_desc trees[2];
    struct unpack_trees_options topts;
    struct index_state istate;
    int ret = 0;

    if (strcmp (head->root_id, task->root_id) == 0)
        return 0;

    memset (&istate, 0, sizeof(istate));
    snprintf (index_path, SEAF_PATH_MAX, "%s/%s", mgr->index_dir, repo->id);
    if (read_index_from (&istate, index_path) < 0) {
        seaf_warning ("Failed to load index.\n");
        return -1;
    }
    repo->index_corrupted = FALSE;

    fill_tree_descriptor (&trees[0], task->root_id);
    fill_tree_descriptor (&trees[1], head->root_id);

    memset(&topts, 0, sizeof(topts));
    topts.base = task->worktree;
    topts.head_idx = -1;
    topts.src_index = &istate;
    topts.update = 1;
    topts.merge = 1;
    topts.fn = twoway_merge;
    if (repo->encrypted) {
        topts.crypt = seafile_crypt_new (repo->enc_version, 
                                         repo->enc_key, 
                                         repo->enc_iv);
    }

    if (unpack_trees (2, trees, &topts) < 0) {
        seaf_warning ("Failed to merge commit %s with work tree.\n", head->commit_id);
        ret = -1;
        goto out;
    }

    if (update_worktree (&topts, FALSE,
                         head->commit_id,
                         head->creator_name,
                         NULL) < 0) {
        seaf_warning ("Failed to update worktree.\n");
        ret = -1;
        goto out;
    }

    discard_index (&istate);
    istate = topts.result;

    if (update_index (&istate, index_path) < 0) {
        seaf_warning ("Failed to update index.\n");
    }

out:
    tree_desc_free (&trees[0]);
    tree_desc_free (&trees[1]);

    g_free (topts.crypt);

    discard_index (&istate);

    return ret;
}
static int
decrypt_token (CcnetProcessor *processor)
{
    USE_PRIV;
    int hex_len, encrypted_len, token_len; 
    char *encrypted_token = NULL;
    SeafileCrypt *crypt = NULL;
    unsigned char key[16], iv[16];
    char *token = NULL;
    int ret = 0;

    /* raw data is half the length of hexidecimal */
    hex_len = strlen(priv->token);
    if (hex_len % 2 != 0) {
        seaf_warning ("[check tx slave v2] invalid length of encrypted token\n"); 
        ret = -1;
        goto out;
    }

    token = seaf_repo_manager_get_decrypted_token (seaf->repo_mgr,
                                                   priv->token,
                                                   priv->session_key);
    if (token)
        goto found;
    
    encrypted_len = hex_len / 2;
    encrypted_token = g_malloc (encrypted_len);
    hex_to_rawdata (priv->token,
                    (unsigned char *)encrypted_token,
                    encrypted_len);

    seafile_generate_enc_key (priv->session_key,
                              strlen(priv->session_key),
                              CURRENT_ENC_VERSION, key, iv);
    crypt = seafile_crypt_new (CURRENT_ENC_VERSION, key, iv);
    
    if (seafile_decrypt (&token, &token_len, encrypted_token,
                         encrypted_len, crypt) < 0) {
        seaf_warning ("[check tx slave v2] failed to decrypt token\n");
        ret = -1;
        goto out;
    }

    /* Add to cache. */
    seaf_repo_manager_add_decrypted_token (seaf->repo_mgr,
                                           priv->token,
                                           priv->session_key,
                                           token);

found:
    g_free (priv->token);
    /* we can use the decrypted data directly, since the trailing null byte is
     * also included when encrypting in the client */
    priv->token = token;

out:
    g_free (crypt);
    g_free (encrypted_token);
    
    return ret;
}
Exemple #10
0
static int
do_real_merge (SeafRepo *repo, 
               SeafBranch *head_branch,
               SeafCommit *head,
               SeafBranch *remote_branch, 
               SeafCommit *remote,
               SeafCommit *common,
               gboolean recover_merge,
               char **error)
{
    struct merge_options opts;
    char index_path[SEAF_PATH_MAX];
    struct index_state istate;
    char *root_id = NULL;
    SeafCommit *merged;
    int ret = 0, clean;

    memset (&istate, 0, sizeof(istate));
    snprintf (index_path, SEAF_PATH_MAX, "%s/%s", repo->manager->index_dir, repo->id);
    if (read_index_from (&istate, index_path) < 0) {
        g_warning ("Failed to load index.\n");
        *error = g_strdup ("Internal error.\n");
        return -1;
    }

    init_merge_options (&opts);
    opts.index = &istate;
    opts.worktree = repo->worktree;
    opts.ancestor = "common ancestor";
    opts.branch1 = seaf->session->base.user_name;
    opts.branch2 = remote->creator_name;
    opts.remote_head = remote->commit_id;
    opts.recover_merge = recover_merge;
    if (repo->encrypted) {
        opts.crypt = seafile_crypt_new (repo->enc_version, 
                                        repo->enc_key, 
                                        repo->enc_iv);
    }

    ret = merge_recursive (&opts,
                           head->root_id, remote->root_id, common->root_id,
                           &clean, &root_id);
    if (ret < 0)
        goto out;

    if (update_index (&istate, index_path) < 0) {
        *error = g_strdup ("Internal error.\n");
        ret = -1;
        goto out;
    }

    if (clean) {
        merged = seaf_commit_new (NULL,
                                  repo->id,
                                  root_id,
                                  repo->email ? repo->email
                                  : seaf->session->base.user_name,
                                  seaf->session->base.id,
                                  "Auto merge by seafile system",
                                  0);

        merged->parent_id = g_strdup(head->commit_id);
        merged->second_parent_id = g_strdup(remote->commit_id);

        seaf_repo_to_commit (repo, merged);

        if (seaf_commit_manager_add_commit (seaf->commit_mgr, merged) < 0) {
            seaf_commit_unref (merged);
            *error = g_strdup ("Internal error.\n");
            ret = -1;
            goto out;
        }
        seaf_branch_set_commit (head_branch, merged->commit_id);
        seaf_branch_manager_update_branch (seaf->branch_mgr, head_branch);
        g_debug ("Auto merged.\n");

        seaf_commit_unref (merged);
    } else {
        ret = -1;
        g_debug ("Auto merge failed.\n");
    }

out:
    if (root_id)
        g_free (root_id);
    g_free (opts.crypt);
    clear_merge_options (&opts);
    discard_index (&istate);
    return ret;
}