/*
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
*
* This file is released under the GPL.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/mempool.h>
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/workqueue.h>
#include <asm/atomic.h>
#include <asm/scatterlist.h>
#include <asm/page.h>
#include "dm.h"
#define PFX "crypt: "
/*
* per bio private data
*/
struct crypt_io {
struct dm_target *target;
struct bio *bio;
struct bio *first_clone;
struct work_struct work;
atomic_t pending;
int error;
};
/*
* context holding the current state of a multi-part conversion
*/
struct convert_context {
struct bio *bio_in;
struct bio *bio_out;
unsigned int offset_in;
unsigned int offset_out;
unsigned int idx_in;
unsigned int idx_out;
sector_t sector;
int write;
};
struct crypt_config;
struct crypt_iv_operations {
int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
const char *opts);
void (*dtr)(struct crypt_config *cc);
const char *(*status)(struct crypt_config *cc);
int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
};
/*
* Crypt: maps a linear range of a block device
* and encrypts / decrypts at the same time.
*/
struct crypt_config {
struct dm_dev *dev;
sector_t start;
/*
* pool for per bio private data and
* for encryption buffer pages
*/
mempool_t *io_pool;
mempool_t *page_pool;
/*
* crypto related data
*/
struct crypt_iv_operations *iv_gen_ops;
char *iv_mode;
void *iv_gen_private;
sector_t iv_offset;
unsigned int iv_size;
struct crypto_tfm *tfm;
unsigned int key_size;
u8 key[0];
};
#define MIN_IOS 256
#define MIN_POOL_PAGES 32
#define MIN_BIO_PAGES 8
static kmem_cache_t *_crypt_io_pool;
/*
* Mempool alloc and free functions for the page
*/
static void *mempool_alloc_page(unsigned int __nocast gfp_mask, void *data)
{
return alloc_page(gfp_mask);
}
static void mempool_free_page(void *page, void *data)
{
__free_page(page);
}
/*
* Different IV generation algorithms:
*
* plain: the initial vector is the 32-bit low-endian version of the sector
* number, padded with zeros if neccessary.
*
* ess_iv: "encrypted sector|salt initial vector", the sector number is
* encrypted with the bulk cipher using a salt as key. The salt
* should be derived from the bulk cipher's key via hashing.
*
* plumb: unimplemented, see:
* http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
*/
static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
{
memset(iv, 0, cc->iv_size);
*(u32 *)iv = cpu_to_le32(sector & 0xffffffff);
return 0;
}
static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
struct crypto_tfm *essiv_tfm;
struct crypto_tfm *hash_tfm;
struct scatterlist sg;
unsigned int saltsize;
u8 *salt;
if (opts == NULL) {
ti->error = PFX "Digest algorithm missing for ESSIV mode";
return -EINVAL;
}
/* Hash the cipher key with the given hash algorithm */
hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
if (hash_tfm == NULL) {
ti->error = PFX "Error initializing ESSIV hash";
return -EINVAL;
}
if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) {
ti->error = PFX "Expected digest algorithm for ESSIV hash";
crypto_free_tfm(hash_tfm);
return -EINVAL;
}
saltsize = crypto_tfm_alg_digestsize(hash_tfm);
salt = kmalloc(saltsize, GFP_KERNEL);
if (salt == NULL) {
ti->error = PFX "Error kmallocing salt storage in ESSIV";
crypto_free_tfm(hash_tfm);
return -ENOMEM;
}
sg.page = virt_to_page(cc->key);
sg.offset = offset_in_page(cc->key);
sg.length = cc->key_size;
crypto_digest_digest(hash_tfm, &sg, 1, salt);
crypto_free_tfm(hash_tfm);
/* Setup the essiv_tfm with the given salt */
essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
CRYPTO_TFM_MODE_ECB |
CRYPTO_TFM_REQ_MAY_SLEEP);
if (essiv_tfm == NULL) {
ti->error = PFX "Error allocating crypto tfm for ESSIV";
kfree(salt);
return -EINVAL;
}
if (crypto_tfm_alg_blocksize