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.cksum.HashProvider; import org.apache.kerberos.kerb.crypto.key.DkKeyMaker; import org.apache.kerberos.kerb.KrbException; public abstract class KeKiEnc extends AbstractEncTypeHandler { public KeKiEnc(EncryptProvider encProvider, HashProvider hashProvider) { super(encProvider, hashProvider); } @Override public int paddingSize() { return 0; } @Override protected void encryptWith(byte[] workBuffer, int[] workLens, byte[] key, byte[] iv, int usage) throws KrbException { int confounderLen = workLens[0]; int checksumLen = workLens[1]; int inputLen = workLens[2]; int paddingLen = workLens[3]; byte[] Ke, Ki; byte[] constant = new byte[5]; constant[0] = (byte) ((usage>>24)&0xff); constant[1] = (byte) ((usage>>16)&0xff); constant[2] = (byte) ((usage>>8)&0xff); constant[3] = (byte) (usage&0xff); constant[4] = (byte) 0xaa; Ke = ((DkKeyMaker) keyMaker()).dk(key, constant); constant[4] = (byte) 0x55; Ki = ((DkKeyMaker) keyMaker()).dk(key, constant); /** * Instead of E(Confounder | Checksum | Plaintext | Padding), * E(Confounder | Plaintext | Padding) | Checksum, * so need to adjust the workBuffer arrangement */ byte[] tmpEnc = new byte[confounderLen + inputLen + paddingLen]; // confounder byte[] confounder = Confounder.makeBytes(confounderLen); System.arraycopy(confounder, 0, tmpEnc, 0, confounderLen); // data System.arraycopy(workBuffer, confounderLen + checksumLen, tmpEnc, confounderLen, inputLen); // padding for (int i = confounderLen + inputLen; i < paddingLen; ++i) { tmpEnc[i] = 0; } // checksum & encrypt byte[] checksum; checksum = makeChecksum(Ki, tmpEnc, checksumLen); encProvider().encrypt(Ke, iv, tmpEnc); System.arraycopy(tmpEnc, 0, workBuffer, 0, tmpEnc.length); System.arraycopy(checksum, 0, workBuffer, tmpEnc.length, checksum.length); } @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]; byte[] Ke, Ki; byte[] constant = new byte[5]; BytesUtil.int2bytes(usage, constant, 0, true); constant[4] = (byte) 0xaa; Ke = ((DkKeyMaker) keyMaker()).dk(key, constant); constant[4] = (byte) 0x55; Ki = ((DkKeyMaker) keyMaker()).dk(key, constant); // decrypt and verify checksum byte[] tmpEnc = new byte[confounderLen + dataLen]; System.arraycopy(workBuffer, 0, tmpEnc, 0, confounderLen + dataLen); byte[] checksum = new byte[checksumLen]; System.arraycopy(workBuffer, confounderLen + dataLen, checksum, 0, checksumLen); byte[] newChecksum; encProvider().decrypt(Ke, iv, tmpEnc); newChecksum = makeChecksum(Ki, tmpEnc, checksumLen); 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; } protected abstract byte[] makeChecksum(byte[] key, byte[] data, int hashSize) throws KrbException; }