1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
/*
* Copyright (c) 1990 Dennis Ferguson. All rights reserved.
*
* Commercial use is permitted only if products which are derived from
* or include this software are made available for purchase and/or use
* in Canada. Otherwise, redistribution and use in source and binary
* forms are permitted.
*/
/*
* des_cbc_cksum.c - compute an 8 byte checksum using DES in CBC mode
*/
#include "des.h"
#include "f_tables.h"
/*
* This routine performs DES cipher-block-chaining checksum operation,
* a.k.a. Message Authentication Code. It ALWAYS encrypts from input
* to a single 64 bit output MAC checksum.
*
* The key schedule is passed as an arg, as well as the cleartext or
* ciphertext. The cleartext and ciphertext should be in host order.
*
* NOTE-- the output is ALWAYS 8 bytes long. If not enough space was
* provided, your program will get trashed.
*
* The input is null padded, at the end (highest addr), to an integral
* multiple of eight bytes.
*/
unsigned long
mit_des_cbc_cksum(in, out, length, schedule, ivec)
des_cblock *in;
des_cblock *out;
long length;
des_key_schedule schedule;
des_cblock ivec;
{
register unsigned KRB_INT32 left, right;
register unsigned KRB_INT32 temp;
register unsigned KRB_INT32 *kp;
register unsigned char *ip;
register KRB_INT32 len;
/*
* Initialize left and right with the contents of the initial
* vector.
*/
ip = (unsigned char *)ivec;
GET_HALF_BLOCK(left, ip);
GET_HALF_BLOCK(right, ip);
/*
* Suitably initialized, now work the length down 8 bytes
* at a time.
*/
ip = (unsigned char *)in;
len = length;
while (len > 0) {
/*
* Get more input, xor it in. If the length is
* greater than or equal to 8 this is straight
* forward. Otherwise we have to fart around.
*/
if (len >= 8) {
left ^= ((*ip++) & 0xff) << 24;
left ^= ((*ip++) & 0xff) << 16;
left ^= ((*ip++) & 0xff) << 8;
left ^= (*ip++) & 0xff;
right ^= ((*ip++) & 0xff) << 24;
right ^= ((*ip++) & 0xff) << 16;
right ^= ((*ip++) & 0xff) << 8;
right ^= (*ip++) & 0xff;
len -= 8;
} else {
/*
* Oh, shoot. We need to pad the
* end with zeroes. Work backwards
* to do this.
*/
ip += (int) len;
switch(len) {
case 7:
right ^= (*(--ip) & 0xff) << 8;
case 6:
right ^= (*(--ip) & 0xff) << 16;
case 5:
right ^= (*(--ip) & 0xff) << 24;
case 4:
left ^= *(--ip) & 0xff;
case 3:
left ^= (*(--ip) & 0xff) << 8;
case 2:
left ^= (*(--ip) & 0xff) << 16;
case 1:
left ^= (*(--ip) & 0xff) << 24;
break;
}
len = 0;
}
/*
* Encrypt what we have
*/
kp = (unsigned KRB_INT32 *)schedule;
DES_DO_ENCRYPT(left, right, temp, kp);
}
/*
* Done. Left and right have the checksum. Put it into
* the output.
*/
ip = (unsigned char *)out;
PUT_HALF_BLOCK(left, ip);
PUT_HALF_BLOCK(right, ip);
/*
* Return right. I'll bet the MIT code returns this
* inconsistantly (with the low order byte of the checksum
* not always in the low order byte of the KRB_INT32). We won't.
*/
return right;
}
|