2 * Copyright (c) 2002 - 2004, Stockholms universitet
3 * (Stockholm University, Stockholm Sweden)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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"
43 struct _rxg_key_type
{
51 static struct _rxg_key_type ktypes
[] = {
52 { "des-cbc-crc", RXGK_CRYPTO_DES_CBC_CRC
,
55 { "des-cbc-md5", RXGK_CRYPTO_DES_CBC_MD5
,
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
)
72 rxgk_set_conn(struct rx_connection
*con
, int enctype
, int enc
)
74 struct _rxg_key_type
*key
;
76 key
= _rxg_find_enctype(enctype
);
81 rx_SetSecurityHeaderSize(con
, key
->checksumlen
+ key
->confounderlen
+
82 RXGK_HEADER_DATA_SIZE
);
84 rx_SetSecurityMaxTrailerSize(con
, key
->blocklen
);
86 rx_SetSecurityHeaderSize(con
,
87 key
->checksumlen
+ RXGK_HEADER_DATA_SIZE
);
88 rx_SetSecurityMaxTrailerSize(con
, 0);
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
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
123 #define ALLOCFUNC(x) osi_Alloc(x)
124 #define FREEFUNC(x,y) osi_Free(x,y)
126 #define ALLOCFUNC(x) malloc(x)
127 #define FREEFUNC(x,y) free(x)
130 #define GETCONTEXT rxgk_krb5_context
133 rxgk_crypto_init(struct rxgk_keyblock
*tk
, key_stuff
*k
)
139 ret
= krb5_keyblock_init(GETCONTEXT
, tk
->enctype
,
140 tk
->data
, tk
->length
,
146 ret
= krb5_crypto_init (GETCONTEXT
, &tk_kb
,
150 krb5_free_keyblock_contents(GETCONTEXT
, &tk_kb
);
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
);
166 int padding
= rx_GetSecurityMaxTrailerSize(conn
);
170 CIPHERTYPE cipher
[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 */
180 #if defined(MIT_KRB5)
183 int cktype
= 1; /* CKSUMTYPE_CRC32 XXX */
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
;
202 rx_packetread(p
, off
, len
-off
, scratch
->data
);
203 scratch
->length
= len
- off
;
204 cp
= rx_data(p
, 0, cs
);
206 printf ("rxgk_preparepacket: short packet %d < %d\n", cs
, off
);
207 code
= RXGKINCONSISTENCY
;
212 #if defined(MIT_KRB5)
213 cksum
->checksum_type
= cktype
; /* XXX */
214 #elif !defined(SHISHI_KRB5)
215 cksum
->cksumtype
= cktype
; /* XXX */
219 /* XXX confounders? */
220 code
= shishi_checksum(GETCONTEXT
, key
->sk
, keyusage_mic
, cktype
,
221 scratch
->data
, scratch
->length
,
222 &computed
->data
, &computed
->length
);
224 code
+= ERROR_TABLE_BASE_SHI5
;
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
)))
235 if (valid
== 0) code
= RXGKSEALEDINCON
;
237 if ((code
= krb5_verify_checksum(GETCONTEXT
, k
->ks_scrypto
, keyusage_mic
,
238 scratch
->data
, scratch
->length
, cksum
)))
242 rx_SetDataSize(p
, len
-off
);
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
);
253 plain
->data
= ALLOCFUNC(plain
->length
);
254 #if defined(MIT_KRB5)
255 code
= krb5_c_block_size(GETCONTEXT
, akey
->enctype
, &enclen
);
258 code
= krb5_c_encrypt_length(GETCONTEXT
, akey
->enctype
, plain
->length
, &enclen
);
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
;
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",
276 code
= shishi_encrypt(GETCONTEXT
,
277 key
->sk
, keyusage_enc
,
278 plain
->data
, plain
->length
,
279 &cipher
->data
, &cipher
->length
);
281 code
+= ERROR_TABLE_BASE_SHI5
;
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
;
291 #elif defined(MIT_KRB5)
292 code
= krb5_c_encrypt(GETCONTEXT
, key
, keyusage_enc
, 0, plain
, cipher
);
294 code
= krb5_encrypt(GETCONTEXT
, k
->ks_scrypto
, keyusage_enc
,
295 plain
->data
, plain
->length
,
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
;
314 FREEFUNC(plain
->data
, plain
->length
);
316 FREEFUNC(CIPHTEXTDAT
, CIPHTEXTLEN
);
317 krb5_free_keyblock_contents(GETCONTEXT
, key
);
318 } else if (level
== RXGK_M_AUTH_ONLY
) {
321 code
= RXGKILLEGALLEVEL
;
324 printf ("rxgk_preparepacket err=%d\n", 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
);
340 CIPHERTYPE cipher
[1];
341 krb5_data scratch
[1];
342 krb5_data computed
[1];
344 krb5_keyblock key
[1];
347 #if defined(MIT_KRB5)
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
);
357 CIPHTEXTDAT
= ALLOCFUNC(CIPHTEXTLEN
);
358 #if !defined(MIT_KRB5)
360 printf ("rxgk_checkpacket: NOALLOC %lu\n",
361 (unsigned long)cipher
->length
);
362 code
= RXGKINCONSISTENCY
;
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
;
377 rx_packetread(p
, 0, CIPHTEXTLEN
, CIPHTEXTDAT
);
379 code
= shishi_decrypt(GETCONTEXT
, key
->sk
, keyusage_enc
,
380 cipher
->data
, cipher
->length
,
381 &plain
->data
, &plain
->length
);
383 code
+= ERROR_TABLE_BASE_SHI5
;
387 if ((code
= krb5_c_decrypt(GETCONTEXT
, key
, keyusage_enc
, 0, cipher
, plain
)))
390 code
= krb5_decrypt(GETCONTEXT
, k
->ks_scrypto
, keyusage_enc
,
391 cipher
->data
, cipher
->length
,
396 rx_packetwrite(p
, off
, plain
->length
, plain
->data
);
397 rx_SetDataSize(p
, plain
->length
);
400 FREEFUNC(plain
->data
, plain
->length
); /* really free CIPHTEXTLEN? */
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
;
418 rx_packetread(p
, off
, len
-off
, scratch
->data
);
419 scratch
->length
= len
- off
;
420 cp
= rx_data(p
, 0, cs
);
422 printf ("rxgk_checkpacket: short packet %d < %d\n", cs
, off
);
423 code
= RXGKINCONSISTENCY
;
428 #if defined(MIT_KRB5)
429 cksum
->checksum_type
= cktype
; /* XXX */
430 #elif !defined(SHISHI_KRB5)
431 cksum
->cksumtype
= cktype
; /* XXX */
435 /* XXX confounders? */
436 code
= shishi_checksum(GETCONTEXT
, key
->sk
, keyusage_mic
, cktype
,
437 scratch
->data
, scratch
->length
,
438 &computed
->data
, &computed
->length
);
440 code
+= ERROR_TABLE_BASE_SHI5
;
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
)))
451 if (valid
== 0) code
= RXGKSEALEDINCON
;
453 if ((code
= krb5_verify_checksum(GETCONTEXT
, k
->ks_scrypto
, keyusage_mic
,
454 scratch
->data
, scratch
->length
,
459 rx_SetDataSize(p
, len
-off
);
462 FREEFUNC(computed
->data
, computed
->length
);
463 krb5_free_keyblock_contents(GETCONTEXT
, key
);
465 FREEFUNC(scratch
->data
, len
);
466 } else if (level
== RXGK_M_AUTH_ONLY
) {
469 code
= RXGKILLEGALLEVEL
;
472 printf ("rxgk_checkpacket err=%d\n", code
);
477 rxgk_encrypt_buffer(RXGK_Token
*in
, RXGK_Token
*out
,
478 struct rxgk_keyblock
*key
, int keyusage
)
483 out
->len
= in
->len
+ 4;
484 out
->val
= malloc(out
->len
);
491 /* XXX add real crypto */
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
;
502 rxgk_decrypt_buffer(RXGK_Token
*in
, RXGK_Token
*out
,
503 struct rxgk_keyblock
*key
, int keyusage
)
512 if (in
->val
[0] != 1 ||
519 out
->len
= in
->len
- 4;
520 out
->val
= malloc(out
->len
);
522 /* XXX add real crypto */
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
;
533 print_key(char *name
, struct rxgk_keyblock
*key
)
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
)
550 /* XXX get real key */
552 if (k0
->enctype
!= RXGK_CRYPTO_AES256_CTS_HMAC_SHA1_96
) {
557 tk
->enctype
= RXGK_CRYPTO_AES256_CTS_HMAC_SHA1_96
;
559 tk
->data
= malloc(tk
->length
);
560 if (tk
->data
== NULL
)
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
);