summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto
diff options
context:
space:
mode:
authorRichard Basch <probe@mit.edu>1995-11-28 01:09:19 +0000
committerRichard Basch <probe@mit.edu>1995-11-28 01:09:19 +0000
commite9883f16460e4e81377144c59112fa528fb26811 (patch)
tree4e93174ee2a534f8de26943efe50968c38c3321f /src/lib/crypto
parentedb56f18a74e4346f475572ca42d97421aa3cd54 (diff)
downloadkrb5-e9883f16460e4e81377144c59112fa528fb26811.tar.gz
krb5-e9883f16460e4e81377144c59112fa528fb26811.tar.xz
krb5-e9883f16460e4e81377144c59112fa528fb26811.zip
Triple-DES support routines
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7127 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/crypto')
-rw-r--r--src/lib/crypto/des/d3_cbc.c200
-rw-r--r--src/lib/crypto/des/d3_ecb.c48
-rw-r--r--src/lib/crypto/des/d3_kysched.c55
-rw-r--r--src/lib/crypto/des/d3_procky.c59
-rw-r--r--src/lib/crypto/des/d3_rndky.c51
-rw-r--r--src/lib/crypto/des/d3_str2ky.c118
-rw-r--r--src/lib/crypto/des/u_nfold.c106
7 files changed, 637 insertions, 0 deletions
diff --git a/src/lib/crypto/des/d3_cbc.c b/src/lib/crypto/des/d3_cbc.c
new file mode 100644
index 0000000000..4509c2e17c
--- /dev/null
+++ b/src/lib/crypto/des/d3_cbc.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "des.h"
+#include "des_int.h"
+#include "f_tables.h"
+
+/*
+ * Triple-DES CBC encryption mode.
+ */
+
+int
+mit_des3_cbc_encrypt(in, out, length, ks1, ks2, ks3, ivec, encrypt)
+ const mit_des_cblock FAR *in;
+ mit_des_cblock FAR *out;
+ long length;
+ mit_des_key_schedule ks1, ks2, ks3;
+ mit_des_cblock ivec;
+ int encrypt;
+{
+ register unsigned KRB_INT32 left, right;
+ register unsigned KRB_INT32 temp;
+ register unsigned KRB_INT32 *kp1, *kp2, *kp3;
+ register unsigned char *ip, *op;
+
+ /*
+ * Get key pointer here. This won't need to be reinitialized
+ */
+ kp1 = (unsigned KRB_INT32 *)ks1;
+ kp2 = (unsigned KRB_INT32 *)ks2;
+ kp3 = (unsigned KRB_INT32 *)ks3;
+
+ /*
+ * 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++) & FF_UINT32) << 24;
+ left ^= ((*ip++) & FF_UINT32) << 16;
+ left ^= ((*ip++) & FF_UINT32) << 8;
+ left ^= (*ip++) & FF_UINT32;
+ right ^= ((*ip++) & FF_UINT32) << 24;
+ right ^= ((*ip++) & FF_UINT32) << 16;
+ right ^= ((*ip++) & FF_UINT32) << 8;
+ right ^= (*ip++) & FF_UINT32;
+ 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) & FF_UINT32) << 8;
+ case 6: right ^= (*(--ip) & FF_UINT32) << 16;
+ case 5: right ^= (*(--ip) & FF_UINT32) << 24;
+ case 4: left ^= *(--ip) & FF_UINT32;
+ case 3: left ^= (*(--ip) & FF_UINT32) << 8;
+ case 2: left ^= (*(--ip) & FF_UINT32) << 16;
+ case 1: left ^= (*(--ip) & FF_UINT32) << 24;
+
+ }
+ length = 0;
+ }
+
+ /*
+ * Encrypt what we have
+ */
+ DES_DO_ENCRYPT(left, right, temp, kp1);
+ DES_DO_DECRYPT(left, right, temp, kp2);
+ DES_DO_ENCRYPT(left, right, temp, kp3);
+
+ /*
+ * 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 KRB_INT32 ocipherl, ocipherr;
+ unsigned KRB_INT32 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, kp3);
+ DES_DO_ENCRYPT(left, right, temp, kp2);
+ DES_DO_DECRYPT(left, right, temp, kp1);
+
+ /*
+ * 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) = (unsigned char) (right & 0xff);
+ case 7: *(--op) = (unsigned char) ((right >> 8) & 0xff);
+ case 6: *(--op) = (unsigned char) ((right >> 16) & 0xff);
+ case 5: *(--op) = (unsigned char) ((right >> 24) & 0xff);
+ case 4: *(--op) = (unsigned char) (left & 0xff);
+ case 3: *(--op) = (unsigned char) ((left >> 8) & 0xff);
+ case 2: *(--op) = (unsigned char) ((left >> 16) & 0xff);
+ case 1: *(--op) = (unsigned char) ((left >> 24) & 0xff);
+ }
+ break; /* we're done */
+ }
+ }
+ }
+
+ /*
+ * Done, return nothing.
+ */
+ return 0;
+}
diff --git a/src/lib/crypto/des/d3_ecb.c b/src/lib/crypto/des/d3_ecb.c
new file mode 100644
index 0000000000..a51898fd9d
--- /dev/null
+++ b/src/lib/crypto/des/d3_ecb.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "des.h"
+#include "des_int.h"
+#include "f_tables.h"
+
+/*
+ * Triple-DES ECB encryption mode.
+ */
+
+int
+mit_des3_ecb_encrypt(in, out, sched1, sched2, sched3, encrypt)
+ const mit_des_cblock FAR *in;
+ mit_des_cblock FAR *out;
+ mit_des_key_schedule sched1, sched2, sched3;
+ int encrypt;
+{
+ if (encrypt) {
+ mit_des_ecb_encrypt(in, out, sched1, encrypt);
+ mit_des_ecb_encrypt(out, out, sched2, !encrypt);
+ mit_des_ecb_encrypt(out, out, sched3, encrypt);
+ } else {
+ mit_des_ecb_encrypt(in, out, sched3, encrypt);
+ mit_des_ecb_encrypt(out, out, sched2, !encrypt);
+ mit_des_ecb_encrypt(out, out, sched1, encrypt);
+ }
+ return 0;
+}
diff --git a/src/lib/crypto/des/d3_kysched.c b/src/lib/crypto/des/d3_kysched.c
new file mode 100644
index 0000000000..efd91c44b2
--- /dev/null
+++ b/src/lib/crypto/des/d3_kysched.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+int
+mit_des3_key_sched(key,key_sched)
+ mit_des3_cblock key;
+ mit_des3_key_schedule key_sched;
+{
+ mit_des_cblock *k = (mit_des_cblock *)key;
+ mit_des_key_schedule *schedule = (mit_des_key_schedule *)key_sched;
+
+ make_key_sched(k[0],schedule[0]);
+ make_key_sched(k[1],schedule[1]);
+ make_key_sched(k[2],schedule[2]);
+
+ if (!mit_des_check_key_parity(k[0])) /* bad parity --> return -1 */
+ return(-1);
+ if (mit_des_is_weak_key(k[0]))
+ return(-2);
+
+ if (!mit_des_check_key_parity(k[1]))
+ return(-1);
+ if (mit_des_is_weak_key(k[1]))
+ return(-2);
+
+ if (!mit_des_check_key_parity(k[2]))
+ return(-1);
+ if (mit_des_is_weak_key(k[2]))
+ return(-2);
+
+ /* if key was good, return 0 */
+ return 0;
+}
diff --git a/src/lib/crypto/des/d3_procky.c b/src/lib/crypto/des/d3_procky.c
new file mode 100644
index 0000000000..1e50dd9fdb
--- /dev/null
+++ b/src/lib/crypto/des/d3_procky.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+krb5_error_code
+mit_des3_process_key (eblock, keyblock)
+ krb5_encrypt_block * eblock;
+ const krb5_keyblock * keyblock;
+{
+ struct mit_des_ks_struct *schedule; /* pointer to key schedules */
+
+ if (keyblock->enctype != ENCTYPE_DES3_CBC_MD5)
+ return KRB5_PROG_ETYPE_NOSUPP;
+
+ if (keyblock->length != sizeof (mit_des3_cblock))
+ return KRB5_BAD_KEYSIZE;
+
+ if ( !(schedule = (struct mit_des_ks_struct *) malloc(3*sizeof(mit_des_key_schedule))) )
+ return ENOMEM;
+#define cleanup() { free( (char *) schedule); }
+
+ switch (mit_des3_key_sched (*(mit_des3_cblock *)keyblock->contents,
+ *(mit_des3_key_schedule *)schedule)) {
+ case -1:
+ cleanup();
+ return KRB5DES_BAD_KEYPAR;
+
+ case -2:
+ cleanup();
+ return KRB5DES_WEAK_KEY;
+ }
+
+ eblock->key = (krb5_keyblock *) keyblock;
+ eblock->priv = (krb5_pointer) schedule;
+ eblock->priv_size = (krb5_int32) 3*sizeof(mit_des_key_schedule);
+
+ return 0;
+}
diff --git a/src/lib/crypto/des/d3_rndky.c b/src/lib/crypto/des/d3_rndky.c
new file mode 100644
index 0000000000..5edcf4d322
--- /dev/null
+++ b/src/lib/crypto/des/d3_rndky.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+krb5_error_code
+mit_des3_random_key (eblock, seed, keyblock)
+ const krb5_encrypt_block * eblock;
+ krb5_pointer seed;
+ krb5_keyblock ** keyblock;
+{
+ krb5_keyblock *randkey;
+
+ if (!(randkey = (krb5_keyblock *)malloc(sizeof(*randkey))))
+ return ENOMEM;
+ if (!(randkey->contents=(krb5_octet *)malloc(sizeof(mit_des3_cblock)))) {
+ krb5_xfree(randkey);
+ return ENOMEM;
+ }
+ randkey->magic = KV5M_KEYBLOCK;
+ randkey->length = sizeof(mit_des3_cblock);
+ randkey->enctype = eblock->crypto_entry->proto_enctype;
+ mit_des_new_random_key(*(mit_des_cblock *)randkey->contents,
+ (mit_des_random_key_seed *) seed);
+ mit_des_new_random_key(*((mit_des_cblock *)randkey->contents + 1),
+ (mit_des_random_key_seed *) seed);
+ mit_des_new_random_key(*((mit_des_cblock *)randkey->contents + 2),
+ (mit_des_random_key_seed *) seed);
+ *keyblock = randkey;
+ return 0;
+}
diff --git a/src/lib/crypto/des/d3_str2ky.c b/src/lib/crypto/des/d3_str2ky.c
new file mode 100644
index 0000000000..5f4d7a050b
--- /dev/null
+++ b/src/lib/crypto/des/d3_str2ky.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+/*
+ * Triple-DES string-to-key algorithm
+ *
+ * 1. Concatenate the input string and salt, and pad with zeroes until
+ * it is at least 24 bits, and a multiple of eight.
+ * 2. Fanfold the bits into a 24 bytes of key information (3 DES keys).
+ * 3. Use the three DES keys to perform a triple CBC encryption and return
+ * the last 24 bytes (similar to the MAC computation for DES in FIPS 81).
+ *
+ * This routine assumes that the triple CBC checksum will do the appropriate
+ * padding and that its return value will be 24 bytes.
+ */
+
+static mit_des_cblock zero_ivec = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+krb5_error_code
+mit_des3_string_to_key (eblock, keyblock, data, salt)
+const krb5_encrypt_block FAR * eblock;
+krb5_keyblock FAR * keyblock;
+const krb5_data FAR * data;
+const krb5_data FAR * salt;
+{
+ register char *str, *copystr;
+ register mit_des_cblock *key;
+ register int j;
+
+ register long length;
+ mit_des3_key_schedule ks;
+ krb5_enctype enctype = eblock->crypto_entry->proto_enctype;
+
+ if (enctype == ENCTYPE_DES3_CBC_MD5)
+ keyblock->length = sizeof(mit_des3_cblock);
+ else
+ return (KRB5_PROG_ETYPE_NOSUPP);
+
+ if ( !(keyblock->contents = (krb5_octet *)malloc(keyblock->length)) )
+ return(ENOMEM);
+
+ keyblock->magic = KV5M_KEYBLOCK;
+ keyblock->enctype = enctype;
+ key = (mit_des_cblock *)keyblock->contents;
+
+ if (salt)
+ length = data->length + salt->length;
+ else
+ length = data->length;
+
+ if (length < keyblock->length)
+ length = keyblock->length;
+
+ copystr = malloc((size_t) length);
+ if (!copystr) {
+ free(keyblock->contents);
+ keyblock->contents = 0;
+ return ENOMEM;
+ }
+
+ memset(copystr, 0, length);
+ memcpy(copystr, (char *) data->data, data->length);
+ if (salt)
+ memcpy(copystr + data->length, (char *)salt->data, salt->length);
+
+ /* n-fold into des3 key */
+ if (mit_des_n_fold(copystr, length, keyblock->contents, keyblock->length))
+ return EINVAL;
+
+ /* fix key parity */
+ for (j = 0; j < keyblock->length/sizeof(mit_des_cblock); j++)
+ mit_des_fixup_key_parity(*((mit_des_cblock *)key+j));
+
+ /* Now, CBC encrypt with itself */
+ (void) mit_des3_key_sched(*((mit_des3_cblock *)key), ks);
+ (void) mit_des3_cbc_encrypt((mit_des_cblock *)key,
+ (mit_des_cblock *)key,
+ keyblock->length,
+ ((mit_des_key_schedule *)ks)[0],
+ ((mit_des_key_schedule *)ks)[1],
+ ((mit_des_key_schedule *)ks)[2],
+ zero_ivec, TRUE);
+
+ /* erase key_sked */
+ memset((char *)ks, 0, sizeof(ks));
+
+ /* clean & free the input string */
+ memset(copystr, 0, (size_t) length);
+ krb5_xfree(copystr);
+
+ /* now fix up key parity again */
+ for (j = 0; j < keyblock->length/sizeof(mit_des_cblock); j++)
+ mit_des_fixup_key_parity(*((mit_des_cblock *)key+j));
+
+ return 0;
+}
diff --git a/src/lib/crypto/des/u_nfold.c b/src/lib/crypto/des/u_nfold.c
new file mode 100644
index 0000000000..3dd9199620
--- /dev/null
+++ b/src/lib/crypto/des/u_nfold.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1995 by Richard P. Basch. All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ *
+ *
+ * N-folding algorithm
+ * Described in "A Better Key Schedule for DES-like Ciphers"
+ * by Uri Blumenthal and Steven M. Bellovin
+ * based on the work done by Lars Knudsen.
+ *
+ * To n-fold a number X, replicate the input value X to a length that is
+ * the least common multiple of n and the length of X. Before each
+ * repetition, the input value is rotated to the right by 13 bit positions.
+ * The successive n-bit chunks are added together using 1's complement
+ * addition (addition with end-around carry) to yield a n-bit result.
+ *
+ * The algorithm here assumes that the input and output are padded to
+ * octet boundaries (8-bit multiple).
+ */
+
+#include "k5-int.h"
+#include <assert.h>
+
+#define ROTATE_VALUE 13
+
+krb5_error_code
+mit_des_n_fold(inbuf, inlen, outbuf, outlen)
+ krb5_octet *inbuf;
+ size_t inlen;
+ krb5_octet *outbuf;
+ size_t outlen;
+{
+ register int bytes;
+ register krb5_octet *tempbuf;
+
+ if (inbuf == (krb5_octet *)NULL)
+ return EINVAL;
+ if (outbuf == (krb5_octet *)NULL)
+ return EINVAL;
+
+ tempbuf = (krb5_octet *)malloc(inlen);
+ if (tempbuf == (krb5_octet *)NULL)
+ return ENOMEM;
+
+ memset(outbuf, 0, outlen);
+ bytes = 0;
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+ do {
+ int i, j;
+ register unsigned int k;
+
+ if ((bytes % inlen) == 0) {
+ /* Rotate input */
+ k = ((bytes/inlen) * ROTATE_VALUE) % (inlen*8);
+
+ for (j = (k+7)/8; j < inlen + (k/7)/8; j++)
+ tempbuf[j % inlen] =
+ (inbuf[((8*j-k)/8)%inlen] & (((1<<(8-(k&7)))-1) <<(k&7))) +
+ (inbuf[((8*j-k)/8 + 1)%inlen] >> (8-(k&7)));
+ }
+
+
+ i = min(outlen - (bytes % outlen), inlen - (bytes % inlen));
+
+ j = i;
+ k = 0;
+ while (j--) {
+ k = outbuf[(bytes+j) % outlen] + tempbuf[(bytes+j) % inlen] + k;
+ outbuf[(bytes+j) % outlen] = k & 0xff;
+ k >>= 8;
+ }
+
+ j = outlen-1;
+ while (k) {
+ assert(j >= 0);
+ k += outbuf[j];
+ outbuf[j--] = k & 0xff;
+ k >>= 8;
+ }
+
+ bytes += i;
+ } while (((bytes % inlen) == 0) && ((bytes % outlen) == 0));
+
+ return 0;
+}