1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/builtin/des/f_cbc.c */
3 /*
4 * Copyright (C) 1990 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 * CBC functions; used only by the test programs at this time. (krb5 uses the
29 * functions in f_aead.c instead.)
30 */
31
32 /*
33 * des_cbc_encrypt.c - an implementation of the DES cipher function in cbc mode
34 */
35 #include "des_int.h"
36 #include "f_tables.h"
37
38 /*
39 * des_cbc_encrypt - {en,de}crypt a stream in CBC mode
40 */
41
42 /*
43 * This routine performs DES cipher-block-chaining operation, either
44 * encrypting from cleartext to ciphertext, if encrypt != 0 or
45 * decrypting from ciphertext to cleartext, if encrypt == 0.
46 *
47 * The key schedule is passed as an arg, as well as the cleartext or
48 * ciphertext. The cleartext and ciphertext should be in host order.
49 *
50 * NOTE-- the output is ALWAYS an multiple of 8 bytes long. If not
51 * enough space was provided, your program will get trashed.
52 *
53 * For encryption, the cleartext string is null padded, at the end, to
54 * an integral multiple of eight bytes.
55 *
56 * For decryption, the ciphertext will be used in integral multiples
57 * of 8 bytes, but only the first "length" bytes returned into the
58 * cleartext.
59 */
60
61 const mit_des_cblock mit_des_zeroblock /* = all zero */;
62
63 static void
des_cbc_encrypt(const mit_des_cblock * in,mit_des_cblock * out,unsigned long length,const mit_des_key_schedule schedule,const mit_des_cblock ivec)64 des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
65 unsigned long length, const mit_des_key_schedule schedule,
66 const mit_des_cblock ivec)
67 {
68 unsigned DES_INT32 left, right;
69 const unsigned DES_INT32 *kp;
70 const unsigned char *ip;
71 unsigned char *op;
72
73 /*
74 * Get key pointer here. This won't need to be reinitialized
75 */
76 kp = (const unsigned DES_INT32 *)schedule;
77
78 /*
79 * Initialize left and right with the contents of the initial
80 * vector.
81 */
82 ip = ivec;
83 GET_HALF_BLOCK(left, ip);
84 GET_HALF_BLOCK(right, ip);
85
86 /*
87 * Suitably initialized, now work the length down 8 bytes
88 * at a time.
89 */
90 ip = *in;
91 op = *out;
92 while (length > 0) {
93 /*
94 * Get more input, xor it in. If the length is
95 * greater than or equal to 8 this is straight
96 * forward. Otherwise we have to fart around.
97 */
98 if (length >= 8) {
99 unsigned DES_INT32 temp;
100 GET_HALF_BLOCK(temp, ip);
101 left ^= temp;
102 GET_HALF_BLOCK(temp, ip);
103 right ^= temp;
104 length -= 8;
105 } else {
106 /*
107 * Oh, shoot. We need to pad the
108 * end with zeroes. Work backwards
109 * to do this.
110 */
111 ip += (int) length;
112 switch(length) {
113 case 7:
114 right ^= (*(--ip) & FF_UINT32) << 8;
115 case 6:
116 right ^= (*(--ip) & FF_UINT32) << 16;
117 case 5:
118 right ^= (*(--ip) & FF_UINT32) << 24;
119 case 4:
120 left ^= *(--ip) & FF_UINT32;
121 case 3:
122 left ^= (*(--ip) & FF_UINT32) << 8;
123 case 2:
124 left ^= (*(--ip) & FF_UINT32) << 16;
125 case 1:
126 left ^= (*(--ip) & FF_UINT32) << 24;
127 break;
128 }
129 length = 0;
130 }
131
132 /*
133 * Encrypt what we have
134 */
135 DES_DO_ENCRYPT(left, right, kp);
136
137 /*
138 * Copy the results out
139 */
140 PUT_HALF_BLOCK(left, op);
141 PUT_HALF_BLOCK(right, op);
142 }
143 }
144
145 static void
des_cbc_decrypt(const mit_des_cblock * in,mit_des_cblock * out,unsigned long length,const mit_des_key_schedule schedule,const mit_des_cblock ivec)146 des_cbc_decrypt(const mit_des_cblock *in, mit_des_cblock *out,
147 unsigned long length, const mit_des_key_schedule schedule,
148 const mit_des_cblock ivec)
149 {
150 unsigned DES_INT32 left, right;
151 const unsigned DES_INT32 *kp;
152 const unsigned char *ip;
153 unsigned char *op;
154 unsigned DES_INT32 ocipherl, ocipherr;
155 unsigned DES_INT32 cipherl, cipherr;
156
157 /*
158 * Get key pointer here. This won't need to be reinitialized
159 */
160 kp = (const unsigned DES_INT32 *)schedule;
161
162 /*
163 * Decrypting is harder than encrypting because of
164 * the necessity of remembering a lot more things.
165 * Should think about this a little more...
166 */
167
168 if (length <= 0)
169 return;
170
171 /*
172 * Prime the old cipher with ivec.
173 */
174 ip = ivec;
175 GET_HALF_BLOCK(ocipherl, ip);
176 GET_HALF_BLOCK(ocipherr, ip);
177
178 /*
179 * Now do this in earnest until we run out of length.
180 */
181 ip = *in;
182 op = *out;
183 for (;;) { /* check done inside loop */
184 /*
185 * Read a block from the input into left and
186 * right. Save this cipher block for later.
187 */
188 GET_HALF_BLOCK(left, ip);
189 GET_HALF_BLOCK(right, ip);
190 cipherl = left;
191 cipherr = right;
192
193 /*
194 * Decrypt this.
195 */
196 DES_DO_DECRYPT(left, right, kp);
197
198 /*
199 * Xor with the old cipher to get plain
200 * text. Output 8 or less bytes of this.
201 */
202 left ^= ocipherl;
203 right ^= ocipherr;
204 if (length > 8) {
205 length -= 8;
206 PUT_HALF_BLOCK(left, op);
207 PUT_HALF_BLOCK(right, op);
208 /*
209 * Save current cipher block here
210 */
211 ocipherl = cipherl;
212 ocipherr = cipherr;
213 } else {
214 /*
215 * Trouble here. Start at end of output,
216 * work backwards.
217 */
218 op += (int) length;
219 switch(length) {
220 case 8:
221 *(--op) = (unsigned char) (right & 0xff);
222 case 7:
223 *(--op) = (unsigned char) ((right >> 8) & 0xff);
224 case 6:
225 *(--op) = (unsigned char) ((right >> 16) & 0xff);
226 case 5:
227 *(--op) = (unsigned char) ((right >> 24) & 0xff);
228 case 4:
229 *(--op) = (unsigned char) (left & 0xff);
230 case 3:
231 *(--op) = (unsigned char) ((left >> 8) & 0xff);
232 case 2:
233 *(--op) = (unsigned char) ((left >> 16) & 0xff);
234 case 1:
235 *(--op) = (unsigned char) ((left >> 24) & 0xff);
236 break;
237 }
238 break; /* we're done */
239 }
240 }
241 }
242
243 int
mit_des_cbc_encrypt(const mit_des_cblock * in,mit_des_cblock * out,unsigned long length,const mit_des_key_schedule schedule,const mit_des_cblock ivec,int enc)244 mit_des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
245 unsigned long length, const mit_des_key_schedule schedule,
246 const mit_des_cblock ivec, int enc)
247 {
248 /*
249 * Deal with encryption and decryption separately.
250 */
251 if (enc)
252 des_cbc_encrypt(in, out, length, schedule, ivec);
253 else
254 des_cbc_decrypt(in, out, length, schedule, ivec);
255 return 0;
256 }
257