package org.apache.kerberos.kerb.crypto.enc; import org.apache.kerberos.kerb.KrbErrorCode; import org.apache.kerberos.kerb.crypto.BytesUtil; import org.apache.kerberos.kerb.crypto.Confounder; import org.apache.kerberos.kerb.crypto.Rc4; import org.apache.kerberos.kerb.crypto.Hmac; import org.apache.kerberos.kerb.crypto.cksum.provider.Md5Provider; import org.apache.kerberos.kerb.crypto.enc.provider.Rc4Provider; import org.apache.kerberos.kerb.crypto.key.Rc4KeyMaker; import org.apache.kerberos.kerb.KrbException; import org.apache.kerberos.kerb.spec.common.CheckSumType; import org.apache.kerberos.kerb.spec.common.EncryptionType; public class Rc4HmacEnc extends AbstractEncTypeHandler { private boolean exportable; public Rc4HmacEnc() { this(false); } public Rc4HmacEnc(boolean exportable) { super(new Rc4Provider(), new Md5Provider()); keyMaker(new Rc4KeyMaker(this.encProvider())); this.exportable = exportable; } public EncryptionType eType() { return EncryptionType.ARCFOUR_HMAC; } @Override public int confounderSize() { return 8; } @Override public int paddingSize() { return 0; } public CheckSumType checksumType() { return CheckSumType.HMAC_MD5_ARCFOUR; } protected void encryptWith(byte[] workBuffer, int[] workLens, byte[] key, byte[] iv, int usage) throws KrbException { int confounderLen = workLens[0]; int checksumLen = workLens[1]; int dataLen = workLens[2]; /** * Instead of E(Confounder | Checksum | Plaintext | Padding), * Checksum | E(Confounder | Plaintext) */ // confounder byte[] confounder = Confounder.makeBytes(confounderLen); System.arraycopy(confounder, 0, workBuffer, checksumLen, confounderLen); // no padding /* checksum and encryption */ byte[] usageKey = makeUsageKey(key, usage); byte[] checksum = Hmac.hmac(hashProvider(), usageKey, workBuffer, checksumLen, confounderLen + dataLen); byte[] encKey = makeEncKey(usageKey, checksum); byte[] tmpEnc = new byte[confounderLen + dataLen]; System.arraycopy(workBuffer, checksumLen, tmpEnc, 0, confounderLen + dataLen); encProvider().encrypt(encKey, iv, tmpEnc); System.arraycopy(checksum, 0, workBuffer, 0, checksumLen); System.arraycopy(tmpEnc, 0, workBuffer, checksumLen, tmpEnc.length); } protected byte[] makeUsageKey(byte[] key, int usage) throws KrbException { byte[] salt = Rc4.getSalt(usage, exportable); byte[] usageKey = Hmac.hmac(hashProvider(), key, salt); return usageKey; } protected byte[] makeEncKey(byte[] usageKey, byte[] checksum) throws KrbException { byte[] tmpKey = usageKey; if (exportable) { tmpKey = BytesUtil.duplicate(usageKey); for (int i = 0; i < 9; ++i) { tmpKey[i + 7] = (byte) 0xab; } } byte[] encKey = Hmac.hmac(hashProvider(), tmpKey, checksum); return encKey; } @Override protected byte[] decryptWith(byte[] workBuffer, int[] workLens, byte[] key, byte[] iv, int usage) throws KrbException { int confounderLen = workLens[0]; int checksumLen = workLens[1]; int dataLen = workLens[2]; /* checksum and decryption */ byte[] usageKey = makeUsageKey(key, usage); byte[] checksum = new byte[checksumLen]; System.arraycopy(workBuffer, 0, checksum, 0, checksumLen); byte[] encKey = makeEncKey(usageKey, checksum); byte[] tmpEnc = new byte[confounderLen + dataLen]; System.arraycopy(workBuffer, checksumLen, tmpEnc, 0, confounderLen + dataLen); encProvider().decrypt(encKey, iv, tmpEnc); byte[] newChecksum = Hmac.hmac(hashProvider(), usageKey, tmpEnc); if (! checksumEqual(checksum, newChecksum)) { throw new KrbException(KrbErrorCode.KRB_AP_ERR_BAD_INTEGRITY); } byte[] data = new byte[dataLen]; System.arraycopy(tmpEnc, confounderLen, data, 0, dataLen); return data; } }