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 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 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 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