1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * Copyright (C) 1998 by the FundsXpress, INC.
9  *
10  * All rights reserved.
11  *
12  * Export of this software from the United States of America may require
13  * a specific license from the United States Government.  It is the
14  * responsibility of any person or organization contemplating export to
15  * obtain such a license before exporting.
16  *
17  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18  * distribute this software and its documentation for any purpose and
19  * without fee is hereby granted, provided that the above copyright
20  * notice appear in all copies and that both that copyright notice and
21  * this permission notice appear in supporting documentation, and that
22  * the name of FundsXpress. not be used in advertising or publicity pertaining
23  * to distribution of the software without specific, written prior
24  * permission.  FundsXpress makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is" without express
26  * or implied warranty.
27  *
28  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31  */
32 
33 #include "k5-int.h"
34 #include "old.h"
35 
36 /*ARGSUSED*/
37 krb5_error_code
krb5_old_decrypt(krb5_context context,const struct krb5_enc_provider * enc,const struct krb5_hash_provider * hash,const krb5_keyblock * key,krb5_keyusage usage,const krb5_data * ivec,const krb5_data * input,krb5_data * arg_output)38 krb5_old_decrypt(krb5_context context,
39 		 const struct krb5_enc_provider *enc,
40 		 const struct krb5_hash_provider *hash,
41 		 const krb5_keyblock *key,
42 		 krb5_keyusage usage,
43 		 const krb5_data *ivec,
44 		 const krb5_data *input,
45 		 krb5_data *arg_output)
46 {
47     krb5_error_code ret;
48     size_t blocksize, hashsize, plainsize;
49     unsigned char *cn;
50     krb5_data output, cksum, crcivec;
51     int alloced;
52     unsigned char orig_cksum[128], new_cksum[128];
53 
54     blocksize = enc->block_size;
55     hashsize = hash->hashsize;
56 
57     /* Verify input and output lengths. */
58     if (input->length < blocksize + hashsize || input->length % blocksize != 0)
59         return(KRB5_BAD_MSIZE);
60     plainsize = input->length - blocksize - hashsize;
61     if (arg_output->length < plainsize)
62 	return(KRB5_BAD_MSIZE);
63 
64     if (arg_output->length < input->length) {
65 	output.length = input->length;
66 
67 	if ((output.data = (char *) MALLOC(output.length)) == NULL) {
68 	    return(ENOMEM);
69 	}
70 
71 	alloced = 1;
72     } else {
73 	output.length = input->length;
74 
75 	output.data = arg_output->data;
76 
77 	alloced = 0;
78     }
79 
80     /* decrypt it */
81 
82     /* save last ciphertext block in case we decrypt in place */
83     if (ivec != NULL && ivec->length == blocksize) {
84 	cn = MALLOC(blocksize);
85 	if (cn == NULL) {
86 	    ret = ENOMEM;
87 	    goto cleanup;
88 	}
89 	(void) memcpy(cn, input->data + input->length - blocksize, blocksize);
90     } else
91 	cn = NULL;
92 
93     /* XXX this is gross, but I don't have much choice */
94     if ((key->enctype == ENCTYPE_DES_CBC_CRC) && (ivec == 0)) {
95 	crcivec.length = key->length;
96 	crcivec.data = (char *) key->contents;
97 	ivec = &crcivec;
98     }
99 
100     if ((ret = ((*(enc->decrypt))(context, key, ivec, input, &output))))
101 	goto cleanup;
102 
103     /* verify the checksum */
104 
105     (void) memcpy(orig_cksum, output.data+blocksize, hashsize);
106     (void) memset(output.data+blocksize, 0, hashsize);
107 
108     cksum.length = hashsize;
109     cksum.data = (char *)new_cksum;
110 
111     if ((ret = ((*(hash->hash))(context, 1, &output, &cksum))))
112 	goto cleanup;
113 
114     if (memcmp(cksum.data, orig_cksum, cksum.length) != 0) {
115 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
116 	goto cleanup;
117     }
118 
119     /* copy the plaintext around */
120 
121     if (alloced) {
122 	(void) memcpy(arg_output->data, output.data+blocksize+hashsize,
123 	       plainsize);
124     } else {
125 	(void) memmove(arg_output->data, arg_output->data+blocksize+hashsize,
126 		plainsize);
127     }
128     arg_output->length = plainsize;
129 
130     /* update ivec */
131     if (cn != NULL)
132 	(void) memcpy(ivec->data, cn, blocksize);
133 
134     ret = 0;
135 
136 cleanup:
137     if (alloced) {
138 	(void) memset(output.data, 0, output.length);
139 	FREE(output.data, output.length);
140     }
141 
142     if (cn != NULL)
143 	FREE(cn, blocksize);
144     (void) memset(new_cksum, 0, hashsize);
145 
146     return(ret);
147 }
148