Windows global stuff:
[krb5.git] / src / lib / crypto / des / f_pcbc.c
1 /*
2  * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
3  *
4  * Commercial use is permitted only if products which are derived from
5  * or include this software are made available for purchase and/or use
6  * in Canada.  Otherwise, redistribution and use in source and binary
7  * forms are permitted.
8  */
9
10 /*
11  * des_pcbc_encrypt.c - encrypt a string of characters in error propagation mode
12  */
13 #include "des.h"
14 #include "f_tables.h"
15
16 /*
17  * des_pcbc_encrypt - {en,de}crypt a stream in PCBC mode
18  */
19 int
20 mit_des_pcbc_encrypt(in, out, length, schedule, ivec, encrypt)
21         des_cblock *in;
22         des_cblock *out;
23         long length;
24         des_key_schedule schedule;
25         des_cblock ivec;
26         int encrypt;
27 {
28         register unsigned KRB_INT32 left, right;
29         register unsigned KRB_INT32 temp;
30         register unsigned KRB_INT32 *kp;
31         register unsigned char *ip, *op;
32
33         /*
34          * Copy the key pointer, just once
35          */
36         kp = (unsigned KRB_INT32 *)schedule;
37
38         /*
39          * Deal with encryption and decryption separately.
40          */
41         if (encrypt) {
42                 register unsigned KRB_INT32 plainl;
43                 register unsigned KRB_INT32 plainr;
44
45                 /*
46                  * Initialize left and right with the contents of the initial
47                  * vector.
48                  */
49                 ip = (unsigned char *)ivec;
50                 GET_HALF_BLOCK(left, ip);
51                 GET_HALF_BLOCK(right, ip);
52
53                 /*
54                  * Suitably initialized, now work the length down 8 bytes
55                  * at a time.
56                  */
57                 ip = (unsigned char *)in;
58                 op = (unsigned char *)out;
59                 while (length > 0) {
60                         /*
61                          * Get block of input.  If the length is
62                          * greater than 8 this is straight
63                          * forward.  Otherwise we have to fart around.
64                          */
65                         if (length > 8) {
66                                 GET_HALF_BLOCK(plainl, ip);
67                                 GET_HALF_BLOCK(plainr, ip);
68                                 left ^= plainl;
69                                 right ^= plainr;
70                                 length -= 8;
71                         } else {
72                                 /*
73                                  * Oh, shoot.  We need to pad the
74                                  * end with zeroes.  Work backwards
75                                  * to do this.  We know this is the
76                                  * last block, though, so we don't have
77                                  * to save the plain text.
78                                  */
79                                 ip += (int) length;
80                                 switch(length) {
81                                 case 8:
82                                         right ^=  *(--ip) & FF_UINT32;
83                                 case 7:
84                                         right ^= (*(--ip) & FF_UINT32) <<  8;
85                                 case 6:
86                                         right ^= (*(--ip) & FF_UINT32) << 16;
87                                 case 5:
88                                         right ^= (*(--ip) & FF_UINT32) << 24;
89                                 case 4:
90                                         left  ^=  *(--ip) & FF_UINT32;
91                                 case 3:
92                                         left  ^= (*(--ip) & FF_UINT32) <<  8;
93                                 case 2:
94                                         left  ^= (*(--ip) & FF_UINT32) << 16;
95                                 case 1:
96                                         left  ^= (*(--ip) & FF_UINT32) << 24;
97                                         break;
98                                 }
99                                 length = 0;
100                         }
101
102                         /*
103                          * Encrypt what we have
104                          */
105                         DES_DO_ENCRYPT(left, right, temp, kp);
106
107                         /*
108                          * Copy the results out
109                          */
110                         PUT_HALF_BLOCK(left, op);
111                         PUT_HALF_BLOCK(right, op);
112
113                         /*
114                          * Xor with the old plain text
115                          */
116                         left ^= plainl;
117                         right ^= plainr;
118                 }
119         } else {
120                 /*
121                  * Decrypting is harder than encrypting because of
122                  * the necessity of remembering a lot more things.
123                  * Should think about this a little more...
124                  */
125                 unsigned KRB_INT32 ocipherl, ocipherr;
126                 unsigned KRB_INT32 cipherl, cipherr;
127
128                 if (length <= 0)
129                         return 0;
130
131                 /*
132                  * Prime the old cipher with ivec.
133                  */
134                 ip = (unsigned char *)ivec;
135                 GET_HALF_BLOCK(ocipherl, ip);
136                 GET_HALF_BLOCK(ocipherr, ip);
137
138                 /*
139                  * Now do this in earnest until we run out of length.
140                  */
141                 ip = (unsigned char *)in;
142                 op = (unsigned char *)out;
143                 for (;;) {              /* check done inside loop */
144                         /*
145                          * Read a block from the input into left and
146                          * right.  Save this cipher block for later.
147                          */
148                         GET_HALF_BLOCK(left, ip);
149                         GET_HALF_BLOCK(right, ip);
150                         cipherl = left;
151                         cipherr = right;
152
153                         /*
154                          * Decrypt this.
155                          */
156                         DES_DO_DECRYPT(left, right, temp, kp);
157
158                         /*
159                          * Xor with the old cipher to get plain
160                          * text.  Output 8 or less bytes of this.
161                          */
162                         left ^= ocipherl;
163                         right ^= ocipherr;
164                         if (length > 8) {
165                                 length -= 8;
166                                 PUT_HALF_BLOCK(left, op);
167                                 PUT_HALF_BLOCK(right, op);
168                                 /*
169                                  * Save current cipher block here
170                                  */
171                                 ocipherl = cipherl ^ left;
172                                 ocipherr = cipherr ^ right;
173                         } else {
174                                 /*
175                                  * Trouble here.  Start at end of output,
176                                  * work backwards.
177                                  */
178                                 op += (int) length;
179                                 switch(length) {
180                                 case 8:
181                                         *(--op) = (unsigned char) (right & 0xff);
182                                 case 7:
183                                         *(--op) = (unsigned char) ((right >> 8) & 0xff);
184                                 case 6:
185                                         *(--op) = (unsigned char) ((right >> 16) & 0xff);
186                                 case 5:
187                                         *(--op) = (unsigned char) ((right >> 24) & 0xff);
188                                 case 4:
189                                         *(--op) = (unsigned char) (left & 0xff);
190                                 case 3:
191                                         *(--op) = (unsigned char) ((left >> 8) & 0xff);
192                                 case 2:
193                                         *(--op) = (unsigned char) ((left >> 16) & 0xff);
194                                 case 1:
195                                         *(--op) = (unsigned char) ((left >> 24) & 0xff);
196                                         break;
197                                 }
198                                 break;          /* we're done */
199                         }
200                 }
201         }
202
203         /*
204          * Done, return nothing.
205          */
206         return 0;
207 }