X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Fcrypto.c;h=492e4ff71a5efde9dfd47a2aa1f04744a18d5ac1;hb=8ff0fd08d6e1cc97cdb7e94b7cd97dc28c29e674;hp=13e19c1b88ad067e935be3cadd87034f1aff8e17;hpb=52a6a600573a0483ea1aa99ec018e649299ea151;p=bluesky.git diff --git a/bluesky/crypto.c b/bluesky/crypto.c index 13e19c1..492e4ff 100644 --- a/bluesky/crypto.c +++ b/bluesky/crypto.c @@ -3,7 +3,29 @@ * Copyright (C) 2009 The Regents of the University of California * Written by Michael Vrable * - * TODO: Licensing + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #include @@ -109,9 +131,32 @@ void bluesky_crypt_derive_keys(BlueSkyCryptKeys *keys, const gchar *master) memcpy(keys->authentication_key, outbuf, sizeof(keys->authentication_key)); } +/* A boolean: are blocks of the specified type encrypted in the BlueSky file + * system? */ +gboolean bluesky_crypt_block_needs_encryption(uint8_t type) +{ + type -= '0'; + + switch (type) { + case LOGTYPE_DATA: + case LOGTYPE_INODE: + return TRUE; + case LOGTYPE_INODE_MAP: + case LOGTYPE_CHECKPOINT: + return FALSE; + default: + g_warning("Unknown log item type in crypto layer: %d!\n", + type); + return TRUE; + } +} + void bluesky_crypt_block_encrypt(gchar *cloud_block, size_t len, BlueSkyCryptKeys *keys) { + if (bluesky_options.disable_crypto) + return; + gcry_error_t status; gcry_cipher_hd_t handle; @@ -131,109 +176,116 @@ void bluesky_crypt_block_encrypt(gchar *cloud_block, size_t len, 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)); + gboolean encrypted = bluesky_crypt_block_needs_encryption(header->type); + + if (encrypted) { + header->magic[3] ^= 0x10; + + 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)); + } + } else { + memset(header->crypt_iv, 0, sizeof(header->crypt_iv)); } bluesky_crypt_hmac((char *)&header->crypt_iv, - cloud_block + len - (char *)&header->crypt_iv, + cloud_block + len - (char *)&header->crypt_iv - GUINT32_FROM_LE(header->size3), keys->authentication_key, header->crypt_auth); -} - -#if 0 -/* 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_CTR, - 0); - 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_setctr(handle, out, CRYPTO_BLOCK_SIZE); - if (status) { - g_error("gcrypt error setting IV: %s\n", - gcry_strerror(status)); - } - - 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); } -/* Decrypt a data block. */ -BlueSkyRCStr *bluesky_crypt_decrypt(BlueSkyRCStr *in, const uint8_t *key) +gboolean bluesky_crypt_block_decrypt(gchar *cloud_block, size_t len, + BlueSkyCryptKeys *keys, + gboolean allow_unauth) { gcry_error_t status; - gcry_cipher_hd_t handle; + uint8_t hmac_check[CRYPTO_HASH_SIZE]; - g_return_val_if_fail(in->len > CRYPTO_BLOCK_SIZE, NULL); + gboolean encrypted = TRUE; - 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; + if (memcmp(header->magic, CLOUDLOG_MAGIC, + sizeof(header->magic)) == 0) + encrypted = FALSE; + else + g_assert(memcmp(header->magic, CLOUDLOG_MAGIC_ENCRYPTED, + sizeof(header->magic)) == 0); + + if (bluesky_options.disable_crypto) { + g_assert(encrypted == FALSE); + return TRUE; } - 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)); + if (encrypted != bluesky_crypt_block_needs_encryption(header->type)) { + g_warning("Encrypted status of item does not match expected!\n"); } - status = gcry_cipher_setctr(handle, in->data, CRYPTO_BLOCK_SIZE); - if (status) { - g_error("gcrypt error setting IV: %s\n", - gcry_strerror(status)); + bluesky_crypt_hmac((char *)&header->crypt_iv, + cloud_block + len - (char *)&header->crypt_iv - GUINT32_FROM_LE(header->size3), + keys->authentication_key, + hmac_check); + if (memcmp(hmac_check, header->crypt_auth, CRYPTO_HASH_SIZE) != 0) { + g_warning("Cloud block HMAC does not match!"); + if (allow_unauth + && (header->type == LOGTYPE_INODE_MAP + '0' + || header->type == LOGTYPE_CHECKPOINT + '0')) + { + g_warning("Allowing unauthenticated data from cleaner"); + } else { + return FALSE; + } } - status = gcry_cipher_decrypt(handle, out, in->len - CRYPTO_BLOCK_SIZE, - in->data + CRYPTO_BLOCK_SIZE, - in->len - CRYPTO_BLOCK_SIZE); - if (status) { - g_error("gcrypt error decrypting: %s\n", - gcry_strerror(status)); + if (encrypted) { + 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)); + } + + gcry_cipher_setkey(handle, keys->encryption_key, CRYPTO_KEY_SIZE); + if (status) { + g_error("gcrypt error setting key: %s\n", + gcry_strerror(status)); + } + + 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_decrypt(handle, + cloud_block + sizeof(struct cloudlog_header), + GUINT32_FROM_LE(header->size1), + NULL, 0); + if (status) { + g_error("gcrypt error decrypting: %s\n", + gcry_strerror(status)); + } + header->magic[3] ^= 0x10; + memset(header->crypt_iv, 0, sizeof(header->crypt_iv)); + + gcry_cipher_close(handle); } - gcry_cipher_close(handle); - - return bluesky_string_new(out, in->len - CRYPTO_BLOCK_SIZE); + return TRUE; } -#endif