From: Michael Vrable Date: Wed, 2 Sep 2009 03:35:55 +0000 (-0700) Subject: Encrypt data blocks being stored to S3. X-Git-Url: http://git.vrable.net/?p=bluesky.git;a=commitdiff_plain;h=c83d8b650786b8e7d6a9d41c9449c203929c7215 Encrypt data blocks being stored to S3. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bdb01c..da22511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 2.6) project(bluesky) +set(CMAKE_BUILD_TYPE Debug) include(FindPkgConfig) pkg_check_modules(GLIB REQUIRED glib-2.0 gthread-2.0) diff --git a/bluesky/CMakeLists.txt b/bluesky/CMakeLists.txt index d84d7b7..3500918 100644 --- a/bluesky/CMakeLists.txt +++ b/bluesky/CMakeLists.txt @@ -1,13 +1,13 @@ link_directories(/home/mvrable/scratch/libs3-1.4/build/lib) -add_library(bluesky SHARED dir.c inode.c store.c s3store.c) +add_library(bluesky SHARED crypto.c dir.c inode.c store.c s3store.c) add_executable(bluesky-test main.c) set(CMAKE_C_FLAGS "-std=gnu99 ${CMAKE_C_FLAGS}") set(INSTALL_RPATH_USE_LINK_PATH 1) include_directories(${GLIB_INCLUDE_DIRS}) -target_link_libraries(bluesky ${GLIB_LIBRARIES} s3) +target_link_libraries(bluesky ${GLIB_LIBRARIES} gcrypt s3) target_link_libraries(bluesky-test bluesky ${GLIB_LIBRARIES}) #set_target_properties(bluesky PROPERTIES LINK_INTERFACE_LIBRARIES "") diff --git a/bluesky/bluesky.h b/bluesky/bluesky.h index 856dd75..afb2304 100644 --- a/bluesky/bluesky.h +++ b/bluesky/bluesky.h @@ -31,6 +31,11 @@ void bluesky_string_ref(BlueSkyRCStr *string); void bluesky_string_unref(BlueSkyRCStr *string); BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string); +/* Cryptographic operations. */ +void bluesky_crypt_init(); +void bluesky_crypt_random_bytes(guchar *buf, gint len); +BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key); + /* File types. The numeric values are chosen to match with those used in * NFSv3. */ typedef enum { @@ -53,6 +58,8 @@ typedef struct { uint64_t next_inum; /* Next available inode for allocation */ struct S3Store *store; + + uint8_t *encryption_key; } BlueSkyFS; /* Inode number of the root directory. */ @@ -63,10 +70,18 @@ typedef int64_t bluesky_time; /* In-memory representation of an inode within a Blue Sky server. This * corresponds roughly with information that is committed to persistent - * storage. */ + * storage. Locking/refcounting rules: + * - To access or modify any data fields, the lock must be held. This + * includes file blocks. + * - One reference is held by the BlueSkyFS inode hash table. If that is the + * only reference (and the inode is unlocked), the inode is subject to + * dropping from the cache. + * - Any pending operations should hold extra references to the inode as + * appropriate to keep it available until the operation completes. + * */ typedef struct { - gint refcnt; /* May be accessed atomically without lock */ GMutex *lock; + gint refcount; BlueSkyFS *fs; diff --git a/bluesky/crypto.c b/bluesky/crypto.c new file mode 100644 index 0000000..6eec464 --- /dev/null +++ b/bluesky/crypto.c @@ -0,0 +1,87 @@ +/* Blue Sky: File Systems in the Cloud + * + * Copyright (C) 2009 The Regents of the University of California + * Written by Michael Vrable + * + * TODO: Licensing + */ + +#include +#include +#include +#include +#include +#include + +#include "bluesky.h" + +/* Cryptographic operations. The rest of the BlueSky code merely calls into + * the functions in this file, so this is the only point where we interface + * with an external cryptographic library. */ + +#define CRYPTO_BLOCK_SIZE 16 /* 128-bit AES */ +#define CRYPTO_KEY_SIZE 16 + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +void bluesky_crypt_init() +{ + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + g_print("libgcrypt not yet initialized, initializing...\n"); + + if (!gcry_check_version(GCRYPT_VERSION)) + g_error("libgcrypt version mismatch\n"); + + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} + +/* Return cryptographically-strong random data. */ +void bluesky_crypt_random_bytes(guchar *buf, gint len) +{ + gcry_randomize(buf, len, GCRY_STRONG_RANDOM); +} + +/* Encrypt a data block. */ +BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key) +{ + gcry_error_t status; + gcry_cipher_hd_t handle; + + status = gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, + GCRY_CIPHER_CBC_CTS); + if (status) { + g_error("gcrypt error setting up encryption: %s\n", + gcry_strerror(status)); + } + + uint8_t *out = g_malloc0(in->len + CRYPTO_BLOCK_SIZE); + + gcry_cipher_setkey(handle, key, CRYPTO_KEY_SIZE); + if (status) { + g_error("gcrypt error setting key: %s\n", + gcry_strerror(status)); + } + + bluesky_crypt_random_bytes(out, CRYPTO_BLOCK_SIZE); + status = gcry_cipher_setiv(handle, out, CRYPTO_BLOCK_SIZE); + if (status) { + g_error("gcrypt error setting IV: %s\n", + gcry_strerror(status)); + } + + gcry_cipher_encrypt(handle, out + CRYPTO_BLOCK_SIZE, in->len, + in->data, in->len); + if (status) { + g_error("gcrypt error encrypting: %s\n", + gcry_strerror(status)); + } + + gcry_cipher_close(handle); + + return bluesky_string_new(out, in->len + CRYPTO_BLOCK_SIZE); +} diff --git a/bluesky/inode.c b/bluesky/inode.c index 7ea8dbf..42b045c 100644 --- a/bluesky/inode.c +++ b/bluesky/inode.c @@ -119,6 +119,20 @@ BlueSkyFS *bluesky_new_fs(gchar *name) return fs; } +/* Inode reference counting. */ +void bluesky_inode_ref(BlueSkyInode *inode) +{ + g_atomic_int_inc(&inode->refcount); +} + +void bluesky_inode_unref(BlueSkyInode *inode) +{ + if (g_atomic_int_dec_and_test(&inode->refcount)) { + g_error("Reference count for inode %lld dropped to zero!\n", + inode->inum); + } +} + /* Allocate a fresh inode number which has not been used before within a * filesystem. */ uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs) @@ -139,6 +153,7 @@ BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFS *fs, BlueSkyInode *i = g_new0(BlueSkyInode, 1); i->lock = g_mutex_new(); + i->refcount = 1; i->type = type; i->fs = fs; i->inum = inum; @@ -337,12 +352,15 @@ void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block) if (block->type != BLUESKY_BLOCK_DIRTY) return; + BlueSkyRCStr *data = block->data; + data = bluesky_crypt_encrypt(data, fs->encryption_key); + GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256); - g_checksum_update(csum, block->data->data, block->data->len); + g_checksum_update(csum, data->data, data->len); gchar *name = g_strdup(g_checksum_get_string(csum)); g_print("Flushing block as %s\n", name); - s3store_put(fs->store, name, block->data); + s3store_put(fs->store, name, data); g_free(block->ref); block->ref = name; @@ -352,4 +370,5 @@ void bluesky_block_flush(BlueSkyFS *fs, BlueSkyBlock *block) block->type = BLUESKY_BLOCK_REF; g_checksum_free(csum); + bluesky_string_unref(data); } diff --git a/nfs3/nfsd.c b/nfs3/nfsd.c index ab7b749..f80b01a 100644 --- a/nfs3/nfsd.c +++ b/nfs3/nfsd.c @@ -25,15 +25,26 @@ void register_rpc(); BlueSkyFS *fs; +static uint8_t filesystem_key[16]; int main(int argc, char *argv[]) { + int i; g_thread_init(NULL); + bluesky_crypt_init(); register_rpc(); + bluesky_crypt_random_bytes(filesystem_key, sizeof(filesystem_key)); + printf("Filesystem key: "); + for (i = 0; i < sizeof(filesystem_key); i++) { + printf("%02x", filesystem_key[i]); + } + printf("\n"); + S3_initialize(NULL, S3_INIT_ALL); fs = bluesky_new_fs("export"); + fs->encryption_key = filesystem_key; BlueSkyInode *root; root = bluesky_new_inode(BLUESKY_ROOT_INUM, fs, BLUESKY_DIRECTORY);