package org.apache.kerberos.kerb.crypto;
import java.util.Arrays;
/**
* Based on MIT krb5 nfold.c
*/
/*
* 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]
*/
public class Nfold {
/**
* 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.
*/
public static byte[] nfold(byte[] inBytes, int size) {
int inBytesNum = inBytes.length; // count inBytes byte
int outBytesNum = size; // count inBytes byte
int a, b, c, lcm;
a = outBytesNum;
b = inBytesNum;
while (b != 0) {
c = b;
b = a % b;
a = c;
}
lcm = (outBytesNum * inBytesNum) / a;
byte[] outBytes = new byte[outBytesNum];
Arrays.fill(outBytes, (byte)0);
int tmpByte = 0;
int msbit, i, tmp;
for (i = lcm-1; i >= 0; i--) {
// first, start with the msbit inBytes the first, unrotated byte
tmp = ((inBytesNum<<3)-1);
// then, for each byte, shift to the right for each repetition
tmp += (((inBytesNum<<3)+13)*(i/inBytesNum));
// last, pick outBytes the correct byte within that shifted repetition
tmp += ((inBytesNum-(i%inBytesNum)) << 3);
msbit = tmp % (inBytesNum << 3);
// pull outBytes the byte value itself
tmp = ((((inBytes[((inBytesNum - 1)-(msbit >>> 3)) % inBytesNum] & 0xff) << 8) |
(inBytes[((inBytesNum) - (msbit >>> 3)) % inBytesNum] & 0xff))
>>>((msbit & 7)+1)) & 0xff;
tmpByte += tmp;
tmp = (outBytes[i % outBytesNum] & 0xff);
tmpByte += tmp;
outBytes[i % outBytesNum] = (byte) (tmpByte & 0xff);
tmpByte >>>= 8;
}
// if there's a carry bit left over, add it back inBytes
if (tmpByte != 0) {
for (i = outBytesNum-1; i >= 0; i--) {
// do the addition
tmpByte += (outBytes[i] & 0xff);
outBytes[i] = (byte) (tmpByte & 0xff);
tmpByte >>>= 8;
}
}
return outBytes;
}
}