Commit | Line | Data |
---|---|---|
4891f2d0 KC |
1 | /* |
2 | * COPYRIGHT (c) 2008 | |
3 | * The Regents of the University of Michigan | |
4 | * ALL RIGHTS RESERVED | |
5 | * | |
6 | * Permission is granted to use, copy, create derivative works | |
7 | * and redistribute this software and such derivative works | |
8 | * for any purpose, so long as the name of The University of | |
9 | * Michigan is not used in any advertising or publicity | |
10 | * pertaining to the use of distribution of this software | |
11 | * without specific, written prior authorization. If the | |
12 | * above copyright notice or any other identification of the | |
13 | * University of Michigan is included in any copy of any | |
14 | * portion of this software, then the disclaimer below must | |
15 | * also be included. | |
16 | * | |
17 | * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION | |
18 | * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY | |
19 | * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF | |
20 | * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING | |
21 | * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF | |
22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | |
23 | * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE | |
24 | * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR | |
25 | * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING | |
26 | * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN | |
27 | * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF | |
28 | * SUCH DAMAGES. | |
29 | */ | |
30 | ||
31 | /* | |
32 | * Copyright (C) 1998 by the FundsXpress, INC. | |
33 | * | |
34 | * All rights reserved. | |
35 | * | |
36 | * Export of this software from the United States of America may require | |
37 | * a specific license from the United States Government. It is the | |
38 | * responsibility of any person or organization contemplating export to | |
39 | * obtain such a license before exporting. | |
40 | * | |
41 | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and | |
42 | * distribute this software and its documentation for any purpose and | |
43 | * without fee is hereby granted, provided that the above copyright | |
44 | * notice appear in all copies and that both that copyright notice and | |
45 | * this permission notice appear in supporting documentation, and that | |
46 | * the name of FundsXpress. not be used in advertising or publicity pertaining | |
47 | * to distribution of the software without specific, written prior | |
48 | * permission. FundsXpress makes no representations about the suitability of | |
49 | * this software for any purpose. It is provided "as is" without express | |
50 | * or implied warranty. | |
51 | * | |
52 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
53 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
54 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
55 | */ | |
56 | ||
57 | #include <linux/err.h> | |
58 | #include <linux/types.h> | |
59 | #include <linux/crypto.h> | |
60 | #include <linux/sunrpc/gss_krb5.h> | |
61 | #include <linux/sunrpc/xdr.h> | |
62 | ||
63 | #ifdef RPC_DEBUG | |
64 | # define RPCDBG_FACILITY RPCDBG_AUTH | |
65 | #endif | |
66 | ||
67 | /* | |
68 | * This is the n-fold function as described in rfc3961, sec 5.1 | |
69 | * Taken from MIT Kerberos and modified. | |
70 | */ | |
71 | ||
72 | static void krb5_nfold(u32 inbits, const u8 *in, | |
73 | u32 outbits, u8 *out) | |
74 | { | |
75 | int a, b, c, lcm; | |
76 | int byte, i, msbit; | |
77 | ||
78 | /* the code below is more readable if I make these bytes | |
79 | instead of bits */ | |
80 | ||
81 | inbits >>= 3; | |
82 | outbits >>= 3; | |
83 | ||
84 | /* first compute lcm(n,k) */ | |
85 | ||
86 | a = outbits; | |
87 | b = inbits; | |
88 | ||
89 | while (b != 0) { | |
90 | c = b; | |
91 | b = a%b; | |
92 | a = c; | |
93 | } | |
94 | ||
95 | lcm = outbits*inbits/a; | |
96 | ||
97 | /* now do the real work */ | |
98 | ||
99 | memset(out, 0, outbits); | |
100 | byte = 0; | |
101 | ||
102 | /* this will end up cycling through k lcm(k,n)/k times, which | |
103 | is correct */ | |
104 | for (i = lcm-1; i >= 0; i--) { | |
105 | /* compute the msbit in k which gets added into this byte */ | |
106 | msbit = ( | |
107 | /* first, start with the msbit in the first, | |
108 | * unrotated byte */ | |
109 | ((inbits << 3) - 1) | |
110 | /* then, for each byte, shift to the right | |
111 | * for each repetition */ | |
112 | + (((inbits << 3) + 13) * (i/inbits)) | |
113 | /* last, pick out the correct byte within | |
114 | * that shifted repetition */ | |
115 | + ((inbits - (i % inbits)) << 3) | |
116 | ) % (inbits << 3); | |
117 | ||
118 | /* pull out the byte value itself */ | |
119 | byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)| | |
120 | (in[((inbits) - (msbit >> 3)) % inbits])) | |
121 | >> ((msbit & 7) + 1)) & 0xff; | |
122 | ||
123 | /* do the addition */ | |
124 | byte += out[i % outbits]; | |
125 | out[i % outbits] = byte & 0xff; | |
126 | ||
127 | /* keep around the carry bit, if any */ | |
128 | byte >>= 8; | |
129 | ||
130 | } | |
131 | ||
132 | /* if there's a carry bit left over, add it back in */ | |
133 | if (byte) { | |
134 | for (i = outbits - 1; i >= 0; i--) { | |
135 | /* do the addition */ | |
136 | byte += out[i]; | |
137 | out[i] = byte & 0xff; | |
138 | ||
139 | /* keep around the carry bit, if any */ | |
140 | byte >>= 8; | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | /* | |
146 | * This is the DK (derive_key) function as described in rfc3961, sec 5.1 | |
147 | * Taken from MIT Kerberos and modified. | |
148 | */ | |
149 | ||
47d84807 | 150 | u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, |
4891f2d0 KC |
151 | const struct xdr_netobj *inkey, |
152 | struct xdr_netobj *outkey, | |
1f4c86c0 TM |
153 | const struct xdr_netobj *in_constant, |
154 | gfp_t gfp_mask) | |
4891f2d0 KC |
155 | { |
156 | size_t blocksize, keybytes, keylength, n; | |
157 | unsigned char *inblockdata, *outblockdata, *rawkey; | |
158 | struct xdr_netobj inblock, outblock; | |
159 | struct crypto_blkcipher *cipher; | |
160 | u32 ret = EINVAL; | |
161 | ||
162 | blocksize = gk5e->blocksize; | |
163 | keybytes = gk5e->keybytes; | |
164 | keylength = gk5e->keylength; | |
165 | ||
166 | if ((inkey->len != keylength) || (outkey->len != keylength)) | |
167 | goto err_return; | |
168 | ||
169 | cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0, | |
170 | CRYPTO_ALG_ASYNC); | |
171 | if (IS_ERR(cipher)) | |
172 | goto err_return; | |
173 | if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len)) | |
174 | goto err_return; | |
175 | ||
176 | /* allocate and set up buffers */ | |
177 | ||
178 | ret = ENOMEM; | |
1f4c86c0 | 179 | inblockdata = kmalloc(blocksize, gfp_mask); |
4891f2d0 KC |
180 | if (inblockdata == NULL) |
181 | goto err_free_cipher; | |
182 | ||
1f4c86c0 | 183 | outblockdata = kmalloc(blocksize, gfp_mask); |
4891f2d0 KC |
184 | if (outblockdata == NULL) |
185 | goto err_free_in; | |
186 | ||
1f4c86c0 | 187 | rawkey = kmalloc(keybytes, gfp_mask); |
4891f2d0 KC |
188 | if (rawkey == NULL) |
189 | goto err_free_out; | |
190 | ||
191 | inblock.data = (char *) inblockdata; | |
192 | inblock.len = blocksize; | |
193 | ||
194 | outblock.data = (char *) outblockdata; | |
195 | outblock.len = blocksize; | |
196 | ||
197 | /* initialize the input block */ | |
198 | ||
199 | if (in_constant->len == inblock.len) { | |
200 | memcpy(inblock.data, in_constant->data, inblock.len); | |
201 | } else { | |
202 | krb5_nfold(in_constant->len * 8, in_constant->data, | |
203 | inblock.len * 8, inblock.data); | |
204 | } | |
205 | ||
206 | /* loop encrypting the blocks until enough key bytes are generated */ | |
207 | ||
208 | n = 0; | |
209 | while (n < keybytes) { | |
210 | (*(gk5e->encrypt))(cipher, NULL, inblock.data, | |
211 | outblock.data, inblock.len); | |
212 | ||
213 | if ((keybytes - n) <= outblock.len) { | |
214 | memcpy(rawkey + n, outblock.data, (keybytes - n)); | |
215 | break; | |
216 | } | |
217 | ||
218 | memcpy(rawkey + n, outblock.data, outblock.len); | |
219 | memcpy(inblock.data, outblock.data, outblock.len); | |
220 | n += outblock.len; | |
221 | } | |
222 | ||
223 | /* postprocess the key */ | |
224 | ||
225 | inblock.data = (char *) rawkey; | |
226 | inblock.len = keybytes; | |
227 | ||
228 | BUG_ON(gk5e->mk_key == NULL); | |
229 | ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey); | |
230 | if (ret) { | |
231 | dprintk("%s: got %d from mk_key function for '%s'\n", | |
232 | __func__, ret, gk5e->encrypt_name); | |
233 | goto err_free_raw; | |
234 | } | |
235 | ||
236 | /* clean memory, free resources and exit */ | |
237 | ||
238 | ret = 0; | |
239 | ||
240 | err_free_raw: | |
241 | memset(rawkey, 0, keybytes); | |
242 | kfree(rawkey); | |
243 | err_free_out: | |
244 | memset(outblockdata, 0, blocksize); | |
245 | kfree(outblockdata); | |
246 | err_free_in: | |
247 | memset(inblockdata, 0, blocksize); | |
248 | kfree(inblockdata); | |
249 | err_free_cipher: | |
250 | crypto_free_blkcipher(cipher); | |
251 | err_return: | |
252 | return ret; | |
253 | } | |
958142e9 KC |
254 | |
255 | #define smask(step) ((1<<step)-1) | |
256 | #define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) | |
257 | #define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) | |
258 | ||
259 | static void mit_des_fixup_key_parity(u8 key[8]) | |
260 | { | |
261 | int i; | |
262 | for (i = 0; i < 8; i++) { | |
263 | key[i] &= 0xfe; | |
264 | key[i] |= 1^parity_char(key[i]); | |
265 | } | |
266 | } | |
267 | ||
268 | /* | |
269 | * This is the des3 key derivation postprocess function | |
270 | */ | |
271 | u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e, | |
272 | struct xdr_netobj *randombits, | |
273 | struct xdr_netobj *key) | |
274 | { | |
275 | int i; | |
276 | u32 ret = EINVAL; | |
277 | ||
278 | if (key->len != 24) { | |
279 | dprintk("%s: key->len is %d\n", __func__, key->len); | |
280 | goto err_out; | |
281 | } | |
282 | if (randombits->len != 21) { | |
283 | dprintk("%s: randombits->len is %d\n", | |
284 | __func__, randombits->len); | |
285 | goto err_out; | |
286 | } | |
287 | ||
288 | /* take the seven bytes, move them around into the top 7 bits of the | |
289 | 8 key bytes, then compute the parity bits. Do this three times. */ | |
290 | ||
291 | for (i = 0; i < 3; i++) { | |
292 | memcpy(key->data + i*8, randombits->data + i*7, 7); | |
293 | key->data[i*8+7] = (((key->data[i*8]&1)<<1) | | |
294 | ((key->data[i*8+1]&1)<<2) | | |
295 | ((key->data[i*8+2]&1)<<3) | | |
296 | ((key->data[i*8+3]&1)<<4) | | |
297 | ((key->data[i*8+4]&1)<<5) | | |
298 | ((key->data[i*8+5]&1)<<6) | | |
299 | ((key->data[i*8+6]&1)<<7)); | |
300 | ||
301 | mit_des_fixup_key_parity(key->data + i*8); | |
302 | } | |
303 | ret = 0; | |
304 | err_out: | |
305 | return ret; | |
306 | } | |
934a95aa KC |
307 | |
308 | /* | |
309 | * This is the aes key derivation postprocess function | |
310 | */ | |
311 | u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, | |
312 | struct xdr_netobj *randombits, | |
313 | struct xdr_netobj *key) | |
314 | { | |
315 | u32 ret = EINVAL; | |
316 | ||
317 | if (key->len != 16 && key->len != 32) { | |
318 | dprintk("%s: key->len is %d\n", __func__, key->len); | |
319 | goto err_out; | |
320 | } | |
321 | if (randombits->len != 16 && randombits->len != 32) { | |
322 | dprintk("%s: randombits->len is %d\n", | |
323 | __func__, randombits->len); | |
324 | goto err_out; | |
325 | } | |
326 | if (randombits->len != key->len) { | |
327 | dprintk("%s: randombits->len is %d, key->len is %d\n", | |
328 | __func__, randombits->len, key->len); | |
329 | goto err_out; | |
330 | } | |
331 | memcpy(key->data, randombits->data, key->len); | |
332 | ret = 0; | |
333 | err_out: | |
334 | return ret; | |
335 | } | |
336 |