/*
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
#include <linux/err.h>
#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 <linux/backing-dev.h>
#include <asm/atomic.h>
#include <linux/scatterlist.h>
#include <asm/page.h>
#include "dm.h"
#define DM_MSG_PREFIX "crypt"
#define MESG_STR(x) x, sizeof(x)
/*
* per bio private data
*/
struct crypt_io {
struct dm_target *target;
struct bio *base_bio;
struct bio *first_clone;
struct work_struct work;
atomic_t pending;
int error;
int post_process;
};
/*
* 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.
*/
enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
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;
struct bio_set *bs;
/*
* crypto related data
*/
struct crypt_iv_operations *iv_gen_ops;
char *iv_mode;
struct crypto_cipher *iv_gen_private;
sector_t iv_offset;
unsigned int iv_size;
char cipher[CRYPTO_MAX_ALG_NAME];
char chainmode[CRYPTO_MAX_ALG_NAME];
struct crypto_blkcipher *tfm;
unsigned long flags;
unsigned int key_size;
u8 key[0];
};
#define MIN_IOS 16
#define MIN_POOL_PAGES 32
#define MIN_BIO_PAGES 8
static kmem_cache_t *_crypt_io_pool;
/*
* Different IV generation algorithms:
*
* plain: the initial vector is the 32-bit little-endian version of the sector
* number, padded with zeros if neccessary.
*
* essiv: "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_cipher *essiv_tfm;
struct crypto_hash *hash_tfm;
struct hash_desc desc;
struct scatterlist sg;
unsigned int saltsize;
u8 *salt;
int err;
if (opts == NULL) {
ti->error = "Digest algorithm missing for ESSIV mode";
return -EINVAL;
}
/* Hash the cipher key with the given hash algorithm */
hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hash_tfm)) {
ti->error = "Error initializing ESSIV hash";
return PTR_ERR(hash_tfm);
}
saltsize = crypto_hash_digestsize(hash_tfm);
salt = kmalloc(saltsize, GFP_KERNEL);
if (salt == NULL) {
ti->error = "Error kmallocing salt storage in ESSIV";
crypto_free_hash(hash_tfm);
return -ENOMEM;
}
sg_set_buf(&sg, cc->key, cc->key_size);
desc.tfm =