X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Fcrypto.c;h=1dc5e0d4a92f4584350127777f39c39bb488a956;hb=818d00b4cceab93949aec208c8555aa8c409a0f2;hp=13e19c1b88ad067e935be3cadd87034f1aff8e17;hpb=f32dd89994b4f01a78d024bd1aa2ed41f526b8c8;p=bluesky.git diff --git a/bluesky/crypto.c b/bluesky/crypto.c index 13e19c1..1dc5e0d 100644 --- a/bluesky/crypto.c +++ b/bluesky/crypto.c @@ -109,6 +109,26 @@ 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) { @@ -131,27 +151,104 @@ 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)); + 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)); } - 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); + + gcry_cipher_close(handle); +} + +gboolean bluesky_crypt_block_decrypt(gchar *cloud_block, size_t len, + BlueSkyCryptKeys *keys) +{ + gcry_error_t status; + uint8_t hmac_check[CRYPTO_HASH_SIZE]; + + gboolean encrypted = TRUE; + + 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 (encrypted != bluesky_crypt_block_needs_encryption(header->type)) { + g_warning("Encrypted status of item does not match expected!\n"); } bluesky_crypt_hmac((char *)&header->crypt_iv, cloud_block + len - (char *)&header->crypt_iv, keys->authentication_key, - header->crypt_auth); + hmac_check); + if (memcmp(hmac_check, header->crypt_auth, CRYPTO_HASH_SIZE) != 0) { + g_warning("Cloud block HMAC does not match!\n"); + return FALSE; + } + + 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; + + gcry_cipher_close(handle); + } + + return TRUE; } #if 0