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*/
37krb5_error_code
38krb5_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
136cleanup:
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