*** empty log message ***
[arla.git] / rxgk / rxgk_hcrypto.c
blobf00775cceb469de3477f26dcdbe9e9893c4df4b9
1 /*
2 * Copyright (c) 2002 - 2004, Stockholms universitet
3 * (Stockholm University, Stockholm Sweden)
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the university nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
35 * Portable implementation of rxgk wire encryption
38 #include "rxgk_locl.h"
39 #include <errno.h>
41 RCSID("$Id$");
43 struct _rxg_key_type {
44 char *name;
45 int enctype;
46 int blocklen;
47 int checksumlen;
48 int confounderlen;
51 static struct _rxg_key_type ktypes[] = {
52 { "des-cbc-crc", RXGK_CRYPTO_DES_CBC_CRC,
53 8, 4, 8,
55 { "des-cbc-md5", RXGK_CRYPTO_DES_CBC_MD5,
56 8, 24, 8,
60 static struct _rxg_key_type *
61 _rxg_find_enctype(int enctype)
63 struct _rxg_key_type *key;
65 for (key = ktypes; key->name != NULL; key++)
66 if (key->enctype == enctype)
67 return key;
68 return NULL;
71 int
72 rxgk_set_conn(struct rx_connection *con, int enctype, int enc)
74 struct _rxg_key_type *key;
76 key = _rxg_find_enctype(enctype);
77 if (key == NULL)
78 return ENOENT;
80 if (enc) {
81 rx_SetSecurityHeaderSize(con, key->checksumlen + key->confounderlen +
82 RXGK_HEADER_DATA_SIZE);
84 rx_SetSecurityMaxTrailerSize(con, key->blocklen);
85 } else {
86 rx_SetSecurityHeaderSize(con,
87 key->checksumlen + RXGK_HEADER_DATA_SIZE);
88 rx_SetSecurityMaxTrailerSize(con, 0);
90 return 0;
94 * portability macros
96 #ifdef MIT_KRB5
97 #define CIPHERTYPE krb5_enc_data
98 #define CKSUMTYPE krb5_checksum
99 #define CIPHTEXT cipher->ciphertext
100 #define CIPHTEXTLEN cipher->ciphertext.length
101 #define CIPHTEXTDAT cipher->ciphertext.data
102 #define CKSUMDAT cksum->contents
103 #define CKSUMLEN cksum->length
104 #elif defined(SHISHI_KRB5)
105 #define CIPHERTYPE krb5_data
106 #define CKSUMTYPE krb5_data
107 #define CIPHTEXT cipher
108 #define CIPHTEXTLEN cipher->length
109 #define CIPHTEXTDAT cipher->data
110 #define CKSUMDAT cksum->data
111 #define CKSUMLEN cksum->length
112 #else
113 #define CIPHERTYPE krb5_data
114 #define CKSUMTYPE krb5_checksum
115 #define CIPHTEXT cipher
116 #define CIPHTEXTLEN cipher->length
117 #define CIPHTEXTDAT cipher->data
118 #define CKSUMDAT cksum->checksum.data
119 #define CKSUMLEN cksum->checksum.length
120 #endif
122 #ifdef OPENAFS
123 #define ALLOCFUNC(x) osi_Alloc(x)
124 #define FREEFUNC(x,y) osi_Free(x,y)
125 #else
126 #define ALLOCFUNC(x) malloc(x)
127 #define FREEFUNC(x,y) free(x)
128 #endif
130 #define GETCONTEXT rxgk_krb5_context
133 rxgk_crypto_init(struct rxgk_keyblock *tk, key_stuff *k)
135 int ret;
137 krb5_keyblock tk_kb;
139 ret = krb5_keyblock_init(GETCONTEXT, tk->enctype,
140 tk->data, tk->length,
141 &tk_kb);
143 if (ret)
144 return EINVAL;
146 ret = krb5_crypto_init (GETCONTEXT, &tk_kb,
147 tk->enctype,
148 &k->ks_scrypto);
150 krb5_free_keyblock_contents(GETCONTEXT, &tk_kb);
152 if (ret)
153 return EINVAL;
155 return 0;
159 rxgk_prepare_packet(struct rx_packet *p, struct rx_connection *conn,
160 int level, key_stuff *k, end_stuff *e,
161 int keyusage_enc, int keyusage_mic)
163 int len = rx_GetDataSize(p);
164 int off = rx_GetSecurityHeaderSize(conn);
165 #if 0
166 int padding = rx_GetSecurityMaxTrailerSize(conn);
167 #endif
169 krb5_data plain[1];
170 CIPHERTYPE cipher[1];
171 CKSUMTYPE cksum[1];
172 krb5_data scratch[1];
173 krb5_keyblock key[1];
175 krb5_data computed[1]; /* shishi tmp */
176 #if defined(MIT_KRB5)
177 size_t enclen; /* mit tmp */
178 #endif
180 #if defined(MIT_KRB5)
181 krb5_boolean valid;
182 #endif
183 int cktype = 1; /* CKSUMTYPE_CRC32 XXX */
185 int cs, code;
186 char *cp;
188 if (level == RXGK_M_INTEGRITY) {
189 memset((void*) scratch, 0, sizeof *scratch);
190 memset((void*) cksum, 0, sizeof *cksum);
191 memset((void*) key, 0, sizeof *key);
192 memset((void*) computed, 0, sizeof *computed);
194 scratch->length = len;
195 scratch->data = ALLOCFUNC(scratch->length);
196 if (!scratch->data) {
197 printf ("rxgk_preparepacket: NOALLOC %d\n", len);
198 code = RXGKINCONSISTENCY;
199 goto PrChDone;
201 rx_Pullup(p, off);
202 rx_packetread(p, off, len-off, scratch->data);
203 scratch->length = len - off;
204 cp = rx_data(p, 0, cs);
205 if (cs < off) {
206 printf ("rxgk_preparepacket: short packet %d < %d\n", cs, off);
207 code = RXGKINCONSISTENCY;
208 goto PrChDone;
210 CKSUMDAT = cp;
211 CKSUMLEN = off;
212 #if defined(MIT_KRB5)
213 cksum->checksum_type = cktype; /* XXX */
214 #elif !defined(SHISHI_KRB5)
215 cksum->cksumtype = cktype; /* XXX */
216 #endif
218 #ifdef SHISHI_KRB5
219 /* XXX confounders? */
220 code = shishi_checksum(GETCONTEXT, key->sk, keyusage_mic, cktype,
221 scratch->data, scratch->length,
222 &computed->data, &computed->length);
223 if (code) {
224 code += ERROR_TABLE_BASE_SHI5;
225 goto PrChDone;
227 if (computed->length != CKSUMLEN
228 || memcmp(CKSUMDAT, computed->data, computed->length)) {
229 code = RXGKSEALEDINCON;
231 #elif defined(MIT_KRB5)
232 if ((code = krb5_c_verify_checksum(GETCONTEXT, key, keyusage_mic,
233 scratch, cksum, &valid)))
234 goto PrChDone;
235 if (valid == 0) code = RXGKSEALEDINCON;
236 #else
237 if ((code = krb5_verify_checksum(GETCONTEXT, k->ks_scrypto, keyusage_mic,
238 scratch->data, scratch->length, cksum)))
239 goto PrChDone;
240 #endif
241 if(!code)
242 rx_SetDataSize(p, len-off);
243 PrChDone:
244 if (computed->data) FREEFUNC(computed->data, computed->length);
245 krb5_free_keyblock_contents(GETCONTEXT, key);
246 if (scratch->data) FREEFUNC(scratch->data, len);
247 } else if (level == RXGK_M_CRYPT) {
248 memset((void*) cipher, 0, sizeof *cipher);
249 memset((void*) plain, 0, sizeof *plain);
250 memset((void*) key, 0, sizeof *key);
252 plain->length = len;
253 plain->data = ALLOCFUNC(plain->length);
254 #if defined(MIT_KRB5)
255 code = krb5_c_block_size(GETCONTEXT, akey->enctype, &enclen);
256 if (code)
257 goto PrEncPrChDone;
258 code = krb5_c_encrypt_length(GETCONTEXT, akey->enctype, plain->length, &enclen);
259 if (code)
260 goto PrEncPrChDone;
261 cipher->ciphertext.length = enclen;
262 cipher->ciphertext.data = ALLOCFUNC(cipher->ciphertext.length);
263 cipher->enctype = akey->enctype;
264 if (!cipher->ciphertext.data || !plain->data) {
265 code = RXGKINCONSISTENCY;
266 goto PrEncPrChDone;
268 #endif
269 /* XXX pad here */
270 cs = rx_packetread(p, off, len, plain->data);
271 if (cs && cs != len) {
272 printf ("rxgk_preparepacket read failed: got r=%d; gave len=%d\n",
273 cs, len);
275 #ifdef USING_SHISHI
276 code = shishi_encrypt(GETCONTEXT,
277 key->sk, keyusage_enc,
278 plain->data, plain->length,
279 &cipher->data, &cipher->length);
280 if (code) {
281 code += ERROR_TABLE_BASE_SHI5;
282 goto PrEncPrChDone;
284 if (cipher->length != plain->length + off)
286 printf ("rxgk_preparepacket: plain=%d off=%d; encrypted: predicted=%d actual=%d\n",
287 plain->length, off, plain->length+off, cipher->length);
288 code = RXGKINCONSISTENCY;
289 goto PrEncPrChDone;
291 #elif defined(MIT_KRB5)
292 code = krb5_c_encrypt(GETCONTEXT, key, keyusage_enc, 0, plain, cipher);
293 #else
294 code = krb5_encrypt(GETCONTEXT, k->ks_scrypto, keyusage_enc,
295 plain->data, plain->length,
296 cipher);
297 #endif
298 if (code)
299 goto PrEncPrChDone;
300 rxi_RoundUpPacket(p, plain->length-len);
301 rx_packetwrite(p, 0, CIPHTEXTLEN, CIPHTEXTDAT);
302 rx_SetDataSize(p, CIPHTEXTLEN);
303 cs = rx_GetDataSize(p);
305 if (cs && cs != CIPHTEXTLEN) {
306 printf("rxgk_preparepacket failed to write: "
307 "got r=%lu; gave len=%lu\n",
308 (unsigned long)cs, (unsigned long)CIPHTEXTLEN);
309 code = RXGKINCONSISTENCY;
310 goto PrEncPrChDone;
312 PrEncPrChDone:
313 if (plain->data)
314 FREEFUNC(plain->data, plain->length);
315 if (CIPHTEXTDAT)
316 FREEFUNC(CIPHTEXTDAT, CIPHTEXTLEN);
317 krb5_free_keyblock_contents(GETCONTEXT, key);
318 } else if (level == RXGK_M_AUTH_ONLY) {
319 code = 0;
320 } else
321 code = RXGKILLEGALLEVEL;
323 if (code)
324 printf ("rxgk_preparepacket err=%d\n", code);
325 return code;
332 rxgk_check_packet(struct rx_packet *p, struct rx_connection *conn,
333 int level, key_stuff *k, end_stuff *e,
334 int keyusage_enc, int keyusage_mic)
336 int len = rx_GetDataSize(p);
337 int off = rx_GetSecurityHeaderSize(conn);
338 int code;
339 krb5_data plain[1];
340 CIPHERTYPE cipher[1];
341 krb5_data scratch[1];
342 krb5_data computed[1];
343 CKSUMTYPE cksum[1];
344 krb5_keyblock key[1];
345 int cs;
346 char *cp;
347 #if defined(MIT_KRB5)
348 krb5_boolean valid;
349 #endif
350 int cktype = 1; /* CKSUMTYPE_CRC32 XXX */
352 if (level == RXGK_M_CRYPT) {
353 memset((void*) cipher, 0, sizeof *cipher);
354 memset((void*) plain, 0, sizeof *plain);
355 memset((void*) key, 0, sizeof *key);
356 CIPHTEXTLEN = len;
357 CIPHTEXTDAT = ALLOCFUNC(CIPHTEXTLEN);
358 #if !defined(MIT_KRB5)
359 if (!CIPHTEXTDAT) {
360 printf ("rxgk_checkpacket: NOALLOC %lu\n",
361 (unsigned long)cipher->length);
362 code = RXGKINCONSISTENCY;
363 goto ChEncPrChDone;
365 #else
366 plain->length = CIPHTEXTLEN;
367 plain->data = ALLOCFUNC(plain->length);
368 cipher->enctype = akey->enctype;
369 if (!cipher->ciphertext.data || !plain->data) {
370 printf ("rxgk_checkpacket: failed %#x(%d) %#x(%d)\n",
371 (int) cipher->ciphertext.data, (int) cipher->ciphertext.length,
372 (int) plain->data, (int) plain->length);
373 code = RXGKINCONSISTENCY;
374 goto ChEncPrChDone;
376 #endif
377 rx_packetread(p, 0, CIPHTEXTLEN, CIPHTEXTDAT);
378 #ifdef SHISHI_KRB5
379 code = shishi_decrypt(GETCONTEXT, key->sk, keyusage_enc,
380 cipher->data, cipher->length,
381 &plain->data, &plain->length);
382 if (code) {
383 code += ERROR_TABLE_BASE_SHI5;
384 goto ChEncPrChDone;
386 #elif MIT_KRB5
387 if ((code = krb5_c_decrypt(GETCONTEXT, key, keyusage_enc, 0, cipher, plain)))
388 goto ChEncPrChDone;
389 #else
390 code = krb5_decrypt(GETCONTEXT, k->ks_scrypto, keyusage_enc,
391 cipher->data, cipher->length,
392 plain);
393 if (code)
394 goto ChEncPrChDone;
395 #endif
396 rx_packetwrite(p, off, plain->length, plain->data);
397 rx_SetDataSize(p, plain->length);
398 ChEncPrChDone:
399 if (plain->data)
400 FREEFUNC(plain->data, plain->length); /* really free CIPHTEXTLEN? */
401 if (CIPHTEXTDAT)
402 FREEFUNC(CIPHTEXTDAT, CIPHTEXTLEN);
403 krb5_free_keyblock_contents(GETCONTEXT, key);
404 } else if (level == RXGK_M_INTEGRITY) {
405 memset((void*) scratch, 0, sizeof *scratch);
406 memset((void*) cksum, 0, sizeof *cksum);
407 memset((void*) key, 0, sizeof *key);
408 memset((void*) computed, 0, sizeof *computed);
409 scratch->length = len;
410 scratch->data = ALLOCFUNC(scratch->length);
411 if (!scratch->data) {
412 printf ("rxgk_checkpacket: alloc failed %lu\n",
413 (unsigned long)scratch->length);
414 code = RXGKINCONSISTENCY;
415 goto ChChDone;
417 rx_Pullup(p, off);
418 rx_packetread(p, off, len-off, scratch->data);
419 scratch->length = len - off;
420 cp = rx_data(p, 0, cs);
421 if (cs < off) {
422 printf ("rxgk_checkpacket: short packet %d < %d\n", cs, off);
423 code = RXGKINCONSISTENCY;
424 goto ChChDone;
426 CKSUMDAT = cp;
427 CKSUMLEN = off;
428 #if defined(MIT_KRB5)
429 cksum->checksum_type = cktype; /* XXX */
430 #elif !defined(SHISHI_KRB5)
431 cksum->cksumtype = cktype; /* XXX */
432 #endif
434 #ifdef SHISHI_KRB5
435 /* XXX confounders? */
436 code = shishi_checksum(GETCONTEXT, key->sk, keyusage_mic, cktype,
437 scratch->data, scratch->length,
438 &computed->data, &computed->length);
439 if (code) {
440 code += ERROR_TABLE_BASE_SHI5;
441 goto ChChDone;
443 if (computed->length != CKSUMLEN
444 || memcmp(CKSUMDAT, computed->data, computed->length)) {
445 code = RXGKSEALEDINCON;
447 #elif defined(MIT_KRB5)
448 if ((code = krb5_c_verify_checksum(GETCONTEXT, key, keyusage_mic,
449 scratch, cksum, &valid)))
450 goto ChChDone;
451 if (valid == 0) code = RXGKSEALEDINCON;
452 #else
453 if ((code = krb5_verify_checksum(GETCONTEXT, k->ks_scrypto, keyusage_mic,
454 scratch->data, scratch->length,
455 cksum)))
456 goto ChChDone;
457 #endif
458 if(!code)
459 rx_SetDataSize(p, len-off);
460 ChChDone:
461 if (computed->data)
462 FREEFUNC(computed->data, computed->length);
463 krb5_free_keyblock_contents(GETCONTEXT, key);
464 if (scratch->data)
465 FREEFUNC(scratch->data, len);
466 } else if (level == RXGK_M_AUTH_ONLY) {
467 code = 0;
468 } else {
469 code = RXGKILLEGALLEVEL;
471 if (code)
472 printf ("rxgk_checkpacket err=%d\n", code);
473 return code;
477 rxgk_encrypt_buffer(RXGK_Token *in, RXGK_Token *out,
478 struct rxgk_keyblock *key, int keyusage)
480 int i;
481 int x;
483 out->len = in->len + 4;
484 out->val = malloc(out->len);
486 out->val[0] = 1;
487 out->val[1] = 2;
488 out->val[2] = 3;
489 out->val[3] = 4;
491 /* XXX add real crypto */
492 x = keyusage;
493 for (i = 0; i < in->len; i++) {
494 x += i * 3 + ((unsigned char *)key->data)[i%key->length];
495 out->val[i+4] = in->val[i] ^ x;
498 return 0;
502 rxgk_decrypt_buffer(RXGK_Token *in, RXGK_Token *out,
503 struct rxgk_keyblock *key, int keyusage)
505 int i;
506 int x;
508 if (in->len < 4) {
509 return EINVAL;
512 if (in->val[0] != 1 ||
513 in->val[0] != 1 ||
514 in->val[0] != 1 ||
515 in->val[0] != 1) {
516 return EINVAL;
519 out->len = in->len - 4;
520 out->val = malloc(out->len);
522 /* XXX add real crypto */
523 x = keyusage;
524 for (i = 0; i < out->len; i++) {
525 x += i * 3 + ((unsigned char *)key->data)[i%key->length];
526 out->val[i] = in->val[i+4] ^ x;
529 return 0;
532 static void
533 print_key(char *name, struct rxgk_keyblock *key)
535 int i;
537 fprintf(stderr, "type: %s", name);
538 for (i = 0; i < key->length; i++)
539 fprintf(stderr, " %02x", ((unsigned char*)key->data)[i]);
540 fprintf(stderr, "\n");
544 rxgk_derive_transport_key(struct rxgk_keyblock *k0,
545 struct rxgk_keyblock *tk,
546 uint32_t epoch, uint32_t cid, int64_t start_time)
548 int i;
549 uint32_t x;
550 /* XXX get real key */
552 if (k0->enctype != RXGK_CRYPTO_AES256_CTS_HMAC_SHA1_96) {
553 return EINVAL;
556 tk->length = 32;
557 tk->enctype = RXGK_CRYPTO_AES256_CTS_HMAC_SHA1_96;
559 tk->data = malloc(tk->length);
560 if (tk->data == NULL)
561 return ENOMEM;
563 x = epoch * 4711 + cid * 33 + start_time;
564 for (i = 0; i < tk->length; i++) {
565 x += i * 3 + ((unsigned char *)k0->data)[i%k0->length];
566 ((unsigned char *)tk->data)[i] = 0x23 + x * 47;
569 print_key("k0: ", k0);
570 print_key("tk: ", tk);
572 return 0;