static gboolean validate_passwd_pbkdf2_sha256 (const char *passwd, const char *db_passwd) { char **tokens; char *salt_str, *hash; int iter; guint8 sha[SHA256_DIGEST_LENGTH]; guint8 salt[SHA256_DIGEST_LENGTH]; char hashed_passwd[SHA256_DIGEST_LENGTH*2+1]; tokens = g_strsplit (db_passwd, "$", -1); if (!tokens || g_strv_length (tokens) != 4) { ccnet_warning ("Invalide db passwd format %s.\n", db_passwd); return FALSE; } iter = atoi (tokens[1]); salt_str = tokens[2]; hash = tokens[3]; hex_to_rawdata (salt_str, salt, SHA256_DIGEST_LENGTH); PKCS5_PBKDF2_HMAC (passwd, strlen(passwd), salt, sizeof(salt), iter, EVP_sha256(), sizeof(sha), sha); rawdata_to_hex (sha, hashed_passwd, SHA256_DIGEST_LENGTH); gboolean ret = (strcmp (hash, hashed_passwd) == 0); g_strfreev (tokens); 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 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; }
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; }
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; }
int commit_trees_cb (struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen) { SeafDir *seaf_dir; GList *dirents = NULL; int i; for (i = 0; i < entries; i++) { SeafDirent *seaf_dent; char *dirname; struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, entlen; const unsigned char *sha1; char hex[41]; unsigned mode; if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = cache_tree_find_subtree(it, path + baselen, entlen, 0); g_assert (sub != NULL); /* Skip cache entries in the sub level. */ i += sub->cache_tree->entry_count - 1; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; dirname = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); seaf_dent = seaf_dirent_new (hex, mode, dirname); g_free(dirname); dirents = g_list_prepend (dirents, seaf_dent); } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; dirname = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); seaf_dent = seaf_dirent_new (hex, mode, dirname); g_free(dirname); dirents = g_list_prepend (dirents, seaf_dent); } #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } /* Sort dirents in descending order. */ dirents = g_list_sort (dirents, compare_dirents); seaf_dir = seaf_dir_new (NULL, dirents, 0); hex_to_rawdata (seaf_dir->dir_id, it->sha1, 20); seaf_dir_save (seaf->fs_mgr, seaf_dir); #if DEBUG for (p = dirents; p; p = p->next) { SeafDirent *tmp = (SeafDirent *)p->data; fprintf(stderr, "dump dirent name %s id %s\n", tmp->name, tmp->id); } #endif seaf_dir_free (seaf_dir); return 0; }
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; }
int commit_trees_cb (const char *repo_id, int version, const char *worktree, struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen) { SeafDir *seaf_dir; GList *dirents = NULL, *ptr; int i; for (i = 0; i < entries; i++) { SeafDirent *seaf_dent; char *name; struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, entlen; const unsigned char *sha1; char hex[41]; unsigned mode; guint64 mtime; gint64 size; char *modifier; if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = cache_tree_find_subtree(it, path + baselen, entlen, 0); g_return_val_if_fail (sub != NULL, -1); /* Skip cache entries in the sub level. */ i += sub->cache_tree->entry_count - 1; sha1 = sub->cache_tree->sha1; mtime = sub->cache_tree->mtime; mode = S_IFDIR; name = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); seaf_dent = seaf_dirent_new (dir_version_from_repo_version(version), hex, mode, name, mtime, NULL, -1); g_free(name); dirents = g_list_prepend (dirents, seaf_dent); } else { sha1 = ce->sha1; mode = ce->ce_mode; mtime = ce->ce_mtime.sec; size = ce->ce_size; modifier = ce->modifier; entlen = pathlen - baselen; name = g_strndup(path + baselen, entlen); rawdata_to_hex (sha1, hex, 20); if (version > 0) { seaf_dent = seaf_dirent_new (dir_version_from_repo_version(version), hex, mode, name, mtime, modifier, size); } else { seaf_dent = seaf_dirent_new (0, hex, mode, name, 0, NULL, -1); } g_free(name); dirents = g_list_prepend (dirents, seaf_dent); } #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } /* Sort dirents in descending order. */ dirents = g_list_sort (dirents, compare_dirents); seaf_dir = seaf_dir_new (NULL, dirents, dir_version_from_repo_version(version)); hex_to_rawdata (seaf_dir->dir_id, it->sha1, 20); /* Dir's mtime is the latest of all dir entires. */ guint64 dir_mtime = 0; SeafDirent *dent; for (ptr = dirents; ptr; ptr = ptr->next) { dent = ptr->data; if (dent->mtime > dir_mtime) dir_mtime = dent->mtime; } it->mtime = dir_mtime; if (!seaf_fs_manager_object_exists (seaf->fs_mgr, repo_id, version, seaf_dir->dir_id)) seaf_dir_save (seaf->fs_mgr, repo_id, version, seaf_dir); #if DEBUG for (p = dirents; p; p = p->next) { SeafDirent *tmp = (SeafDirent *)p->data; fprintf(stderr, "dump dirent name %s id %s\n", tmp->name, tmp->id); } #endif seaf_dir_free (seaf_dir); return 0; }
int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info) { struct name_entry *entries = g_new0 (struct name_entry, n); GList **ptrs = g_new0 (GList *, n); int i; SeafDirent *dent; char *first_name; gboolean done; unsigned long mask = 0, dirmask = 0; int error = 0, ret; for (i = 0; i < n; ++i) { if (t[i].tree) ptrs[i] = t[i].tree->entries; else ptrs[i] = NULL; } while (1) { first_name = NULL; mask = dirmask = 0; memset (entries, 0, sizeof(entries[0])*n); done = TRUE; /* Find the "largest" name, assuming dirents are sorted. */ for (i = 0; i < n; ++i) { if (ptrs[i] != NULL) { done = FALSE; dent = ptrs[i]->data; if (!first_name) first_name = dent->name; else if (strcmp(dent->name, first_name) > 0) first_name = dent->name; } } if (done) break; /* * Setup name entries for all names that equals first_name */ for (i = 0; i < n; ++i) { if (ptrs[i] != NULL) { dent = ptrs[i]->data; if (strcmp(first_name, dent->name) == 0) { mask |= 1 << i; /* We treat empty dirs as a file. */ if (S_ISDIR(dent->mode) && memcmp (dent->id, EMPTY_SHA1, 40) != 0) dirmask |= 1 << i; hex_to_rawdata (dent->id, entries[i].sha1, 20); entries[i].path = dent->name; entries[i].pathlen = dent->name_len; entries[i].mode = dent->mode; ptrs[i] = ptrs[i]->next; } } } ret = info->fn (n, mask, dirmask, entries, info); if (ret < 0) { error = ret; } } g_free (entries); g_free (ptrs); return error; }