1/*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*
31 * Copyright (C) 1998 by the FundsXpress, INC.
32 *
33 * All rights reserved.
34 *
35 * Export of this software from the United States of America may require
36 * a specific license from the United States Government.  It is the
37 * responsibility of any person or organization contemplating export to
38 * obtain such a license before exporting.
39 *
40 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
41 * distribute this software and its documentation for any purpose and
42 * without fee is hereby granted, provided that the above copyright
43 * notice appear in all copies and that both that copyright notice and
44 * this permission notice appear in supporting documentation, and that
45 * the name of FundsXpress. not be used in advertising or publicity pertaining
46 * to distribution of the software without specific, written prior
47 * permission.  FundsXpress makes no representations about the suitability of
48 * this software for any purpose.  It is provided "as is" without express
49 * or implied warranty.
50 *
51 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
52 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
53 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
54 */
55
56#include "nfs_gss_crypto.h"
57
58
59/*
60n-fold(k-bits):
61  l = lcm(n,k)
62  r = l/k
63  s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
64  compute the 1's complement sum:
65	n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
66*/
67
68/* representation: msb first, assume n and k are multiples of 8, and
69   that k>=16.  this is the case of all the cryptosystems which are
70   likely to be used.  this function can be replaced if that
71   assumption ever fails.  */
72
73/* input length is in bits */
74
75void
76krb5_nfold(unsigned int inbits, const unsigned char *in, unsigned int outbits,
77	   unsigned char *out)
78{
79    int a,b,c,lcm;
80    int byte, i, msbit;
81
82    /* the code below is more readable if I make these bytes
83       instead of bits */
84
85    inbits >>= 3;
86    outbits >>= 3;
87
88    /* first compute lcm(n,k) */
89
90    a = outbits;
91    b = inbits;
92
93    while(b != 0) {
94	c = b;
95	b = a%b;
96	a = c;
97    }
98
99    lcm = outbits*inbits/a;
100
101    /* now do the real work */
102
103    memset(out, 0, outbits);
104    byte = 0;
105
106    /* this will end up cycling through k lcm(k,n)/k times, which
107       is correct */
108    for (i=lcm-1; i>=0; i--) {
109	/* compute the msbit in k which gets added into this byte */
110	msbit = (/* first, start with the msbit in the first, unrotated
111		    byte */
112		 ((inbits<<3)-1)
113		 /* then, for each byte, shift to the right for each
114		    repetition */
115		 +(((inbits<<3)+13)*(i/inbits))
116		 /* last, pick out the correct byte within that
117		    shifted repetition */
118		 +((inbits-(i%inbits))<<3)
119		 )%(inbits<<3);
120
121	/* pull out the byte value itself */
122	byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
123		  (in[((inbits)-(msbit>>3))%inbits]))
124		 >>((msbit&7)+1))&0xff;
125
126	/* do the addition */
127	byte += out[i%outbits];
128	out[i%outbits] = byte&0xff;
129
130#if 0
131	printf("msbit[%d] = %d\tbyte = %02x\tsum = %03x\n", i, msbit,
132	       (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
133		 (in[((inbits)-(msbit>>3))%inbits]))
134		>>((msbit&7)+1))&0xff, byte);
135#endif
136
137	/* keep around the carry bit, if any */
138	byte >>= 8;
139
140#if 0
141	printf("carry=%d\n", byte);
142#endif
143    }
144
145    /* if there's a carry bit left over, add it back in */
146    if (byte) {
147	for (i=outbits-1; i>=0; i--) {
148	    /* do the addition */
149	    byte += out[i];
150	    out[i] = byte&0xff;
151
152	    /* keep around the carry bit, if any */
153	    byte >>= 8;
154	}
155    }
156}
157
158/*
159 * Given 21 bytes of random bits, make a triple DES key.
160 */
161
162void
163des3_make_key(const unsigned char randombits[21], des_cblock key[3])
164{
165	int i;
166
167	for (i = 0; i < 3; i++) {
168		memcpy(&key[i], &randombits[i*7], 7);
169		key[i][7] = (((key[i][0] & 1) << 1) |
170			     ((key[i][1] & 1) << 2) |
171			     ((key[i][2] & 1) << 3) |
172			     ((key[i][3] & 1) << 4) |
173			     ((key[i][4] & 1) << 5) |
174			     ((key[i][5] & 1) << 6) |
175			     ((key[i][6] & 1) << 7));
176		des_fixup_key_parity(&key[i]);
177	}
178}
179
180/*
181 * Key derivation for triple DES.
182 * Given the session key in in key, produce a new key in out key using
183 * the supplied constant.
184 */
185
186int
187des3_derive_key(des_cblock inkey[3], des_cblock outkey[3],
188		const unsigned char *constant, int clen)
189{
190	des_cblock inblock, outblock, ivec;
191	des3_cbc_key_schedule sched;
192	unsigned char rawkey[21];
193	size_t n, keybytes = sizeof(rawkey);
194
195	/* initialize the input block */
196
197	if (clen == sizeof(des_cblock)) {
198		memcpy(inblock, constant, clen);
199	} else {
200		krb5_nfold(clen*8, constant, sizeof(des_cblock)*8, inblock);
201	}
202
203	/* loop encrypting the blocks until enough key bytes are generated */
204
205	bzero(ivec, sizeof(ivec));
206	des3_cbc_key_sched(inkey, &sched);
207	for (n = 0; n < sizeof(rawkey); n += sizeof(des_cblock)) {
208		des3_cbc_encrypt(&inblock, &outblock, sizeof(outblock), &sched, &ivec, NULL, 1);
209		if ((keybytes - n) <= sizeof (des_cblock)) {
210			memcpy(rawkey+n, outblock, (keybytes - n));
211			break;
212		}
213		memcpy(rawkey+n, outblock, sizeof(des_cblock));
214		memcpy(inblock, outblock, sizeof(des_cblock));
215	}
216
217	/* postprocess the key */
218	des3_make_key(rawkey, outkey);
219
220	/* clean memory, free resources and exit */
221
222	bzero(inblock, sizeof (des_cblock));
223	bzero(outblock, sizeof (des_cblock));
224	bzero(rawkey, keybytes);
225	bzero(&sched, sizeof (sched));
226
227	return(0);
228}
229
230/*
231 * Initialize a context for HMAC SHA1
232 * if drived is true we derive a new key
233 * based on KG_USAGE_SIGN
234 */
235
236void
237HMAC_SHA1_DES3KD_Init(HMAC_SHA1_DES3KD_CTX *ctx, des_cblock key[3], int derive)
238{
239	unsigned char ipad[64];
240	size_t i, j;
241
242	SHA1Init(&ctx->sha1_ctx);
243	if (derive)
244		des3_derive_key(key, ctx->dk, KEY_USAGE_DES3_SIGN, KEY_USAGE_LEN);
245	else
246		memcpy(ctx->dk, key, 3*sizeof(des_cblock));
247	memset(ipad, 0x36, sizeof(ipad));
248	for (i = 0; i < 3; i++)
249		for (j = 0; j < sizeof(des_cblock); j++)
250			ipad[j + i * sizeof(des_cblock)] ^= ctx->dk[i][j];
251	SHA1Update(&ctx->sha1_ctx, ipad, sizeof(ipad));
252}
253
254/*
255 * Update the HMAC SHA1 context with the supplied data.
256 */
257void
258HMAC_SHA1_DES3KD_Update(HMAC_SHA1_DES3KD_CTX *ctx, void *data, size_t len)
259{
260	SHA1Update(&ctx->sha1_ctx, data, len);
261}
262
263/*
264 * Finish the context and produce the HMAC SHA1 digest.
265 */
266
267void
268HMAC_SHA1_DES3KD_Final(void *digest, HMAC_SHA1_DES3KD_CTX *ctx)
269{
270	unsigned char opad[64];
271	size_t i, j;
272
273	SHA1Final(digest, &ctx->sha1_ctx);
274	memset(opad, 0x5c, sizeof(opad));
275	for (i = 0; i < 3; i++)
276		for (j = 0; j < sizeof(des_cblock); j++)
277			opad[j + i * sizeof(des_cblock)] ^= ctx->dk[i][j];
278	SHA1Init(&ctx->sha1_ctx);
279	SHA1Update(&ctx->sha1_ctx, opad, sizeof(opad));
280	SHA1Update(&ctx->sha1_ctx, digest, SHA1_RESULTLEN);
281	SHA1Final(digest, &ctx->sha1_ctx);
282}
283
284/*
285 * Initialize an MD5 DES CBC context with a schedule.
286 */
287
288void MD5_DESCBC_Init(MD5_DESCBC_CTX *ctx, des_cbc_key_schedule *sched)
289{
290	MD5Init(&ctx->md5_ctx);
291	ctx->sched = sched;
292}
293
294/*
295 * Update MD5 DES CBC context with the supplied data.
296 */
297
298void MD5_DESCBC_Update(MD5_DESCBC_CTX *ctx, void *data, size_t len)
299{
300	MD5Update(&ctx->md5_ctx, data, len);
301}
302
303/*
304 * Finalize the context and extract the digest.
305 */
306
307void MD5_DESCBC_Final(void *digest, MD5_DESCBC_CTX *ctx)
308{
309	unsigned char md5_digest[MD5_DIGEST_LENGTH];
310
311	MD5Final(md5_digest, &ctx->md5_ctx);
312
313	/*
314	 * Now get the DES CBC checksum for the digest.
315	 */
316	des_cbc_cksum((des_cblock *) md5_digest, (des_cblock *)digest,
317				sizeof (md5_digest), ctx->sched);
318}
319
320