at v2.6.14-rc2 270 lines 6.7 kB view raw
1/* 2 Linux loop encryption enabling module 3 4 Copyright (C) 2002 Herbert Valerio Riedel <hvr@gnu.org> 5 Copyright (C) 2003 Fruhwirth Clemens <clemens@endorphin.org> 6 7 This module is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This module is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this module; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22#include <linux/module.h> 23 24#include <linux/init.h> 25#include <linux/string.h> 26#include <linux/crypto.h> 27#include <linux/blkdev.h> 28#include <linux/loop.h> 29#include <asm/semaphore.h> 30#include <asm/uaccess.h> 31 32MODULE_LICENSE("GPL"); 33MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI"); 34MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>"); 35 36#define LOOP_IV_SECTOR_BITS 9 37#define LOOP_IV_SECTOR_SIZE (1 << LOOP_IV_SECTOR_BITS) 38 39static int 40cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) 41{ 42 int err = -EINVAL; 43 char cms[LO_NAME_SIZE]; /* cipher-mode string */ 44 char *cipher; 45 char *mode; 46 char *cmsp = cms; /* c-m string pointer */ 47 struct crypto_tfm *tfm = NULL; 48 49 /* encryption breaks for non sector aligned offsets */ 50 51 if (info->lo_offset % LOOP_IV_SECTOR_SIZE) 52 goto out; 53 54 strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE); 55 cms[LO_NAME_SIZE - 1] = 0; 56 cipher = strsep(&cmsp, "-"); 57 mode = strsep(&cmsp, "-"); 58 59 if (mode == NULL || strcmp(mode, "cbc") == 0) 60 tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC | 61 CRYPTO_TFM_REQ_MAY_SLEEP); 62 else if (strcmp(mode, "ecb") == 0) 63 tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB | 64 CRYPTO_TFM_REQ_MAY_SLEEP); 65 if (tfm == NULL) 66 return -EINVAL; 67 68 err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key, 69 info->lo_encrypt_key_size); 70 71 if (err != 0) 72 goto out_free_tfm; 73 74 lo->key_data = tfm; 75 return 0; 76 77 out_free_tfm: 78 crypto_free_tfm(tfm); 79 80 out: 81 return err; 82} 83 84 85typedef int (*encdec_ecb_t)(struct crypto_tfm *tfm, 86 struct scatterlist *sg_out, 87 struct scatterlist *sg_in, 88 unsigned int nsg); 89 90 91static int 92cryptoloop_transfer_ecb(struct loop_device *lo, int cmd, 93 struct page *raw_page, unsigned raw_off, 94 struct page *loop_page, unsigned loop_off, 95 int size, sector_t IV) 96{ 97 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; 98 struct scatterlist sg_out = { NULL, }; 99 struct scatterlist sg_in = { NULL, }; 100 101 encdec_ecb_t encdecfunc; 102 struct page *in_page, *out_page; 103 unsigned in_offs, out_offs; 104 105 if (cmd == READ) { 106 in_page = raw_page; 107 in_offs = raw_off; 108 out_page = loop_page; 109 out_offs = loop_off; 110 encdecfunc = tfm->crt_u.cipher.cit_decrypt; 111 } else { 112 in_page = loop_page; 113 in_offs = loop_off; 114 out_page = raw_page; 115 out_offs = raw_off; 116 encdecfunc = tfm->crt_u.cipher.cit_encrypt; 117 } 118 119 while (size > 0) { 120 const int sz = min(size, LOOP_IV_SECTOR_SIZE); 121 122 sg_in.page = in_page; 123 sg_in.offset = in_offs; 124 sg_in.length = sz; 125 126 sg_out.page = out_page; 127 sg_out.offset = out_offs; 128 sg_out.length = sz; 129 130 encdecfunc(tfm, &sg_out, &sg_in, sz); 131 132 size -= sz; 133 in_offs += sz; 134 out_offs += sz; 135 } 136 137 return 0; 138} 139 140typedef int (*encdec_cbc_t)(struct crypto_tfm *tfm, 141 struct scatterlist *sg_out, 142 struct scatterlist *sg_in, 143 unsigned int nsg, u8 *iv); 144 145static int 146cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, 147 struct page *raw_page, unsigned raw_off, 148 struct page *loop_page, unsigned loop_off, 149 int size, sector_t IV) 150{ 151 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; 152 struct scatterlist sg_out = { NULL, }; 153 struct scatterlist sg_in = { NULL, }; 154 155 encdec_cbc_t encdecfunc; 156 struct page *in_page, *out_page; 157 unsigned in_offs, out_offs; 158 159 if (cmd == READ) { 160 in_page = raw_page; 161 in_offs = raw_off; 162 out_page = loop_page; 163 out_offs = loop_off; 164 encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv; 165 } else { 166 in_page = loop_page; 167 in_offs = loop_off; 168 out_page = raw_page; 169 out_offs = raw_off; 170 encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv; 171 } 172 173 while (size > 0) { 174 const int sz = min(size, LOOP_IV_SECTOR_SIZE); 175 u32 iv[4] = { 0, }; 176 iv[0] = cpu_to_le32(IV & 0xffffffff); 177 178 sg_in.page = in_page; 179 sg_in.offset = in_offs; 180 sg_in.length = sz; 181 182 sg_out.page = out_page; 183 sg_out.offset = out_offs; 184 sg_out.length = sz; 185 186 encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv); 187 188 IV++; 189 size -= sz; 190 in_offs += sz; 191 out_offs += sz; 192 } 193 194 return 0; 195} 196 197static int 198cryptoloop_transfer(struct loop_device *lo, int cmd, 199 struct page *raw_page, unsigned raw_off, 200 struct page *loop_page, unsigned loop_off, 201 int size, sector_t IV) 202{ 203 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; 204 if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB) 205 { 206 lo->transfer = cryptoloop_transfer_ecb; 207 return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off, 208 loop_page, loop_off, size, IV); 209 } 210 if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC) 211 { 212 lo->transfer = cryptoloop_transfer_cbc; 213 return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off, 214 loop_page, loop_off, size, IV); 215 } 216 217 /* This is not supposed to happen */ 218 219 printk( KERN_ERR "cryptoloop: unsupported cipher mode in cryptoloop_transfer!\n"); 220 return -EINVAL; 221} 222 223static int 224cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg) 225{ 226 return -EINVAL; 227} 228 229static int 230cryptoloop_release(struct loop_device *lo) 231{ 232 struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; 233 if (tfm != NULL) { 234 crypto_free_tfm(tfm); 235 lo->key_data = NULL; 236 return 0; 237 } 238 printk(KERN_ERR "cryptoloop_release(): tfm == NULL?\n"); 239 return -EINVAL; 240} 241 242static struct loop_func_table cryptoloop_funcs = { 243 .number = LO_CRYPT_CRYPTOAPI, 244 .init = cryptoloop_init, 245 .ioctl = cryptoloop_ioctl, 246 .transfer = cryptoloop_transfer, 247 .release = cryptoloop_release, 248 .owner = THIS_MODULE 249}; 250 251static int __init 252init_cryptoloop(void) 253{ 254 int rc = loop_register_transfer(&cryptoloop_funcs); 255 256 if (rc) 257 printk(KERN_ERR "cryptoloop: loop_register_transfer failed\n"); 258 return rc; 259} 260 261static void __exit 262cleanup_cryptoloop(void) 263{ 264 if (loop_unregister_transfer(LO_CRYPT_CRYPTOAPI)) 265 printk(KERN_ERR 266 "cryptoloop: loop_unregister_transfer failed\n"); 267} 268 269module_init(init_cryptoloop); 270module_exit(cleanup_cryptoloop);