package org.apache.kerberos.kerb.crypto.key;
import org.apache.kerberos.kerb.KrbException;
import org.apache.kerberos.kerb.crypto.Des;
import org.apache.kerberos.kerb.crypto.Nfold;
import org.apache.kerberos.kerb.crypto.enc.EncryptProvider;
import java.io.UnsupportedEncodingException;
public class Des3KeyMaker extends DkKeyMaker {
public Des3KeyMaker(EncryptProvider encProvider) {
super(encProvider);
}
@Override
public byte[] str2key(String string, String salt, byte[] param) throws KrbException {
char[] passwdSalt = makePasswdSalt(string, salt);
int keyInputSize = encProvider().keyInputSize();
try {
byte[] utf8Bytes = new String(passwdSalt).getBytes("UTF-8");
byte[] tmpKey = random2Key(Nfold.nfold(utf8Bytes, keyInputSize));
return dk(tmpKey, KERBEROS_CONSTANT);
} catch (UnsupportedEncodingException e) {
throw new KrbException("str2key failed", e);
}
}
@Override
public byte[] random2Key(byte[] randomBits) throws KrbException {
if (randomBits.length != encProvider().keyInputSize()) {
throw new KrbException("Invalid random bits, not of correct bytes size");
}
/**
* Ref. k5_rand2key_des3 in random_to_key.c in MIT krb5
* Take the seven bytes, move them around into the top 7 bits of the
* 8 key bytes, then compute the parity bits. Do this three times.
*/
byte[] key = new byte[encProvider().keySize()];
int nthByte;
int tmp;
for (int i = 0; i < 3; i++) {
System.arraycopy(randomBits, i * 7, key, i * 8, 7);
nthByte = i * 8;
key[nthByte + 7] = (byte) (((key[nthByte + 0] & 1) << 1) |
((key[nthByte + 1] & 1) << 2) |
((key[nthByte + 2] & 1) << 3) |
((key[nthByte + 3] & 1) << 4) |
((key[nthByte + 4] & 1) << 5) |
((key[nthByte + 5] & 1) << 6) |
((key[nthByte + 6] & 1) << 7));
for (int j = 0; j < 8; j++) {
tmp = key[nthByte + j] & 0xfe;
tmp |= (Integer.bitCount(tmp) & 1) ^ 1;
key[nthByte + j] = (byte) tmp;
}
}
for (int i = 0; i < 3; i++) {
Des.fixKey(key, i * 8, 8);
}
return key;
}
}