2 * linux/net/sunrpc/gss_krb5_crypto.c
4 * Copyright (c) 2000 The Regents of the University of Michigan.
7 * Andy Adamson <andros@umich.edu>
8 * Bruce Fields <bfields@umich.edu>
12 * Copyright (C) 1998 by the FundsXpress, INC.
14 * All rights reserved.
16 * Export of this software from the United States of America may require
17 * a specific license from the United States Government. It is the
18 * responsibility of any person or organization contemplating export to
19 * obtain such a license before exporting.
21 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
22 * distribute this software and its documentation for any purpose and
23 * without fee is hereby granted, provided that the above copyright
24 * notice appear in all copies and that both that copyright notice and
25 * this permission notice appear in supporting documentation, and that
26 * the name of FundsXpress. not be used in advertising or publicity pertaining
27 * to distribution of the software without specific, written prior
28 * permission. FundsXpress makes no representations about the suitability of
29 * this software for any purpose. It is provided "as is" without express
30 * or implied warranty.
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
34 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
37 #include <linux/err.h>
38 #include <linux/types.h>
40 #include <linux/slab.h>
41 #include <linux/scatterlist.h>
42 #include <linux/crypto.h>
43 #include <linux/highmem.h>
44 #include <linux/pagemap.h>
45 #include <linux/sunrpc/gss_krb5.h>
48 # define RPCDBG_FACILITY RPCDBG_AUTH
53 struct crypto_blkcipher
*tfm
,
60 struct scatterlist sg
[1];
61 u8 local_iv
[16] = {0};
62 struct blkcipher_desc desc
= { .tfm
= tfm
, .info
= local_iv
};
64 dprintk("RPC: krb5_encrypt: input data:\n");
65 print_hexl((u32
*)in
, length
, 0);
67 if (length
% crypto_blkcipher_blocksize(tfm
) != 0)
70 if (crypto_blkcipher_ivsize(tfm
) > 16) {
71 dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
72 crypto_blkcipher_ivsize(tfm
));
77 memcpy(local_iv
, iv
, crypto_blkcipher_ivsize(tfm
));
79 memcpy(out
, in
, length
);
80 sg_set_buf(sg
, out
, length
);
82 ret
= crypto_blkcipher_encrypt_iv(&desc
, sg
, sg
, length
);
84 dprintk("RPC: krb5_encrypt: output data:\n");
85 print_hexl((u32
*)out
, length
, 0);
87 dprintk("RPC: krb5_encrypt returns %d\n",ret
);
91 EXPORT_SYMBOL(krb5_encrypt
);
95 struct crypto_blkcipher
*tfm
,
102 struct scatterlist sg
[1];
103 u8 local_iv
[16] = {0};
104 struct blkcipher_desc desc
= { .tfm
= tfm
, .info
= local_iv
};
106 dprintk("RPC: krb5_decrypt: input data:\n");
107 print_hexl((u32
*)in
, length
, 0);
109 if (length
% crypto_blkcipher_blocksize(tfm
) != 0)
112 if (crypto_blkcipher_ivsize(tfm
) > 16) {
113 dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
114 crypto_blkcipher_ivsize(tfm
));
118 memcpy(local_iv
,iv
, crypto_blkcipher_ivsize(tfm
));
120 memcpy(out
, in
, length
);
121 sg_set_buf(sg
, out
, length
);
123 ret
= crypto_blkcipher_decrypt_iv(&desc
, sg
, sg
, length
);
125 dprintk("RPC: krb5_decrypt: output_data:\n");
126 print_hexl((u32
*)out
, length
, 0);
128 dprintk("RPC: gss_k5decrypt returns %d\n",ret
);
132 EXPORT_SYMBOL(krb5_decrypt
);
135 process_xdr_buf(struct xdr_buf
*buf
, int offset
, int len
,
136 int (*actor
)(struct scatterlist
*, void *), void *data
)
138 int i
, page_len
, thislen
, page_offset
, ret
= 0;
139 struct scatterlist sg
[1];
141 if (offset
>= buf
->head
[0].iov_len
) {
142 offset
-= buf
->head
[0].iov_len
;
144 thislen
= buf
->head
[0].iov_len
- offset
;
147 sg_set_buf(sg
, buf
->head
[0].iov_base
+ offset
, thislen
);
148 ret
= actor(sg
, data
);
157 if (offset
>= buf
->page_len
) {
158 offset
-= buf
->page_len
;
160 page_len
= buf
->page_len
- offset
;
164 page_offset
= (offset
+ buf
->page_base
) & (PAGE_CACHE_SIZE
- 1);
165 i
= (offset
+ buf
->page_base
) >> PAGE_CACHE_SHIFT
;
166 thislen
= PAGE_CACHE_SIZE
- page_offset
;
168 if (thislen
> page_len
)
170 sg
->page
= buf
->pages
[i
];
171 sg
->offset
= page_offset
;
172 sg
->length
= thislen
;
173 ret
= actor(sg
, data
);
179 thislen
= PAGE_CACHE_SIZE
;
180 } while (page_len
!= 0);
186 if (offset
< buf
->tail
[0].iov_len
) {
187 thislen
= buf
->tail
[0].iov_len
- offset
;
190 sg_set_buf(sg
, buf
->tail
[0].iov_base
+ offset
, thislen
);
191 ret
= actor(sg
, data
);
201 checksummer(struct scatterlist
*sg
, void *data
)
203 struct hash_desc
*desc
= data
;
205 return crypto_hash_update(desc
, sg
, sg
->length
);
208 /* checksum the plaintext data and hdrlen bytes of the token header */
210 make_checksum(s32 cksumtype
, char *header
, int hdrlen
, struct xdr_buf
*body
,
211 int body_offset
, struct xdr_netobj
*cksum
)
214 struct hash_desc desc
; /* XXX add to ctx? */
215 struct scatterlist sg
[1];
219 case CKSUMTYPE_RSA_MD5
:
223 dprintk("RPC: krb5_make_checksum:"
224 " unsupported checksum %d", cksumtype
);
225 return GSS_S_FAILURE
;
227 desc
.tfm
= crypto_alloc_hash(cksumname
, 0, CRYPTO_ALG_ASYNC
);
228 if (IS_ERR(desc
.tfm
))
229 return GSS_S_FAILURE
;
230 cksum
->len
= crypto_hash_digestsize(desc
.tfm
);
231 desc
.flags
= CRYPTO_TFM_REQ_MAY_SLEEP
;
233 err
= crypto_hash_init(&desc
);
236 sg_set_buf(sg
, header
, hdrlen
);
237 err
= crypto_hash_update(&desc
, sg
, hdrlen
);
240 err
= process_xdr_buf(body
, body_offset
, body
->len
- body_offset
,
244 err
= crypto_hash_final(&desc
, cksum
->data
);
247 crypto_free_hash(desc
.tfm
);
248 return err
? GSS_S_FAILURE
: 0;
251 EXPORT_SYMBOL(make_checksum
);
253 struct encryptor_desc
{
254 u8 iv
[8]; /* XXX hard-coded blocksize */
255 struct blkcipher_desc desc
;
257 struct xdr_buf
*outbuf
;
259 struct scatterlist infrags
[4];
260 struct scatterlist outfrags
[4];
266 encryptor(struct scatterlist
*sg
, void *data
)
268 struct encryptor_desc
*desc
= data
;
269 struct xdr_buf
*outbuf
= desc
->outbuf
;
270 struct page
*in_page
;
271 int thislen
= desc
->fraglen
+ sg
->length
;
275 /* Worst case is 4 fragments: head, end of page 1, start
276 * of page 2, tail. Anything more is a bug. */
277 BUG_ON(desc
->fragno
> 3);
278 desc
->infrags
[desc
->fragno
] = *sg
;
279 desc
->outfrags
[desc
->fragno
] = *sg
;
281 page_pos
= desc
->pos
- outbuf
->head
[0].iov_len
;
282 if (page_pos
>= 0 && page_pos
< outbuf
->page_len
) {
283 /* pages are not in place: */
284 int i
= (page_pos
+ outbuf
->page_base
) >> PAGE_CACHE_SHIFT
;
285 in_page
= desc
->pages
[i
];
289 desc
->infrags
[desc
->fragno
].page
= in_page
;
291 desc
->fraglen
+= sg
->length
;
292 desc
->pos
+= sg
->length
;
294 fraglen
= thislen
& 7; /* XXX hardcoded blocksize */
300 ret
= crypto_blkcipher_encrypt_iv(&desc
->desc
, desc
->outfrags
,
301 desc
->infrags
, thislen
);
305 desc
->outfrags
[0].page
= sg
->page
;
306 desc
->outfrags
[0].offset
= sg
->offset
+ sg
->length
- fraglen
;
307 desc
->outfrags
[0].length
= fraglen
;
308 desc
->infrags
[0] = desc
->outfrags
[0];
309 desc
->infrags
[0].page
= in_page
;
311 desc
->fraglen
= fraglen
;
320 gss_encrypt_xdr_buf(struct crypto_blkcipher
*tfm
, struct xdr_buf
*buf
,
321 int offset
, struct page
**pages
)
324 struct encryptor_desc desc
;
326 BUG_ON((buf
->len
- offset
) % crypto_blkcipher_blocksize(tfm
) != 0);
328 memset(desc
.iv
, 0, sizeof(desc
.iv
));
330 desc
.desc
.info
= desc
.iv
;
338 ret
= process_xdr_buf(buf
, offset
, buf
->len
- offset
, encryptor
, &desc
);
342 EXPORT_SYMBOL(gss_encrypt_xdr_buf
);
344 struct decryptor_desc
{
345 u8 iv
[8]; /* XXX hard-coded blocksize */
346 struct blkcipher_desc desc
;
347 struct scatterlist frags
[4];
353 decryptor(struct scatterlist
*sg
, void *data
)
355 struct decryptor_desc
*desc
= data
;
356 int thislen
= desc
->fraglen
+ sg
->length
;
359 /* Worst case is 4 fragments: head, end of page 1, start
360 * of page 2, tail. Anything more is a bug. */
361 BUG_ON(desc
->fragno
> 3);
362 desc
->frags
[desc
->fragno
] = *sg
;
364 desc
->fraglen
+= sg
->length
;
366 fraglen
= thislen
& 7; /* XXX hardcoded blocksize */
372 ret
= crypto_blkcipher_decrypt_iv(&desc
->desc
, desc
->frags
,
373 desc
->frags
, thislen
);
377 desc
->frags
[0].page
= sg
->page
;
378 desc
->frags
[0].offset
= sg
->offset
+ sg
->length
- fraglen
;
379 desc
->frags
[0].length
= fraglen
;
381 desc
->fraglen
= fraglen
;
390 gss_decrypt_xdr_buf(struct crypto_blkcipher
*tfm
, struct xdr_buf
*buf
,
393 struct decryptor_desc desc
;
396 BUG_ON((buf
->len
- offset
) % crypto_blkcipher_blocksize(tfm
) != 0);
398 memset(desc
.iv
, 0, sizeof(desc
.iv
));
400 desc
.desc
.info
= desc
.iv
;
404 return process_xdr_buf(buf
, offset
, buf
->len
- offset
, decryptor
, &desc
);
407 EXPORT_SYMBOL(gss_decrypt_xdr_buf
);