package org.apache.kerberos.kerb.crypto.cksum;
import org.apache.kerberos.kerb.crypto.Confounder;
import org.apache.kerberos.kerb.crypto.enc.provider.DesProvider;
import org.apache.kerberos.kerb.KrbException;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
public abstract class ConfounderedDesCheckSum extends AbstractKeyedCheckSumTypeHandler {
public ConfounderedDesCheckSum(HashProvider hashProvider,
int computeSize, int outputSize) {
super(new DesProvider(), hashProvider, computeSize, outputSize);
}
@Override
protected byte[] doChecksumWithKey(byte[] data, int start, int len,
byte[] key, int usage) throws KrbException {
int computeSize = computeSize();
int blockSize = encProvider().blockSize();
int hashSize = hashProvider().hashSize();
byte[] workBuffer = new byte[computeSize];
// confounder
byte[] conf = Confounder.makeBytes(blockSize);
// confounder | data
byte[] toHash = new byte[blockSize + len];
System.arraycopy(conf, 0, toHash, 0, blockSize);
System.arraycopy(data, start, toHash, blockSize, len);
HashProvider hashProvider = hashProvider();
hashProvider.hash(toHash);
byte[] hash = hashProvider.output();
// confounder | hash
System.arraycopy(conf, 0, workBuffer, 0, blockSize);
System.arraycopy(hash, 0, workBuffer, blockSize, hashSize);
// key
byte[] newKey = deriveKey(key);
encProvider().encrypt(newKey, workBuffer);
return workBuffer;
}
protected byte[] deriveKey(byte[] key) {
return fixKey(xorKey(key));
}
protected byte[] xorKey(byte[] key) {
byte[] xorKey = new byte[encProvider().keySize()];
System.arraycopy(key, 0, xorKey, 0, key.length);
for (int i = 0; i < xorKey.length; i++) {
xorKey[i] = (byte) (xorKey[i] ^ 0xf0);
}
return xorKey;
}
private byte[] fixKey(byte[] key) {
boolean isWeak = true;
try {
isWeak = DESKeySpec.isWeak(key, 0);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
if (isWeak) {
key[7] = (byte)(key[7] ^ 0xF0);
}
return key;
}
@Override
public boolean verifyWithKey(byte[] data,byte[] key,
int usage, byte[] checksum) throws KrbException {
int computeSize = computeSize();
int blockSize = encProvider().blockSize();
int hashSize = hashProvider().hashSize();
// key
byte[] newKey = deriveKey(key);
encProvider().decrypt(newKey, checksum);
byte[] decrypted = checksum; // confounder | hash
// confounder | data
byte[] toHash = new byte[blockSize + data.length];
System.arraycopy(decrypted, 0, toHash, 0, blockSize);
System.arraycopy(data, 0, toHash, blockSize, data.length);
HashProvider hashProvider = hashProvider();
hashProvider.hash(toHash);
byte[] newHash = hashProvider.output();
return checksumEqual(newHash, decrypted, blockSize, hashSize);
}
}