xref: /freebsd/crypto/krb5/src/lib/crypto/builtin/des/f_cbc.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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