package org.apache.kerberos.kerb.crypto.key;
import org.apache.kerberos.kerb.crypto.BytesUtil;
import org.apache.kerberos.kerb.crypto.Cmac;
import org.apache.kerberos.kerb.crypto.Pbkdf;
import org.apache.kerberos.kerb.crypto.enc.provider.CamelliaProvider;
import org.apache.kerberos.kerb.KrbException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
public class CamelliaKeyMaker extends DkKeyMaker {
public CamelliaKeyMaker(CamelliaProvider encProvider) {
super(encProvider);
}
@Override
public byte[] random2Key(byte[] randomBits) throws KrbException {
return randomBits;
}
@Override
public byte[] str2key(String string, String salt, byte[] param) throws KrbException {
int iterCount = getIterCount(param, 32768);
byte[] saltBytes = null;
try {
saltBytes = getSaltBytes(salt, getPepper());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
int keySize = encProvider().keySize();
byte[] random = new byte[0];
try {
random = Pbkdf.PBKDF2(string.toCharArray(), saltBytes, iterCount, keySize);
} catch (GeneralSecurityException e) {
throw new KrbException("PBKDF2 failed", e);
}
byte[] tmpKey = random2Key(random);
byte[] result = dk(tmpKey, KERBEROS_CONSTANT);
return result;
}
private String getPepper() {
int keySize = encProvider().keySize();
String pepper = keySize == 16 ? "camellia128-cts-cmac" : "camellia256-cts-cmac";
return pepper;
}
/*
* NIST SP800-108 KDF in feedback mode (section 5.2).
*/
@Override
protected byte[] dr(byte[] key, byte[] constant) throws KrbException {
int blocksize = encProvider().blockSize();
int keyInuptSize = encProvider().keyInputSize();
byte[] keyBytes = new byte[keyInuptSize];
byte[] Ki;
int len = 0;
// K(i-1): the previous block of PRF output, initially all-zeros.
len += blocksize;
// four-byte big-endian binary string giving the block counter
len += 4;
// the fixed derived-key input
len += constant.length;
// 0x00: separator byte
len += 1;
// four-byte big-endian binary string giving the output length
len += 4;
Ki = new byte[len];
System.arraycopy(constant, 0, Ki, blocksize + 4, constant.length);
BytesUtil.int2bytes(keyInuptSize * 8, Ki, len - 4, true);
int i, n = 0;
byte[] tmp;
for (i = 1, n = 0; n < keyInuptSize; i++) {
// Update the block counter
BytesUtil.int2bytes(i, Ki, blocksize, true);
// Compute a CMAC checksum, update Ki with the result
tmp = Cmac.cmac(encProvider(), key, Ki);
System.arraycopy(tmp, 0, Ki, 0, blocksize);
if (n + blocksize >= keyInuptSize) {
System.arraycopy(Ki, 0, keyBytes, n, keyInuptSize - n);
break;
}
System.arraycopy(Ki, 0, keyBytes, n, blocksize);
n += blocksize;
}
return keyBytes;
}
}