1 /* Blue Sky: File Systems in the Cloud
3 * Copyright (C) 2009 The Regents of the University of California
4 * Written by Michael Vrable <mvrable@cs.ucsd.edu>
17 #include "bluesky-private.h"
19 /* Cryptographic operations. The rest of the BlueSky code merely calls into
20 * the functions in this file, so this is the only point where we interface
21 * with an external cryptographic library. */
23 /* TODO: We ought to switch to an authenticated encryption mode like EAX. */
25 GCRY_THREAD_OPTION_PTHREAD_IMPL;
27 void bluesky_crypt_init()
29 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
31 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
34 if (!gcry_check_version(GCRYPT_VERSION))
35 g_error("libgcrypt version mismatch\n");
37 gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
38 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
41 /* Return cryptographically-strong random data. */
42 void bluesky_crypt_random_bytes(guchar *buf, gint len)
44 gcry_randomize(buf, len, GCRY_STRONG_RANDOM);
47 /* Hash a string down to an encryption key. */
48 void bluesky_crypt_hash_key(const char *keystr, uint8_t *out)
51 gsize csum_len = sizeof(raw_csum);
53 assert(CRYPTO_KEY_SIZE == 16);
55 GChecksum *csum = g_checksum_new(G_CHECKSUM_SHA256);
56 g_checksum_update(csum, (const guchar *)keystr, strlen(keystr));
57 g_checksum_get_digest(csum, raw_csum, &csum_len);
58 g_checksum_free(csum);
60 memcpy(out, raw_csum, CRYPTO_KEY_SIZE);
63 /* Compute an HMAC of a given data block with the given key. The key and
64 * output should both as large as the hash output size. */
65 #define MD_ALGO GCRY_MD_SHA256
66 void bluesky_crypt_hmac(const char *buf, size_t bufsize,
67 const uint8_t key[CRYPTO_HASH_SIZE],
68 uint8_t output[CRYPTO_HASH_SIZE])
73 g_assert(gcry_md_get_algo_dlen(MD_ALGO) == CRYPTO_HASH_SIZE);
75 status = gcry_md_open(&handle, MD_ALGO, GCRY_MD_FLAG_HMAC);
77 g_error("gcrypt error setting up message digest: %s\n",
78 gcry_strerror(status));
82 status = gcry_md_setkey(handle, key, CRYPTO_HASH_SIZE);
84 g_error("gcrypt error setting HMAC key: %s\n",
85 gcry_strerror(status));
89 gcry_md_write(handle, buf, bufsize);
91 unsigned char *digest = gcry_md_read(handle, MD_ALGO);
92 memcpy(output, digest, CRYPTO_HASH_SIZE);
94 gcry_md_close(handle);
97 void bluesky_crypt_derive_keys(BlueSkyCryptKeys *keys, const gchar *master)
99 uint8_t outbuf[CRYPTO_HASH_SIZE];
101 const char *key_type = "ENCRYPT";
102 bluesky_crypt_hmac(key_type, strlen(key_type),
103 (const uint8_t *)master, outbuf);
104 memcpy(keys->encryption_key, outbuf, sizeof(keys->encryption_key));
107 bluesky_crypt_hmac(key_type, strlen(key_type),
108 (const uint8_t *)master, outbuf);
109 memcpy(keys->authentication_key, outbuf, sizeof(keys->authentication_key));
112 void bluesky_crypt_block_encrypt(gchar *cloud_block, size_t len,
113 BlueSkyCryptKeys *keys)
116 gcry_cipher_hd_t handle;
118 status = gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
121 g_error("gcrypt error setting up encryption: %s\n",
122 gcry_strerror(status));
125 struct cloudlog_header *header = (struct cloudlog_header *)cloud_block;
126 g_assert(memcmp(header->magic, CLOUDLOG_MAGIC, sizeof(header->magic)) == 0);
128 gcry_cipher_setkey(handle, keys->encryption_key, CRYPTO_KEY_SIZE);
130 g_error("gcrypt error setting key: %s\n",
131 gcry_strerror(status));
134 bluesky_crypt_random_bytes(header->crypt_iv, sizeof(header->crypt_iv));
135 status = gcry_cipher_setctr(handle, header->crypt_iv,
136 sizeof(header->crypt_iv));
138 g_error("gcrypt error setting IV: %s\n",
139 gcry_strerror(status));
142 status = gcry_cipher_encrypt(handle,
143 cloud_block + sizeof(struct cloudlog_header),
144 GUINT32_FROM_LE(header->size1),
147 g_error("gcrypt error encrypting: %s\n",
148 gcry_strerror(status));
151 bluesky_crypt_hmac((char *)&header->crypt_iv,
152 cloud_block + len - (char *)&header->crypt_iv,
153 keys->authentication_key,
158 /* Encrypt a data block. */
159 BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key)
162 gcry_cipher_hd_t handle;
164 status = gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
167 g_error("gcrypt error setting up encryption: %s\n",
168 gcry_strerror(status));
171 uint8_t *out = g_malloc0(in->len + CRYPTO_BLOCK_SIZE);
173 gcry_cipher_setkey(handle, key, CRYPTO_KEY_SIZE);
175 g_error("gcrypt error setting key: %s\n",
176 gcry_strerror(status));
179 bluesky_crypt_random_bytes(out, CRYPTO_BLOCK_SIZE);
180 status = gcry_cipher_setctr(handle, out, CRYPTO_BLOCK_SIZE);
182 g_error("gcrypt error setting IV: %s\n",
183 gcry_strerror(status));
186 status = gcry_cipher_encrypt(handle, out + CRYPTO_BLOCK_SIZE, in->len,
189 g_error("gcrypt error encrypting: %s\n",
190 gcry_strerror(status));
193 gcry_cipher_close(handle);
195 return bluesky_string_new(out, in->len + CRYPTO_BLOCK_SIZE);
198 /* Decrypt a data block. */
199 BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key)
202 gcry_cipher_hd_t handle;
204 g_return_val_if_fail(in->len > CRYPTO_BLOCK_SIZE, NULL);
206 status = gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
209 g_error("gcrypt error setting up encryption: %s\n",
210 gcry_strerror(status));
213 uint8_t *out = g_malloc0(in->len - CRYPTO_BLOCK_SIZE);
215 gcry_cipher_setkey(handle, key, CRYPTO_KEY_SIZE);
217 g_error("gcrypt error setting key: %s\n",
218 gcry_strerror(status));
221 status = gcry_cipher_setctr(handle, in->data, CRYPTO_BLOCK_SIZE);
223 g_error("gcrypt error setting IV: %s\n",
224 gcry_strerror(status));
227 status = gcry_cipher_decrypt(handle, out, in->len - CRYPTO_BLOCK_SIZE,
228 in->data + CRYPTO_BLOCK_SIZE,
229 in->len - CRYPTO_BLOCK_SIZE);
231 g_error("gcrypt error decrypting: %s\n",
232 gcry_strerror(status));
235 gcry_cipher_close(handle);
237 return bluesky_string_new(out, in->len - CRYPTO_BLOCK_SIZE);