/* * Copyright (c) 2000, 2012, 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 boolean allowWeakCrypto; static { initStatic(); } public static void initStatic() { boolean allowed = false; try { Config cfg = Config.getInstance(); String temp = cfg.get("libdefaults", "allow_weak_crypto"); if (temp != null && temp.equals("true")) allowed = true; } catch (Exception exc) { if (DEBUG) { System.out.println ("Exception in getting allow_weak_crypto, " + "using default value " + exc.getMessage()); } } allowWeakCrypto = 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_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, }; // 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 (!allowWeakCrypto) { // The last 2 etypes are now weak ones return Arrays.copyOfRange(result, 0, result.length - 2); } return result; } /** * Retrieves the default etypes from the configuration file, or * if that's not available, return the built-in list of default etypes. * This result is always non-empty. If no etypes are found, * an exception is thrown. */ public static int[] getDefaults(String configName) throws KrbException { Config config = null; try { config = Config.getInstance(); } catch (KrbException exc) { if (DEBUG) { System.out.println("Exception while getting " + configName + exc.getMessage()); System.out.println("Using default builtin etypes"); } return getBuiltInDefaults(); } return config.defaultEtype(configName); } /** * 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); List list = new ArrayList<>(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 + ")"; } }