Encrypt data blocks being stored to S3.
[bluesky.git] / bluesky / crypto.c
1 /* Blue Sky: File Systems in the Cloud
2  *
3  * Copyright (C) 2009  The Regents of the University of California
4  * Written by Michael Vrable <mvrable@cs.ucsd.edu>
5  *
6  * TODO: Licensing
7  */
8
9 #include <stdint.h>
10 #include <errno.h>
11 #include <pthread.h>
12 #include <glib.h>
13 #include <string.h>
14 #include <gcrypt.h>
15
16 #include "bluesky.h"
17
18 /* Cryptographic operations.  The rest of the BlueSky code merely calls into
19  * the functions in this file, so this is the only point where we interface
20  * with an external cryptographic library. */
21
22 #define CRYPTO_BLOCK_SIZE 16        /* 128-bit AES */
23 #define CRYPTO_KEY_SIZE   16
24
25 GCRY_THREAD_OPTION_PTHREAD_IMPL;
26
27 void bluesky_crypt_init()
28 {
29     gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
30
31     if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
32         return;
33
34     g_print("libgcrypt not yet initialized, initializing...\n");
35
36     if (!gcry_check_version(GCRYPT_VERSION))
37         g_error("libgcrypt version mismatch\n");
38
39     gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
40     gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
41 }
42
43 /* Return cryptographically-strong random data. */
44 void bluesky_crypt_random_bytes(guchar *buf, gint len)
45 {
46     gcry_randomize(buf, len, GCRY_STRONG_RANDOM);
47 }
48
49 /* Encrypt a data block. */
50 BlueSkyRCStr *bluesky_crypt_encrypt(BlueSkyRCStr *in, const uint8_t *key)
51 {
52     gcry_error_t status;
53     gcry_cipher_hd_t handle;
54
55     status = gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC,
56                               GCRY_CIPHER_CBC_CTS);
57     if (status) {
58         g_error("gcrypt error setting up encryption: %s\n",
59                 gcry_strerror(status));
60     }
61
62     uint8_t *out = g_malloc0(in->len + CRYPTO_BLOCK_SIZE);
63
64     gcry_cipher_setkey(handle, key, CRYPTO_KEY_SIZE);
65     if (status) {
66         g_error("gcrypt error setting key: %s\n",
67                 gcry_strerror(status));
68     }
69
70     bluesky_crypt_random_bytes(out, CRYPTO_BLOCK_SIZE);
71     status = gcry_cipher_setiv(handle, out, CRYPTO_BLOCK_SIZE);
72     if (status) {
73         g_error("gcrypt error setting IV: %s\n",
74                 gcry_strerror(status));
75     }
76
77     gcry_cipher_encrypt(handle, out + CRYPTO_BLOCK_SIZE, in->len,
78                         in->data, in->len);
79     if (status) {
80         g_error("gcrypt error encrypting: %s\n",
81                 gcry_strerror(status));
82     }
83
84     gcry_cipher_close(handle);
85
86     return bluesky_string_new(out, in->len + CRYPTO_BLOCK_SIZE);
87 }