Triple-DES support routines
authorRichard Basch <probe@mit.edu>
Tue, 28 Nov 1995 01:09:19 +0000 (01:09 +0000)
committerRichard Basch <probe@mit.edu>
Tue, 28 Nov 1995 01:09:19 +0000 (01:09 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7127 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/crypto/des/d3_cbc.c [new file with mode: 0644]
src/lib/crypto/des/d3_ecb.c [new file with mode: 0644]
src/lib/crypto/des/d3_kysched.c [new file with mode: 0644]
src/lib/crypto/des/d3_procky.c [new file with mode: 0644]
src/lib/crypto/des/d3_rndky.c [new file with mode: 0644]
src/lib/crypto/des/d3_str2ky.c [new file with mode: 0644]
src/lib/crypto/des/u_nfold.c [new file with mode: 0644]

diff --git a/src/lib/crypto/des/d3_cbc.c b/src/lib/crypto/des/d3_cbc.c
new file mode 100644 (file)
index 0000000..4509c2e
--- /dev/null
@@ -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 (file)
index 0000000..a51898f
--- /dev/null
@@ -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 (file)
index 0000000..efd91c4
--- /dev/null
@@ -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 (file)
index 0000000..1e50dd9
--- /dev/null
@@ -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 (file)
index 0000000..5edcf4d
--- /dev/null
@@ -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 (file)
index 0000000..5f4d7a0
--- /dev/null
@@ -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 (file)
index 0000000..3dd9199
--- /dev/null
@@ -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;
+}