From: Michael Vrable Date: Fri, 8 Oct 2010 23:57:35 +0000 (-0700) Subject: Start adding in selective encryption of cloud log items. X-Git-Url: http://git.vrable.net/?p=bluesky.git;a=commitdiff_plain;h=52a6a600573a0483ea1aa99ec018e649299ea151 Start adding in selective encryption of cloud log items. Not fully hooked in, but some of the logic for encryption is written now. --- diff --git a/bluesky/bluesky-private.h b/bluesky/bluesky-private.h index dd55729..74b4e06 100644 --- a/bluesky/bluesky-private.h +++ b/bluesky/bluesky-private.h @@ -58,6 +58,23 @@ void bluesky_serialize_cloudlog(BlueSkyCloudLog *log, GString *authenticated, GString *writable); +/* Cryptographic operations. */ +#define CRYPTO_BLOCK_SIZE 16 /* 128-bit AES */ +#define CRYPTO_KEY_SIZE 16 +#define CRYPTO_HASH_SIZE 32 /* SHA-256 */ + +typedef struct BlueSkyCryptKeys { + uint8_t encryption_key[CRYPTO_KEY_SIZE]; + uint8_t authentication_key[CRYPTO_HASH_SIZE]; +} BlueSkyCryptKeys; + +void bluesky_crypt_init(); +void bluesky_crypt_hash_key(const char *keystr, uint8_t *out); +void bluesky_crypt_random_bytes(guchar *buf, gint len); +void bluesky_crypt_derive_keys(BlueSkyCryptKeys *keys, const gchar *master); +BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key); +BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key); + /* Storage layer. Requests can be performed asynchronously, so these objects * help keep track of operations in progress. */ typedef enum { diff --git a/bluesky/bluesky.h b/bluesky/bluesky.h index 4dab234..a4dfbbe 100644 --- a/bluesky/bluesky.h +++ b/bluesky/bluesky.h @@ -85,22 +85,6 @@ void bluesky_string_unref(BlueSkyRCStr *string); BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string); void bluesky_string_resize(BlueSkyRCStr *string, gsize len); -/* Cryptographic operations. */ -#define CRYPTO_BLOCK_SIZE 16 /* 128-bit AES */ -#define CRYPTO_KEY_SIZE 16 -#define CRYPTO_HASH_SIZE 32 /* SHA-256 */ - -struct BlueSkyCryptKeys { - uint8_t encryption_key[CRYPTO_KEY_SIZE]; - uint8_t authentication_key[CRYPTO_HASH_SIZE]; -}; - -void bluesky_crypt_init(); -void bluesky_crypt_hash_key(const char *keystr, uint8_t *out); -void bluesky_crypt_random_bytes(guchar *buf, gint len); -BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key); -BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key); - /* Storage interface. This presents a key-value store abstraction, and can * have multiple implementations: in-memory, on-disk, in-cloud. */ struct _BlueSkyStore; @@ -140,6 +124,8 @@ typedef enum { /* Filesystem state. Each filesystem which is exported is represented by a * single bluesky_fs structure in memory. */ +struct BlueSkyCryptKeys; + typedef struct { GMutex *lock; @@ -151,6 +137,10 @@ typedef struct { BlueSkyLog *log; BlueSkyCloudLogState *log_state; + /* Filesystem crypto keys */ + char *master_key; + struct BlueSkyCryptKeys *keys; + /* Accounting for memory used for caches. Space is measured in blocks, not * bytes. Updates to these variables must be made atomically. */ gint cache_dirty; @@ -313,7 +303,8 @@ typedef struct { BlueSkyRCStr *dirty; /* if DIRTY: raw data in memory */ } BlueSkyBlock; -BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store); +BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store, + const gchar *master_key); gboolean bluesky_inode_is_ready(BlueSkyInode *inode); diff --git a/bluesky/crypto.c b/bluesky/crypto.c index 5b22357..13e19c1 100644 --- a/bluesky/crypto.c +++ b/bluesky/crypto.c @@ -60,6 +60,101 @@ void bluesky_crypt_hash_key(const char *keystr, uint8_t *out) memcpy(out, raw_csum, CRYPTO_KEY_SIZE); } +/* Compute an HMAC of a given data block with the given key. The key and + * output should both as large as the hash output size. */ +#define MD_ALGO GCRY_MD_SHA256 +void bluesky_crypt_hmac(const char *buf, size_t bufsize, + const uint8_t key[CRYPTO_HASH_SIZE], + uint8_t output[CRYPTO_HASH_SIZE]) +{ + gcry_error_t status; + gcry_md_hd_t handle; + + g_assert(gcry_md_get_algo_dlen(MD_ALGO) == CRYPTO_HASH_SIZE); + + status = gcry_md_open(&handle, MD_ALGO, GCRY_MD_FLAG_HMAC); + if (status) { + g_error("gcrypt error setting up message digest: %s\n", + gcry_strerror(status)); + g_assert(FALSE); + } + + status = gcry_md_setkey(handle, key, CRYPTO_HASH_SIZE); + if (status) { + g_error("gcrypt error setting HMAC key: %s\n", + gcry_strerror(status)); + g_assert(FALSE); + } + + gcry_md_write(handle, buf, bufsize); + + unsigned char *digest = gcry_md_read(handle, MD_ALGO); + memcpy(output, digest, CRYPTO_HASH_SIZE); + + gcry_md_close(handle); +} + +void bluesky_crypt_derive_keys(BlueSkyCryptKeys *keys, const gchar *master) +{ + uint8_t outbuf[CRYPTO_HASH_SIZE]; + + const char *key_type = "ENCRYPT"; + bluesky_crypt_hmac(key_type, strlen(key_type), + (const uint8_t *)master, outbuf); + memcpy(keys->encryption_key, outbuf, sizeof(keys->encryption_key)); + + key_type = "AUTH"; + bluesky_crypt_hmac(key_type, strlen(key_type), + (const uint8_t *)master, outbuf); + memcpy(keys->authentication_key, outbuf, sizeof(keys->authentication_key)); +} + +void bluesky_crypt_block_encrypt(gchar *cloud_block, size_t len, + BlueSkyCryptKeys *keys) +{ + gcry_error_t status; + gcry_cipher_hd_t handle; + + status = gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, + 0); + if (status) { + g_error("gcrypt error setting up encryption: %s\n", + gcry_strerror(status)); + } + + struct cloudlog_header *header = (struct cloudlog_header *)cloud_block; + g_assert(memcmp(header->magic, CLOUDLOG_MAGIC, sizeof(header->magic)) == 0); + + gcry_cipher_setkey(handle, keys->encryption_key, CRYPTO_KEY_SIZE); + if (status) { + g_error("gcrypt error setting key: %s\n", + gcry_strerror(status)); + } + + bluesky_crypt_random_bytes(header->crypt_iv, sizeof(header->crypt_iv)); + status = gcry_cipher_setctr(handle, header->crypt_iv, + sizeof(header->crypt_iv)); + if (status) { + g_error("gcrypt error setting IV: %s\n", + gcry_strerror(status)); + } + + status = gcry_cipher_encrypt(handle, + cloud_block + sizeof(struct cloudlog_header), + GUINT32_FROM_LE(header->size1), + NULL, 0); + if (status) { + g_error("gcrypt error encrypting: %s\n", + gcry_strerror(status)); + } + + bluesky_crypt_hmac((char *)&header->crypt_iv, + cloud_block + len - (char *)&header->crypt_iv, + keys->authentication_key, + header->crypt_auth); +} + +#if 0 /* Encrypt a data block. */ BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key) { @@ -141,3 +236,4 @@ BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key) return bluesky_string_new(out, in->len - CRYPTO_BLOCK_SIZE); } +#endif diff --git a/bluesky/inode.c b/bluesky/inode.c index 7ace60d..b4b363c 100644 --- a/bluesky/inode.c +++ b/bluesky/inode.c @@ -104,9 +104,13 @@ BlueSkyFS *bluesky_new_fs(gchar *name) return fs; } -BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store) +BlueSkyFS *bluesky_init_fs(gchar *name, BlueSkyStore *store, + const gchar *master_key) { BlueSkyFS *fs = bluesky_new_fs(name); + fs->master_key = g_strdup(master_key); + fs->keys = g_new(BlueSkyCryptKeys, 1); + bluesky_crypt_derive_keys(fs->keys, master_key); fs->store = store; fs->log = bluesky_log_new("journal"); fs->log->fs = fs; diff --git a/nfs3/nfsd.c b/nfs3/nfsd.c index 8641a56..6c975f2 100644 --- a/nfs3/nfsd.c +++ b/nfs3/nfsd.c @@ -53,8 +53,12 @@ int main(int argc, char *argv[]) if (target == NULL) target = "s3"; + const char *key = getenv("BLUESKY_KEY"); + if (key == NULL) + key = ""; + store = bluesky_store_new(target); - fs = bluesky_init_fs("export", store); + fs = bluesky_init_fs("export", store, key); bluesky_crypt_random_bytes(nfsd_instance_verf_cookie, sizeof(nfsd_instance_verf_cookie));