summaryrefslogtreecommitdiff
path: root/libdes/f_cbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdes/f_cbc.c')
-rw-r--r--libdes/f_cbc.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/libdes/f_cbc.c b/libdes/f_cbc.c
new file mode 100644
index 0000000..eba53be
--- /dev/null
+++ b/libdes/f_cbc.c
@@ -0,0 +1,198 @@
+/*
+ * 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_encrypt.c - an implementation of the DES cipher function in cbc mode
+ */
+#include "des.h"
+#include "f_tables.h"
+
+/*
+ * des_cbc_encrypt - {en,de}crypt a stream in CBC mode
+ */
+int
+des_cbc_encrypt(in, out, length, schedule, ivec, encrypt)
+ des_cblock *in;
+ des_cblock *out;
+ long length;
+ des_key_schedule schedule;
+ des_cblock ivec;
+ int encrypt;
+{
+ register unsigned long left, right;
+ register unsigned long temp;
+ register u_int32 *kp;
+ register unsigned char *ip, *op;
+
+ /*
+ * Get key pointer here. This won't need to be reinitialized
+ */
+ kp = (u_int32 *)schedule;
+
+ /*
+ * Deal with encryption and decryption separately.
+ */
+ if (encrypt) {
+ /*
+ * 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;
+ op = (unsigned char *)out;
+ while (length > 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 (length >= 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;
+ length -= 8;
+ } else {
+ /*
+ * Oh, shoot. We need to pad the
+ * end with zeroes. Work backwards
+ * to do this.
+ */
+ ip += (int) length;
+ switch(length) {
+ 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;
+ }
+ length = 0;
+ }
+
+ /*
+ * Encrypt what we have
+ */
+ DES_DO_ENCRYPT(left, right, temp, kp);
+
+ /*
+ * Copy the results out
+ */
+ PUT_HALF_BLOCK(left, op);
+ PUT_HALF_BLOCK(right, op);
+ }
+ } else {
+ /*
+ * Decrypting is harder than encrypting because of
+ * the necessity of remembering a lot more things.
+ * Should think about this a little more...
+ */
+ unsigned long ocipherl, ocipherr;
+ unsigned long cipherl, cipherr;
+
+ if (length <= 0)
+ return 0;
+
+ /*
+ * Prime the old cipher with ivec.
+ */
+ ip = (unsigned char *)ivec;
+ GET_HALF_BLOCK(ocipherl, ip);
+ GET_HALF_BLOCK(ocipherr, ip);
+
+ /*
+ * Now do this in earnest until we run out of length.
+ */
+ ip = (unsigned char *)in;
+ op = (unsigned char *)out;
+ for (;;) { /* check done inside loop */
+ /*
+ * Read a block from the input into left and
+ * right. Save this cipher block for later.
+ */
+ GET_HALF_BLOCK(left, ip);
+ GET_HALF_BLOCK(right, ip);
+ cipherl = left;
+ cipherr = right;
+
+ /*
+ * Decrypt this.
+ */
+ DES_DO_DECRYPT(left, right, temp, kp);
+
+ /*
+ * Xor with the old cipher to get plain
+ * text. Output 8 or less bytes of this.
+ */
+ left ^= ocipherl;
+ right ^= ocipherr;
+ if (length > 8) {
+ length -= 8;
+ PUT_HALF_BLOCK(left, op);
+ PUT_HALF_BLOCK(right, op);
+ /*
+ * Save current cipher block here
+ */
+ ocipherl = cipherl;
+ ocipherr = cipherr;
+ } else {
+ /*
+ * Trouble here. Start at end of output,
+ * work backwards.
+ */
+ op += (int) length;
+ switch(length) {
+ case 8:
+ *(--op) = right & 0xff;
+ case 7:
+ *(--op) = (right >> 8) & 0xff;
+ case 6:
+ *(--op) = (right >> 16) & 0xff;
+ case 5:
+ *(--op) = (right >> 24) & 0xff;
+ case 4:
+ *(--op) = left & 0xff;
+ case 3:
+ *(--op) = (left >> 8) & 0xff;
+ case 2:
+ *(--op) = (left >> 16) & 0xff;
+ case 1:
+ *(--op) = (left >> 24) & 0xff;
+ break;
+ }
+ break; /* we're done */
+ }
+ }
+ }
+
+ /*
+ * Done, return nothing.
+ */
+ return 0;
+}