Encrypt data blocks being stored to S3.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 2 Sep 2009 03:35:55 +0000 (20:35 -0700)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Wed, 2 Sep 2009 03:35:55 +0000 (20:35 -0700)
CMakeLists.txt
bluesky/CMakeLists.txt
bluesky/bluesky.h
bluesky/crypto.c [new file with mode: 0644]
bluesky/inode.c
nfs3/nfsd.c

index 5bdb01c..da22511 100644 (file)
@@ -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)
index d84d7b7..3500918 100644 (file)
@@ -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 "")
index 856dd75..afb2304 100644 (file)
@@ -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 (file)
index 0000000..6eec464
--- /dev/null
@@ -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 <mvrable@cs.ucsd.edu>
+ *
+ * TODO: Licensing
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <pthread.h>
+#include <glib.h>
+#include <string.h>
+#include <gcrypt.h>
+
+#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);
+}
index 7ea8dbf..42b045c 100644 (file)
@@ -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);
 }
index ab7b749..f80b01a 100644 (file)
 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);