1503 lines · 55.0 KB · Java
RawDownload
/* * Copyright (c) 2004, 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. */ package sun.security.jgss.krb5; import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import javax.crypto.CipherInputStream;import javax.crypto.CipherOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;import org.ietf.jgss.*; import java.security.MessageDigest;import java.security.GeneralSecurityException;import java.security.NoSuchAlgorithmException;import sun.security.krb5.*;import sun.security.krb5.internal.crypto.Des3;import sun.security.krb5.internal.crypto.Aes128;import sun.security.krb5.internal.crypto.Aes256;import sun.security.krb5.internal.crypto.ArcFourHmac; class CipherHelper {     // From draft-raeburn-cat-gssapi-krb5-3des-00    // Key usage values when deriving keys    private static final int KG_USAGE_SEAL = 22;    private static final int KG_USAGE_SIGN = 23;    private static final int KG_USAGE_SEQ = 24;     private static final int DES_CHECKSUM_SIZE = 8;    private static final int DES_IV_SIZE = 8;    private static final int AES_IV_SIZE = 16;     // ARCFOUR-HMAC    // Save first 8 octets of HMAC Sgn_Cksum    private static final int HMAC_CHECKSUM_SIZE = 8;    // key usage for MIC tokens used by MS    private static final int KG_USAGE_SIGN_MS = 15;     // debug flag    private static final boolean DEBUG = Krb5Util.DEBUG;     /**     * A zero initial vector to be used for checksum calculation and for     * DesCbc application data encryption/decryption.     */    private static final byte[] ZERO_IV = new byte[DES_IV_SIZE];    private static final byte[] ZERO_IV_AES = new byte[AES_IV_SIZE];     private int etype;    private int sgnAlg, sealAlg;    private byte[] keybytes;     // new token format from draft-ietf-krb-wg-gssapi-cfx-07    // proto is used to determine new GSS token format for "newer" etypes    private int proto = 0;     CipherHelper(EncryptionKey key) throws GSSException {        etype = key.getEType();        keybytes = key.getBytes();         switch (etype) {        case EncryptedData.ETYPE_DES_CBC_CRC:        case EncryptedData.ETYPE_DES_CBC_MD5:            sgnAlg = MessageToken.SGN_ALG_DES_MAC_MD5;            sealAlg = MessageToken.SEAL_ALG_DES;            break;         case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:            sgnAlg = MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD;            sealAlg = MessageToken.SEAL_ALG_DES3_KD;            break;         case EncryptedData.ETYPE_ARCFOUR_HMAC:            sgnAlg = MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR;            sealAlg = MessageToken.SEAL_ALG_ARCFOUR_HMAC;            break;         case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:        case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:            sgnAlg = -1;            sealAlg = -1;            proto = 1;            break;         default:            throw new GSSException(GSSException.FAILURE, -1,                "Unsupported encryption type: " + etype);        }    }     int getSgnAlg() {        return sgnAlg;    }     int getSealAlg() {        return sealAlg;    }     int getProto() {        return proto;    }     int getEType() {        return etype;    }     boolean isArcFour() {        boolean flag = false;        if (etype == EncryptedData.ETYPE_ARCFOUR_HMAC) {            flag = true;        }        return flag;    }     byte[] calculateChecksum(int alg, byte[] header, byte[] trailer,        byte[] data, int start, int len, int tokenId) throws GSSException {         switch (alg) {        case MessageToken.SGN_ALG_DES_MAC_MD5:            /*             * With this sign algorithm, first an MD5 hash is computed on the             * application data. The 16 byte hash is then DesCbc encrypted.             */            try {                MessageDigest md5 = MessageDigest.getInstance("MD5");                 // debug("\t\tdata=[");                 // debug(getHexBytes(checksumDataHeader,                //                      checksumDataHeader.length) + " ");                md5.update(header);                 // debug(getHexBytes(data, start, len));                md5.update(data, start, len);                 if (trailer != null) {                    // debug(" " +                    //       getHexBytes(trailer,                    //                     optionalTrailer.length));                    md5.update(trailer);                }                //          debug("]\n");                 data = md5.digest();                start = 0;                len = data.length;                //          System.out.println("\tMD5 Checksum is [" +                //                             getHexBytes(data) + "]\n");                header = null;                trailer = null;            } catch (NoSuchAlgorithmException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not get MD5 Message Digest - " + e.getMessage());                ge.initCause(e);                throw ge;            }            // fall through to encrypt checksum         case MessageToken.SGN_ALG_DES_MAC:            return getDesCbcChecksum(keybytes, header, data, start, len);         case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:            byte[] buf;            int offset, total;            if (header == null && trailer == null) {                buf = data;                total = len;                offset = start;            } else {                total = ((header != null ? header.length : 0) + len +                    (trailer != null ? trailer.length : 0));                 buf = new byte[total];                int pos = 0;                if (header != null) {                    System.arraycopy(header, 0, buf, 0, header.length);                    pos = header.length;                }                System.arraycopy(data, start, buf, pos, len);                pos += len;                if (trailer != null) {                    System.arraycopy(trailer, 0, buf, pos, trailer.length);                }                 offset = 0;            }             try {                 /*                Krb5Token.debug("\nkeybytes: " +                    Krb5Token.getHexBytes(keybytes));                Krb5Token.debug("\nheader: " + (header == null ? "NONE" :                    Krb5Token.getHexBytes(header)));                Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :                    Krb5Token.getHexBytes(trailer)));                Krb5Token.debug("\ndata: " +                    Krb5Token.getHexBytes(data, start, len));                Krb5Token.debug("\nbuf: " + Krb5Token.getHexBytes(buf, offset,                    total));                */                 byte[] answer = Des3.calculateChecksum(keybytes,                    KG_USAGE_SIGN, buf, offset, total);                // Krb5Token.debug("\nanswer: " +                //              Krb5Token.getHexBytes(answer));                return answer;            } catch (GeneralSecurityException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not use HMAC-SHA1-DES3-KD signing algorithm - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:            byte[] buffer;            int off, tot;            if (header == null && trailer == null) {                buffer = data;                tot = len;                off = start;            } else {                tot = ((header != null ? header.length : 0) + len +                      (trailer != null ? trailer.length : 0));                 buffer = new byte[tot];                int pos = 0;                 if (header != null) {                    System.arraycopy(header, 0, buffer, 0, header.length);                    pos = header.length;                }                System.arraycopy(data, start, buffer, pos, len);                pos += len;                if (trailer != null) {                    System.arraycopy(trailer, 0, buffer, pos, trailer.length);                }                 off = 0;            }             try {                 /*                Krb5Token.debug("\nkeybytes: " +                    Krb5Token.getHexBytes(keybytes));                Krb5Token.debug("\nheader: " + (header == null ? "NONE" :                    Krb5Token.getHexBytes(header)));                Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :                    Krb5Token.getHexBytes(trailer)));                Krb5Token.debug("\ndata: " +                    Krb5Token.getHexBytes(data, start, len));                Krb5Token.debug("\nbuffer: " +                    Krb5Token.getHexBytes(buffer, off, tot));                */                 // for MIC tokens, key derivation salt is 15                // NOTE: Required for interoperability. The RC4-HMAC spec                // defines key_usage of 23, however all Kerberos impl.                // MS/Solaris/MIT all use key_usage of 15 for MIC tokens                int key_usage = KG_USAGE_SIGN;                if (tokenId == Krb5Token.MIC_ID) {                        key_usage = KG_USAGE_SIGN_MS;                }                byte[] answer = ArcFourHmac.calculateChecksum(keybytes,                    key_usage, buffer, off, tot);                // Krb5Token.debug("\nanswer: " +                //      Krb5Token.getHexBytes(answer));                 // Save first 8 octets of HMAC Sgn_Cksum                byte[] output = new byte[getChecksumLength()];                System.arraycopy(answer, 0, output, 0, output.length);                // Krb5Token.debug("\nanswer (trimmed): " +                //              Krb5Token.getHexBytes(output));                return output;            } catch (GeneralSecurityException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not use HMAC_MD5_ARCFOUR signing algorithm - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         default:            throw new GSSException(GSSException.FAILURE, -1,                "Unsupported signing algorithm: " + sgnAlg);        }    }     // calculate Checksum for the new GSS tokens    byte[] calculateChecksum(byte[] header, byte[] data, int start, int len,        int key_usage) throws GSSException {         // total length        int total = ((header != null ? header.length : 0) + len);         // get_mic("plaintext-data" | "header")        byte[] buf = new byte[total];         // data        System.arraycopy(data, start, buf, 0, len);         // token header        if (header != null) {            System.arraycopy(header, 0, buf, len, header.length);        }         // Krb5Token.debug("\nAES calculate checksum on: " +        //              Krb5Token.getHexBytes(buf));        switch (etype) {        case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:            try {                byte[] answer = Aes128.calculateChecksum(keybytes, key_usage,                                        buf, 0, total);                // Krb5Token.debug("\nAES128 checksum: " +                //                      Krb5Token.getHexBytes(answer));                return answer;            } catch (GeneralSecurityException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not use AES128 signing algorithm - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:            try {                byte[] answer = Aes256.calculateChecksum(keybytes, key_usage,                                        buf, 0, total);                // Krb5Token.debug("\nAES256 checksum: " +                //              Krb5Token.getHexBytes(answer));                return answer;            } catch (GeneralSecurityException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not use AES256 signing algorithm - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         default:            throw new GSSException(GSSException.FAILURE, -1,                "Unsupported encryption type: " + etype);        }    }     byte[] encryptSeq(byte[] ivec, byte[] plaintext, int start, int len)    throws GSSException {         switch (sgnAlg) {        case MessageToken.SGN_ALG_DES_MAC_MD5:        case MessageToken.SGN_ALG_DES_MAC:            try {                Cipher des = getInitializedDes(true, keybytes, ivec);                return des.doFinal(plaintext, start, len);             } catch (GeneralSecurityException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not encrypt sequence number using DES - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:            byte[] iv;            if (ivec.length == DES_IV_SIZE) {                iv = ivec;            } else {                iv = new byte[DES_IV_SIZE];                System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);            }            try {                return Des3.encryptRaw(keybytes, KG_USAGE_SEQ, iv,                    plaintext, start, len);            } catch (Exception e) {                // GeneralSecurityException, KrbCryptoException                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not encrypt sequence number using DES3-KD - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:            // ivec passed is the checksum            byte[] checksum;            if (ivec.length == HMAC_CHECKSUM_SIZE) {                checksum = ivec;            } else {                checksum = new byte[HMAC_CHECKSUM_SIZE];                System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);            }             try {                return ArcFourHmac.encryptSeq(keybytes, KG_USAGE_SEQ, checksum,                    plaintext, start, len);            } catch (Exception e) {                // GeneralSecurityException, KrbCryptoException                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not encrypt sequence number using RC4-HMAC - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         default:            throw new GSSException(GSSException.FAILURE, -1,                "Unsupported signing algorithm: " + sgnAlg);        }    }     byte[] decryptSeq(byte[] ivec, byte[] ciphertext, int start, int len)        throws GSSException {         switch (sgnAlg) {        case MessageToken.SGN_ALG_DES_MAC_MD5:        case MessageToken.SGN_ALG_DES_MAC:            try {                Cipher des = getInitializedDes(false, keybytes, ivec);                return des.doFinal(ciphertext, start, len);            } catch (GeneralSecurityException e) {                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not decrypt sequence number using DES - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:            byte[] iv;            if (ivec.length == DES_IV_SIZE) {                iv = ivec;            } else {                iv = new byte[8];                System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);            }             try {                return Des3.decryptRaw(keybytes, KG_USAGE_SEQ, iv,                    ciphertext, start, len);            } catch (Exception e) {                // GeneralSecurityException, KrbCryptoException                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not decrypt sequence number using DES3-KD - " +                    e.getMessage());                ge.initCause(e);                throw ge;            }         case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:            // ivec passed is the checksum            byte[] checksum;            if (ivec.length == HMAC_CHECKSUM_SIZE) {                checksum = ivec;            } else {                checksum = new byte[HMAC_CHECKSUM_SIZE];                System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);            }             try {                return ArcFourHmac.decryptSeq(keybytes, KG_USAGE_SEQ, checksum,                    ciphertext, start, len);            } catch (Exception e) {                // GeneralSecurityException, KrbCryptoException                GSSException ge = new GSSException(GSSException.FAILURE, -1,                    "Could not decrypt sequence number using RC4-HMAC - " +                    e.getMessage());                ge.initCause(e);                throw ge;            } 

Lines 1–500 of 1503.