blob: 31e998f0bcb29e616c1956bdfd86001dc93d4b89 [file] [log] [blame]
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
* Copyright 1997 The Open Group Research Institute. All rights reserved.
*/
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;
//only needed if dataSize() implementation changes back to spec;
//see dataSize() below
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)
// throws Asn1Exception
{
// EncodeRef ref = new EncodeRef(data, startOfData());
// return ref.end - startOfData();
// should be the above according to spec, but in fact
// implementations include the pad bytes in the data size
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;
}
// Note: the first 2 entries of BUILTIN_ETYPES and BUILTIN_ETYPES_NOAES256
// should be kept DES-related. They will be removed when allow_weak_crypto
// is set to false.
private static final int[] BUILTIN_ETYPES = new int[] {
EncryptedData.ETYPE_DES_CBC_MD5,
EncryptedData.ETYPE_DES_CBC_CRC,
EncryptedData.ETYPE_ARCFOUR_HMAC,
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96,
};
private static final int[] BUILTIN_ETYPES_NOAES256 = new int[] {
EncryptedData.ETYPE_DES_CBC_MD5,
EncryptedData.ETYPE_DES_CBC_CRC,
EncryptedData.ETYPE_ARCFOUR_HMAC,
EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
};
// used in Config
public static int[] getBuiltInDefaults() {
int allowed = 0;
try {
allowed = Cipher.getMaxAllowedKeyLength("AES");
} catch (Exception e) {
// should not happen
}
int[] result;
if (allowed < 256) {
result = BUILTIN_ETYPES_NOAES256;
} else {
result = BUILTIN_ETYPES;
}
if (!ALLOW_WEAK_CRYPTO) {
// The first 2 etypes are now weak ones
return Arrays.copyOfRange(result, 2, result.length);
}
return result;
}
/**
* Retrieves the default etypes from the configuration file, or
* if that's not available, return the built-in list of default etypes.
*/
// used in KrbAsReq, KeyTab
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();
}
}
/**
* Retrieve the default etypes from the configuration file for
* those etypes for which there are corresponding keys.
* Used in scenario we have some keys from a keytab with etypes
* different from those named in configName. Then, in order
* to decrypt an AS-REP, we should only ask for etypes for which
* we have keys.
*/
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 + ")";
}
}