Blame view

drivers/block/cryptoloop.c 4.26 KB
1b9391e34   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
     Linux loop encryption enabling module
  
     Copyright (C)  2002 Herbert Valerio Riedel <hvr@gnu.org>
     Copyright (C)  2003 Fruhwirth Clemens <clemens@endorphin.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
   */
  
  #include <linux/module.h>
84a2c9319   Herbert Xu   block: cryptoloop...
10
  #include <crypto/skcipher.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
  #include <linux/init.h>
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/blkdev.h>
45711f1af   Jens Axboe   [SG] Update drive...
14
  #include <linux/scatterlist.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
15
  #include <linux/uaccess.h>
83a876114   Al Viro   move linux/loop.h...
16
  #include "loop.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
26
27
28
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("loop blockdevice transferfunction adaptor / CryptoAPI");
  MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
  
  #define LOOP_IV_SECTOR_BITS 9
  #define LOOP_IV_SECTOR_SIZE (1 << LOOP_IV_SECTOR_BITS)
  
  static int
  cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
  {
  	int err = -EINVAL;
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
29
30
  	int cipher_len;
  	int mode_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  	char cms[LO_NAME_SIZE];			/* cipher-mode string */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  	char *mode;
  	char *cmsp = cms;			/* c-m string pointer */
dc568baf9   Kees Cook   block: cryptoloop...
34
  	struct crypto_sync_skcipher *tfm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
  
  	/* encryption breaks for non sector aligned offsets */
  
  	if (info->lo_offset % LOOP_IV_SECTOR_SIZE)
  		goto out;
  
  	strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE);
  	cms[LO_NAME_SIZE - 1] = 0;
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
43

69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  	cipher_len = strcspn(cmsp, "-");
  
  	mode = cmsp + cipher_len;
  	mode_len = 0;
  	if (*mode) {
  		mode++;
  		mode_len = strcspn(mode, "-");
  	}
  
  	if (!mode_len) {
  		mode = "cbc";
  		mode_len = 3;
  	}
  
  	if (cipher_len + mode_len + 3 > LO_NAME_SIZE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  		return -EINVAL;
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
60
61
62
63
64
65
66
  	memmove(cms, mode, mode_len);
  	cmsp = cms + mode_len;
  	*cmsp++ = '(';
  	memcpy(cmsp, info->lo_crypt_name, cipher_len);
  	cmsp += cipher_len;
  	*cmsp++ = ')';
  	*cmsp = 0;
dc568baf9   Kees Cook   block: cryptoloop...
67
  	tfm = crypto_alloc_sync_skcipher(cms, 0, 0);
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
68
69
  	if (IS_ERR(tfm))
  		return PTR_ERR(tfm);
dc568baf9   Kees Cook   block: cryptoloop...
70
71
  	err = crypto_sync_skcipher_setkey(tfm, info->lo_encrypt_key,
  					  info->lo_encrypt_key_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
  	if (err != 0)
  		goto out_free_tfm;
  
  	lo->key_data = tfm;
  	return 0;
  
   out_free_tfm:
dc568baf9   Kees Cook   block: cryptoloop...
79
  	crypto_free_sync_skcipher(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
  
   out:
  	return err;
  }
84a2c9319   Herbert Xu   block: cryptoloop...
84
  typedef int (*encdec_cbc_t)(struct skcipher_request *req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  static int
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
87
88
89
90
  cryptoloop_transfer(struct loop_device *lo, int cmd,
  		    struct page *raw_page, unsigned raw_off,
  		    struct page *loop_page, unsigned loop_off,
  		    int size, sector_t IV)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  {
dc568baf9   Kees Cook   block: cryptoloop...
92
93
  	struct crypto_sync_skcipher *tfm = lo->key_data;
  	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
45711f1af   Jens Axboe   [SG] Update drive...
94
95
  	struct scatterlist sg_out;
  	struct scatterlist sg_in;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
  
  	encdec_cbc_t encdecfunc;
  	struct page *in_page, *out_page;
  	unsigned in_offs, out_offs;
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
100
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

dc568baf9   Kees Cook   block: cryptoloop...
102
  	skcipher_request_set_sync_tfm(req, tfm);
84a2c9319   Herbert Xu   block: cryptoloop...
103
104
  	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
  				      NULL, NULL);
45711f1af   Jens Axboe   [SG] Update drive...
105
106
  	sg_init_table(&sg_out, 1);
  	sg_init_table(&sg_in, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
  	if (cmd == READ) {
  		in_page = raw_page;
  		in_offs = raw_off;
  		out_page = loop_page;
  		out_offs = loop_off;
84a2c9319   Herbert Xu   block: cryptoloop...
112
  		encdecfunc = crypto_skcipher_decrypt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
  	} else {
  		in_page = loop_page;
  		in_offs = loop_off;
  		out_page = raw_page;
  		out_offs = raw_off;
84a2c9319   Herbert Xu   block: cryptoloop...
118
  		encdecfunc = crypto_skcipher_encrypt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
  	}
  
  	while (size > 0) {
  		const int sz = min(size, LOOP_IV_SECTOR_SIZE);
  		u32 iv[4] = { 0, };
  		iv[0] = cpu_to_le32(IV & 0xffffffff);
642f14903   Jens Axboe   SG: Change sg_set...
125
126
  		sg_set_page(&sg_in, in_page, sz, in_offs);
  		sg_set_page(&sg_out, out_page, sz, out_offs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127

84a2c9319   Herbert Xu   block: cryptoloop...
128
129
  		skcipher_request_set_crypt(req, &sg_in, &sg_out, sz, iv);
  		err = encdecfunc(req);
69affe7fc   Herbert Xu   [BLOCK] cryptoloo...
130
  		if (err)
84a2c9319   Herbert Xu   block: cryptoloop...
131
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
  
  		IV++;
  		size -= sz;
  		in_offs += sz;
  		out_offs += sz;
  	}
84a2c9319   Herbert Xu   block: cryptoloop...
138
139
140
141
142
  	err = 0;
  
  out:
  	skcipher_request_zero(req);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
  }
  
  static int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
153
  cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
  {
  	return -EINVAL;
  }
  
  static int
  cryptoloop_release(struct loop_device *lo)
  {
dc568baf9   Kees Cook   block: cryptoloop...
154
  	struct crypto_sync_skcipher *tfm = lo->key_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	if (tfm != NULL) {
dc568baf9   Kees Cook   block: cryptoloop...
156
  		crypto_free_sync_skcipher(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  		lo->key_data = NULL;
  		return 0;
  	}
  	printk(KERN_ERR "cryptoloop_release(): tfm == NULL?
  ");
  	return -EINVAL;
  }
  
  static struct loop_func_table cryptoloop_funcs = {
  	.number = LO_CRYPT_CRYPTOAPI,
  	.init = cryptoloop_init,
  	.ioctl = cryptoloop_ioctl,
  	.transfer = cryptoloop_transfer,
  	.release = cryptoloop_release,
  	.owner = THIS_MODULE
  };
  
  static int __init
  init_cryptoloop(void)
  {
  	int rc = loop_register_transfer(&cryptoloop_funcs);
  
  	if (rc)
  		printk(KERN_ERR "cryptoloop: loop_register_transfer failed
  ");
  	return rc;
  }
  
  static void __exit
  cleanup_cryptoloop(void)
  {
  	if (loop_unregister_transfer(LO_CRYPT_CRYPTOAPI))
  		printk(KERN_ERR
  			"cryptoloop: loop_unregister_transfer failed
  ");
  }
  
  module_init(init_cryptoloop);
  module_exit(cleanup_cryptoloop);