diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/cryptoloop.c | 160 |
1 files changed, 54 insertions, 106 deletions
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c index 3d4261c39f16..40535036e893 100644 --- a/drivers/block/cryptoloop.c +++ b/drivers/block/cryptoloop.c | |||
@@ -40,11 +40,13 @@ static int | |||
40 | cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) | 40 | cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) |
41 | { | 41 | { |
42 | int err = -EINVAL; | 42 | int err = -EINVAL; |
43 | int cipher_len; | ||
44 | int mode_len; | ||
43 | char cms[LO_NAME_SIZE]; /* cipher-mode string */ | 45 | char cms[LO_NAME_SIZE]; /* cipher-mode string */ |
44 | char *cipher; | 46 | char *cipher; |
45 | char *mode; | 47 | char *mode; |
46 | char *cmsp = cms; /* c-m string pointer */ | 48 | char *cmsp = cms; /* c-m string pointer */ |
47 | struct crypto_tfm *tfm = NULL; | 49 | struct crypto_blkcipher *tfm; |
48 | 50 | ||
49 | /* encryption breaks for non sector aligned offsets */ | 51 | /* encryption breaks for non sector aligned offsets */ |
50 | 52 | ||
@@ -53,20 +55,39 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) | |||
53 | 55 | ||
54 | strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE); | 56 | strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE); |
55 | cms[LO_NAME_SIZE - 1] = 0; | 57 | cms[LO_NAME_SIZE - 1] = 0; |
56 | cipher = strsep(&cmsp, "-"); | 58 | |
57 | mode = strsep(&cmsp, "-"); | 59 | cipher = cmsp; |
58 | 60 | cipher_len = strcspn(cmsp, "-"); | |
59 | if (mode == NULL || strcmp(mode, "cbc") == 0) | 61 | |
60 | tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC | | 62 | mode = cmsp + cipher_len; |
61 | CRYPTO_TFM_REQ_MAY_SLEEP); | 63 | mode_len = 0; |
62 | else if (strcmp(mode, "ecb") == 0) | 64 | if (*mode) { |
63 | tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB | | 65 | mode++; |
64 | CRYPTO_TFM_REQ_MAY_SLEEP); | 66 | mode_len = strcspn(mode, "-"); |
65 | if (tfm == NULL) | 67 | } |
68 | |||
69 | if (!mode_len) { | ||
70 | mode = "cbc"; | ||
71 | mode_len = 3; | ||
72 | } | ||
73 | |||
74 | if (cipher_len + mode_len + 3 > LO_NAME_SIZE) | ||
66 | return -EINVAL; | 75 | return -EINVAL; |
67 | 76 | ||
68 | err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key, | 77 | memmove(cms, mode, mode_len); |
69 | info->lo_encrypt_key_size); | 78 | cmsp = cms + mode_len; |
79 | *cmsp++ = '('; | ||
80 | memcpy(cmsp, info->lo_crypt_name, cipher_len); | ||
81 | cmsp += cipher_len; | ||
82 | *cmsp++ = ')'; | ||
83 | *cmsp = 0; | ||
84 | |||
85 | tfm = crypto_alloc_blkcipher(cms, 0, CRYPTO_ALG_ASYNC); | ||
86 | if (IS_ERR(tfm)) | ||
87 | return PTR_ERR(tfm); | ||
88 | |||
89 | err = crypto_blkcipher_setkey(tfm, info->lo_encrypt_key, | ||
90 | info->lo_encrypt_key_size); | ||
70 | 91 | ||
71 | if (err != 0) | 92 | if (err != 0) |
72 | goto out_free_tfm; | 93 | goto out_free_tfm; |
@@ -75,99 +96,49 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) | |||
75 | return 0; | 96 | return 0; |
76 | 97 | ||
77 | out_free_tfm: | 98 | out_free_tfm: |
78 | crypto_free_tfm(tfm); | 99 | crypto_free_blkcipher(tfm); |
79 | 100 | ||
80 | out: | 101 | out: |
81 | return err; | 102 | return err; |
82 | } | 103 | } |
83 | 104 | ||
84 | 105 | ||
85 | typedef int (*encdec_ecb_t)(struct crypto_tfm *tfm, | 106 | typedef int (*encdec_cbc_t)(struct blkcipher_desc *desc, |
86 | struct scatterlist *sg_out, | 107 | struct scatterlist *sg_out, |
87 | struct scatterlist *sg_in, | 108 | struct scatterlist *sg_in, |
88 | unsigned int nsg); | 109 | unsigned int nsg); |
89 | 110 | ||
90 | |||
91 | static int | ||
92 | cryptoloop_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 | |||
140 | typedef 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 | |||
145 | static int | 111 | static int |
146 | cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, | 112 | cryptoloop_transfer(struct loop_device *lo, int cmd, |
147 | struct page *raw_page, unsigned raw_off, | 113 | struct page *raw_page, unsigned raw_off, |
148 | struct page *loop_page, unsigned loop_off, | 114 | struct page *loop_page, unsigned loop_off, |
149 | int size, sector_t IV) | 115 | int size, sector_t IV) |
150 | { | 116 | { |
151 | struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; | 117 | struct crypto_blkcipher *tfm = lo->key_data; |
118 | struct blkcipher_desc desc = { | ||
119 | .tfm = tfm, | ||
120 | .flags = CRYPTO_TFM_REQ_MAY_SLEEP, | ||
121 | }; | ||
152 | struct scatterlist sg_out = { NULL, }; | 122 | struct scatterlist sg_out = { NULL, }; |
153 | struct scatterlist sg_in = { NULL, }; | 123 | struct scatterlist sg_in = { NULL, }; |
154 | 124 | ||
155 | encdec_cbc_t encdecfunc; | 125 | encdec_cbc_t encdecfunc; |
156 | struct page *in_page, *out_page; | 126 | struct page *in_page, *out_page; |
157 | unsigned in_offs, out_offs; | 127 | unsigned in_offs, out_offs; |
128 | int err; | ||
158 | 129 | ||
159 | if (cmd == READ) { | 130 | if (cmd == READ) { |
160 | in_page = raw_page; | 131 | in_page = raw_page; |
161 | in_offs = raw_off; | 132 | in_offs = raw_off; |
162 | out_page = loop_page; | 133 | out_page = loop_page; |
163 | out_offs = loop_off; | 134 | out_offs = loop_off; |
164 | encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv; | 135 | encdecfunc = crypto_blkcipher_crt(tfm)->decrypt; |
165 | } else { | 136 | } else { |
166 | in_page = loop_page; | 137 | in_page = loop_page; |
167 | in_offs = loop_off; | 138 | in_offs = loop_off; |
168 | out_page = raw_page; | 139 | out_page = raw_page; |
169 | out_offs = raw_off; | 140 | out_offs = raw_off; |
170 | encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv; | 141 | encdecfunc = crypto_blkcipher_crt(tfm)->encrypt; |
171 | } | 142 | } |
172 | 143 | ||
173 | while (size > 0) { | 144 | while (size > 0) { |
@@ -183,7 +154,10 @@ cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, | |||
183 | sg_out.offset = out_offs; | 154 | sg_out.offset = out_offs; |
184 | sg_out.length = sz; | 155 | sg_out.length = sz; |
185 | 156 | ||
186 | encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv); | 157 | desc.info = iv; |
158 | err = encdecfunc(&desc, &sg_out, &sg_in, sz); | ||
159 | if (err) | ||
160 | return err; | ||
187 | 161 | ||
188 | IV++; | 162 | IV++; |
189 | size -= sz; | 163 | size -= sz; |
@@ -195,32 +169,6 @@ cryptoloop_transfer_cbc(struct loop_device *lo, int cmd, | |||
195 | } | 169 | } |
196 | 170 | ||
197 | static int | 171 | static int |
198 | cryptoloop_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 | |||
223 | static int | ||
224 | cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg) | 172 | cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg) |
225 | { | 173 | { |
226 | return -EINVAL; | 174 | return -EINVAL; |
@@ -229,9 +177,9 @@ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg) | |||
229 | static int | 177 | static int |
230 | cryptoloop_release(struct loop_device *lo) | 178 | cryptoloop_release(struct loop_device *lo) |
231 | { | 179 | { |
232 | struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; | 180 | struct crypto_blkcipher *tfm = lo->key_data; |
233 | if (tfm != NULL) { | 181 | if (tfm != NULL) { |
234 | crypto_free_tfm(tfm); | 182 | crypto_free_blkcipher(tfm); |
235 | lo->key_data = NULL; | 183 | lo->key_data = NULL; |
236 | return 0; | 184 | return 0; |
237 | } | 185 | } |