/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (C) 1998 by the FundsXpress, 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 FundsXpress. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. FundsXpress makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "k5-int.h"
/*
* Solaris Kerberos defines memory management macros in ,
* which is included by , so we need not include
*/
/* #include */
/*
n-fold(k-bits):
l = lcm(n,k)
r = l/k
s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
compute the 1's complement sum:
n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
*/
/* representation: msb first, assume n and k are multiples of 8, and
that k>=16. this is the case of all the cryptosystems which are
likely to be used. this function can be replaced if that
assumption ever fails. */
/* input length is in bits */
void
krb5_nfold(unsigned int inbits, const unsigned char *in, unsigned int outbits,
unsigned char *out)
{
int a,b,c,lcm;
int byte, i, msbit;
/* the code below is more readable if I make these bytes
instead of bits */
inbits >>= 3;
outbits >>= 3;
/* first compute lcm(n,k) */
a = outbits;
b = inbits;
while(b != 0) {
c = b;
b = a%b;
a = c;
}
lcm = outbits*inbits/a;
/* now do the real work */
(void) memset(out, 0, outbits);
byte = 0;
/* this will end up cycling through k lcm(k,n)/k times, which
is correct */
for (i=lcm-1; i>=0; i--) {
/* compute the msbit in k which gets added into this byte */
msbit = (/* first, start with the msbit in the first, unrotated
byte */
((inbits<<3)-1)
/* then, for each byte, shift to the right for each
repetition */
+(((inbits<<3)+13)*(i/inbits))
/* last, pick out the correct byte within that
shifted repetition */
+((inbits-(i%inbits))<<3)
)%(inbits<<3);
/* pull out the byte value itself */
byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
(in[((inbits)-(msbit>>3))%inbits]))
>>((msbit&7)+1))&0xff;
/* do the addition */
byte += out[i%outbits];
out[i%outbits] = byte&0xff;
#if 0
printf("msbit[%d] = %d\tbyte = %02x\tsum = %03x\n", i, msbit,
(((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
(in[((inbits)-(msbit>>3))%inbits]))
>>((msbit&7)+1))&0xff, byte);
#endif
/* keep around the carry bit, if any */
byte >>= 8;
#if 0
printf("carry=%d\n", byte);
#endif
}
/* if there's a carry bit left over, add it back in */
if (byte) {
for (i=outbits-1; i>=0; i--) {
/* do the addition */
byte += out[i];
out[i] = byte&0xff;
/* keep around the carry bit, if any */
byte >>= 8;
}
}
}