package sun.security.krb5.internal.crypto;
import sun.security.krb5.internal.*;
import sun.security.krb5.Config;
import sun.security.krb5.EncryptedData;
import sun.security.krb5.EncryptionKey;
import sun.security.krb5.KrbException;
import sun.security.krb5.KrbCryptoException;
import javax.crypto.*;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
public abstract class EType {
private static final boolean DEBUG = Krb5.DEBUG;
private static final boolean ALLOW_WEAK_CRYPTO;
static {
boolean allowed = true;
try {
Config cfg = Config.getInstance();
String temp = cfg.getDefault("allow_weak_crypto", "libdefaults");
if (temp != null && temp.equals("false")) allowed = false;
} catch (Exception exc) {
if (DEBUG) {
System.out.println ("Exception in getting allow_weak_crypto, " +
"using default value " +
exc.getMessage());
}
}
ALLOW_WEAK_CRYPTO = allowed;
}
public static EType getInstance (int eTypeConst)
throws KdcErrException {
EType eType = null;
String eTypeName = null;
switch (eTypeConst) {
case EncryptedData.ETYPE_NULL:
eType = new NullEType();
eTypeName = "sun.security.krb5.internal.crypto.NullEType";
break;
case EncryptedData.ETYPE_DES_CBC_CRC:
eType = new DesCbcCrcEType();
eTypeName = "sun.security.krb5.internal.crypto.DesCbcCrcEType";
break;
case EncryptedData.ETYPE_DES_CBC_MD5:
eType = new DesCbcMd5EType();
eTypeName = "sun.security.krb5.internal.crypto.DesCbcMd5EType";
break;
case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
eType = new Des3CbcHmacSha1KdEType();
eTypeName =
"sun.security.krb5.internal.crypto.Des3CbcHmacSha1KdEType";
break;
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
eType = new Aes128CtsHmacSha1EType();
eTypeName =
"sun.security.krb5.internal.crypto.Aes128CtsHmacSha1EType";
break;
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
eType = new Aes256CtsHmacSha1EType();
eTypeName =
"sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType";
break;
case EncryptedData.ETYPE_ARCFOUR_HMAC:
eType = new ArcFourHmacEType();
eTypeName = "sun.security.krb5.internal.crypto.ArcFourHmacEType";
break;
default:
String msg = "encryption type = " + toString(eTypeConst)
+ " (" + eTypeConst + ")";
throw new KdcErrException(Krb5.KDC_ERR_ETYPE_NOSUPP, msg);
}
if (DEBUG) {
System.out.println(">>> EType: " + eTypeName);
}
return eType;
}
public abstract int eType();
public abstract int minimumPadSize();
public abstract int confounderSize();
public abstract int checksumType();
public abstract int checksumSize();
public abstract int blockSize();
public abstract int keyType();
public abstract int keySize();
public abstract byte[] encrypt(byte[] data, byte[] key, int usage)
throws KrbCryptoException;
public abstract byte[] encrypt(byte[] data, byte[] key, byte[] ivec,
int usage) throws KrbCryptoException;
public abstract byte[] decrypt(byte[] cipher, byte[] key, int usage)
throws KrbApErrException, KrbCryptoException;
public abstract byte[] decrypt(byte[] cipher, byte[] key, byte[] ivec,
int usage) throws KrbApErrException, KrbCryptoException;
public int dataSize(byte[] data)
{
return data.length - startOfData();
}
public int padSize(byte[] data) {
return data.length - confounderSize() - checksumSize() -
dataSize(data);
}
public int startOfChecksum() {
return confounderSize();
}
public int startOfData() {
return confounderSize() + checksumSize();
}
public int startOfPad(byte[] data) {
return confounderSize() + checksumSize() + dataSize(data);
}
public byte[] decryptedData(byte[] data) {
int tempSize = dataSize(data);
byte[] result = new byte[tempSize];
System.arraycopy(data, startOfData(), result, 0, tempSize);
return result;
}
private static final int[] BUILTIN_ETYPES = new int[] {
EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_ARCFOUR_HMAC,
EncryptedData.ETYPE_DES_CBC_CRC,
EncryptedData.ETYPE_DES_CBC_MD5,
};
private static final int[] BUILTIN_ETYPES_NOAES256 = new int[] {
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_ARCFOUR_HMAC,
EncryptedData.ETYPE_DES_CBC_CRC,
EncryptedData.ETYPE_DES_CBC_MD5,
};
public static int[] getBuiltInDefaults() {
int allowed = 0;
try {
allowed = Cipher.getMaxAllowedKeyLength("AES");
} catch (Exception e) {
}
int[] result;
if (allowed < 256) {
result = BUILTIN_ETYPES_NOAES256;
} else {
result = BUILTIN_ETYPES;
}
if (!ALLOW_WEAK_CRYPTO) {
return Arrays.copyOfRange(result, 0, result.length - 2);
}
return result;
}
public static int[] getDefaults(String configName) {
try {
return Config.getInstance().defaultEtype(configName);
} catch (KrbException exc) {
if (DEBUG) {
System.out.println("Exception while getting " +
configName + exc.getMessage());
System.out.println("Using default builtin etypes");
}
return getBuiltInDefaults();
}
}
public static int[] getDefaults(String configName, EncryptionKey[] keys)
throws KrbException {
int[] answer = getDefaults(configName);
if (answer == null) {
throw new KrbException("No supported encryption types listed in "
+ configName);
}
List<Integer> list = new ArrayList<Integer> (answer.length);
for (int i = 0; i < answer.length; i++) {
if (EncryptionKey.findKey(answer[i], keys) != null) {
list.add(answer[i]);
}
}
int len = list.size();
if (len <= 0) {
StringBuffer keystr = new StringBuffer();
for (int i = 0; i < keys.length; i++) {
keystr.append(toString(keys[i].getEType()));
keystr.append(" ");
}
throw new KrbException(
"Do not have keys of types listed in " + configName +
" available; only have keys of following type: " +
keystr.toString());
} else {
answer = new int[len];
for (int i = 0; i < len; i++) {
answer[i] = list.get(i);
}
return answer;
}
}
public static boolean isSupported(int eTypeConst, int[] config) {
for (int i = 0; i < config.length; i++) {
if (eTypeConst == config[i]) {
return true;
}
}
return false;
}
public static boolean isSupported(int eTypeConst) {
int[] enabledETypes = getBuiltInDefaults();
return isSupported(eTypeConst, enabledETypes);
}
public static String toString(int type) {
switch (type) {
case 0:
return "NULL";
case 1:
return "DES CBC mode with CRC-32";
case 2:
return "DES CBC mode with MD4";
case 3:
return "DES CBC mode with MD5";
case 4:
return "reserved";
case 5:
return "DES3 CBC mode with MD5";
case 6:
return "reserved";
case 7:
return "DES3 CBC mode with SHA1";
case 9:
return "DSA with SHA1- Cms0ID";
case 10:
return "MD5 with RSA encryption - Cms0ID";
case 11:
return "SHA1 with RSA encryption - Cms0ID";
case 12:
return "RC2 CBC mode with Env0ID";
case 13:
return "RSA encryption with Env0ID";
case 14:
return "RSAES-0AEP-ENV-0ID";
case 15:
return "DES-EDE3-CBC-ENV-0ID";
case 16:
return "DES3 CBC mode with SHA1-KD";
case 17:
return "AES128 CTS mode with HMAC SHA1-96";
case 18:
return "AES256 CTS mode with HMAC SHA1-96";
case 23:
return "RC4 with HMAC";
case 24:
return "RC4 with HMAC EXP";
}
return "Unknown (" + type + ")";
}
}