| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  linux/net/sunrpc/gss_krb5_crypto.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (c) 2000 The Regents of the University of Michigan. | 
					
						
							|  |  |  |  *  All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Andy Adamson   <andros@umich.edu> | 
					
						
							|  |  |  |  *  Bruce Fields   <bfields@umich.edu> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 1998 by the FundsXpress, INC. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Export of this software from the United States of America may require | 
					
						
							|  |  |  |  * a specific license from the United States Government.  It is the | 
					
						
							|  |  |  |  * responsibility of any person or organization contemplating export to | 
					
						
							|  |  |  |  * obtain such a license before exporting. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and | 
					
						
							|  |  |  |  * distribute this software and its documentation for any purpose and | 
					
						
							|  |  |  |  * without fee is hereby granted, provided that the above copyright | 
					
						
							|  |  |  |  * notice appear in all copies and that both that copyright notice and | 
					
						
							|  |  |  |  * this permission notice appear in supporting documentation, and that | 
					
						
							|  |  |  |  * the name of FundsXpress. not be used in advertising or publicity pertaining | 
					
						
							|  |  |  |  * to distribution of the software without specific, written prior | 
					
						
							|  |  |  |  * permission.  FundsXpress makes no representations about the suitability of | 
					
						
							|  |  |  |  * this software for any purpose.  It is provided "as is" without express | 
					
						
							|  |  |  |  * or implied warranty. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | 
					
						
							|  |  |  |  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | #include <linux/err.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  | #include <linux/mm.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2005-09-17 17:55:31 +10:00
										 |  |  | #include <linux/scatterlist.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/crypto.h>
 | 
					
						
							|  |  |  | #include <linux/highmem.h>
 | 
					
						
							|  |  |  | #include <linux/pagemap.h>
 | 
					
						
							|  |  |  | #include <linux/sunrpc/gss_krb5.h>
 | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:33 -05:00
										 |  |  | #include <linux/sunrpc/xdr.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef RPC_DEBUG
 | 
					
						
							|  |  |  | # define RPCDBG_FACILITY        RPCDBG_AUTH
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 | 
					
						
							|  |  |  | krb5_encrypt( | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	struct crypto_blkcipher *tfm, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	void * iv, | 
					
						
							|  |  |  | 	void * in, | 
					
						
							|  |  |  | 	void * out, | 
					
						
							|  |  |  | 	int length) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 ret = -EINVAL; | 
					
						
							| 
									
										
										
										
											2007-02-09 15:38:13 -08:00
										 |  |  | 	struct scatterlist sg[1]; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	u8 local_iv[16] = {0}; | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	if (length % crypto_blkcipher_blocksize(tfm) != 0) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	if (crypto_blkcipher_ivsize(tfm) > 16) { | 
					
						
							| 
									
										
										
										
											2008-02-21 13:44:12 -05:00
										 |  |  | 		dprintk("RPC:       gss_k5encrypt: tfm iv size too large %d\n", | 
					
						
							|  |  |  | 			crypto_blkcipher_ivsize(tfm)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (iv) | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 		memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(out, in, length); | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 	sg_init_one(sg, out, length); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, length); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2007-01-31 12:14:05 -05:00
										 |  |  | 	dprintk("RPC:       krb5_encrypt returns %d\n", ret); | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:31 -05:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u32 | 
					
						
							|  |  |  | krb5_decrypt( | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  |      struct crypto_blkcipher *tfm, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |      void * iv, | 
					
						
							|  |  |  |      void * in, | 
					
						
							|  |  |  |      void * out, | 
					
						
							|  |  |  |      int length) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 ret = -EINVAL; | 
					
						
							|  |  |  | 	struct scatterlist sg[1]; | 
					
						
							|  |  |  | 	u8 local_iv[16] = {0}; | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	if (length % crypto_blkcipher_blocksize(tfm) != 0) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	if (crypto_blkcipher_ivsize(tfm) > 16) { | 
					
						
							| 
									
										
										
										
											2008-02-21 13:44:12 -05:00
										 |  |  | 		dprintk("RPC:       gss_k5decrypt: tfm iv size too large %d\n", | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 			crypto_blkcipher_ivsize(tfm)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (iv) | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 		memcpy(local_iv,iv, crypto_blkcipher_ivsize(tfm)); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(out, in, length); | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 	sg_init_one(sg, out, length); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, length); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2007-01-31 12:14:05 -05:00
										 |  |  | 	dprintk("RPC:       gss_k5decrypt returns %d\n",ret); | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:31 -05:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:03 -04:00
										 |  |  | static int | 
					
						
							|  |  |  | checksummer(struct scatterlist *sg, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	struct hash_desc *desc = data; | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:03 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	return crypto_hash_update(desc, sg, sg->length); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:03 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /* checksum the plaintext data and hdrlen bytes of the token header */ | 
					
						
							|  |  |  | s32 | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:38 -05:00
										 |  |  | make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body, | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 		   int body_offset, struct xdr_netobj *cksum) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	struct hash_desc                desc; /* XXX add to ctx? */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	struct scatterlist              sg[1]; | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); | 
					
						
							|  |  |  | 	if (IS_ERR(desc.tfm)) | 
					
						
							| 
									
										
										
										
											2006-04-18 13:14:02 -04:00
										 |  |  | 		return GSS_S_FAILURE; | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	cksum->len = crypto_hash_digestsize(desc.tfm); | 
					
						
							|  |  |  | 	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	err = crypto_hash_init(&desc); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 	sg_init_one(sg, header, hdrlen); | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 	err = crypto_hash_update(&desc, sg, hdrlen); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:33 -05:00
										 |  |  | 	err = xdr_process_buf(body, body_offset, body->len - body_offset, | 
					
						
							| 
									
										
										
										
											2006-08-24 19:10:20 +10:00
										 |  |  | 			      checksummer, &desc); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	err = crypto_hash_final(&desc, cksum->data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	crypto_free_hash(desc.tfm); | 
					
						
							|  |  |  | 	return err ? GSS_S_FAILURE : 0; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | struct encryptor_desc { | 
					
						
							|  |  |  | 	u8 iv[8]; /* XXX hard-coded blocksize */ | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	struct blkcipher_desc desc; | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	int pos; | 
					
						
							|  |  |  | 	struct xdr_buf *outbuf; | 
					
						
							|  |  |  | 	struct page **pages; | 
					
						
							|  |  |  | 	struct scatterlist infrags[4]; | 
					
						
							|  |  |  | 	struct scatterlist outfrags[4]; | 
					
						
							|  |  |  | 	int fragno; | 
					
						
							|  |  |  | 	int fraglen; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | encryptor(struct scatterlist *sg, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct encryptor_desc *desc = data; | 
					
						
							|  |  |  | 	struct xdr_buf *outbuf = desc->outbuf; | 
					
						
							|  |  |  | 	struct page *in_page; | 
					
						
							|  |  |  | 	int thislen = desc->fraglen + sg->length; | 
					
						
							|  |  |  | 	int fraglen, ret; | 
					
						
							|  |  |  | 	int page_pos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Worst case is 4 fragments: head, end of page 1, start
 | 
					
						
							|  |  |  | 	 * of page 2, tail.  Anything more is a bug. */ | 
					
						
							|  |  |  | 	BUG_ON(desc->fragno > 3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	page_pos = desc->pos - outbuf->head[0].iov_len; | 
					
						
							|  |  |  | 	if (page_pos >= 0 && page_pos < outbuf->page_len) { | 
					
						
							|  |  |  | 		/* pages are not in place: */ | 
					
						
							|  |  |  | 		int i = (page_pos + outbuf->page_base) >> PAGE_CACHE_SHIFT; | 
					
						
							|  |  |  | 		in_page = desc->pages[i]; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-10-22 19:44:26 +02:00
										 |  |  | 		in_page = sg_page(sg); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 	sg_set_page(&desc->infrags[desc->fragno], in_page, sg->length, | 
					
						
							|  |  |  | 		    sg->offset); | 
					
						
							|  |  |  | 	sg_set_page(&desc->outfrags[desc->fragno], sg_page(sg), sg->length, | 
					
						
							|  |  |  | 		    sg->offset); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	desc->fragno++; | 
					
						
							|  |  |  | 	desc->fraglen += sg->length; | 
					
						
							|  |  |  | 	desc->pos += sg->length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fraglen = thislen & 7; /* XXX hardcoded blocksize */ | 
					
						
							|  |  |  | 	thislen -= fraglen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (thislen == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-31 12:06:37 +01:00
										 |  |  | 	sg_mark_end(&desc->infrags[desc->fragno - 1]); | 
					
						
							|  |  |  | 	sg_mark_end(&desc->outfrags[desc->fragno - 1]); | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	ret = crypto_blkcipher_encrypt_iv(&desc->desc, desc->outfrags, | 
					
						
							|  |  |  | 					  desc->infrags, thislen); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sg_init_table(desc->infrags, 4); | 
					
						
							|  |  |  | 	sg_init_table(desc->outfrags, 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	if (fraglen) { | 
					
						
							| 
									
										
										
										
											2007-10-24 11:20:47 +02:00
										 |  |  | 		sg_set_page(&desc->outfrags[0], sg_page(sg), fraglen, | 
					
						
							|  |  |  | 				sg->offset + sg->length - fraglen); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 		desc->infrags[0] = desc->outfrags[0]; | 
					
						
							| 
									
										
										
										
											2007-10-24 11:20:47 +02:00
										 |  |  | 		sg_assign_page(&desc->infrags[0], in_page); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 		desc->fragno = 1; | 
					
						
							|  |  |  | 		desc->fraglen = fraglen; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		desc->fragno = 0; | 
					
						
							|  |  |  | 		desc->fraglen = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, | 
					
						
							|  |  |  | 		    int offset, struct page **pages) | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	struct encryptor_desc desc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	BUG_ON((buf->len - offset) % crypto_blkcipher_blocksize(tfm) != 0); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memset(desc.iv, 0, sizeof(desc.iv)); | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	desc.desc.tfm = tfm; | 
					
						
							|  |  |  | 	desc.desc.info = desc.iv; | 
					
						
							|  |  |  | 	desc.desc.flags = 0; | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	desc.pos = offset; | 
					
						
							|  |  |  | 	desc.outbuf = buf; | 
					
						
							|  |  |  | 	desc.pages = pages; | 
					
						
							|  |  |  | 	desc.fragno = 0; | 
					
						
							|  |  |  | 	desc.fraglen = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 	sg_init_table(desc.infrags, 4); | 
					
						
							|  |  |  | 	sg_init_table(desc.outfrags, 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:33 -05:00
										 |  |  | 	ret = xdr_process_buf(buf, offset, buf->len - offset, encryptor, &desc); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct decryptor_desc { | 
					
						
							|  |  |  | 	u8 iv[8]; /* XXX hard-coded blocksize */ | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	struct blkcipher_desc desc; | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	struct scatterlist frags[4]; | 
					
						
							|  |  |  | 	int fragno; | 
					
						
							|  |  |  | 	int fraglen; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | decryptor(struct scatterlist *sg, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct decryptor_desc *desc = data; | 
					
						
							|  |  |  | 	int thislen = desc->fraglen + sg->length; | 
					
						
							|  |  |  | 	int fraglen, ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Worst case is 4 fragments: head, end of page 1, start
 | 
					
						
							|  |  |  | 	 * of page 2, tail.  Anything more is a bug. */ | 
					
						
							|  |  |  | 	BUG_ON(desc->fragno > 3); | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 	sg_set_page(&desc->frags[desc->fragno], sg_page(sg), sg->length, | 
					
						
							|  |  |  | 		    sg->offset); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	desc->fragno++; | 
					
						
							|  |  |  | 	desc->fraglen += sg->length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fraglen = thislen & 7; /* XXX hardcoded blocksize */ | 
					
						
							|  |  |  | 	thislen -= fraglen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (thislen == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-31 12:06:37 +01:00
										 |  |  | 	sg_mark_end(&desc->frags[desc->fragno - 1]); | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	ret = crypto_blkcipher_decrypt_iv(&desc->desc, desc->frags, | 
					
						
							|  |  |  | 					  desc->frags, thislen); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sg_init_table(desc->frags, 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	if (fraglen) { | 
					
						
							| 
									
										
										
										
											2007-10-24 11:20:47 +02:00
										 |  |  | 		sg_set_page(&desc->frags[0], sg_page(sg), fraglen, | 
					
						
							|  |  |  | 				sg->offset + sg->length - fraglen); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 		desc->fragno = 1; | 
					
						
							|  |  |  | 		desc->fraglen = fraglen; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		desc->fragno = 0; | 
					
						
							|  |  |  | 		desc->fraglen = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, | 
					
						
							|  |  |  | 		    int offset) | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct decryptor_desc desc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* XXXJBF: */ | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	BUG_ON((buf->len - offset) % crypto_blkcipher_blocksize(tfm) != 0); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memset(desc.iv, 0, sizeof(desc.iv)); | 
					
						
							| 
									
										
										
										
											2006-08-22 20:33:54 +10:00
										 |  |  | 	desc.desc.tfm = tfm; | 
					
						
							|  |  |  | 	desc.desc.info = desc.iv; | 
					
						
							|  |  |  | 	desc.desc.flags = 0; | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | 	desc.fragno = 0; | 
					
						
							|  |  |  | 	desc.fraglen = 0; | 
					
						
							| 
									
										
										
										
											2007-10-27 00:52:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sg_init_table(desc.frags, 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-04 20:22:33 -05:00
										 |  |  | 	return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc); | 
					
						
							| 
									
										
										
										
											2005-10-13 16:55:13 -04:00
										 |  |  | } |