JDK 11 java.security.jgss.jmod - Security JGSS Module

JDK 11 java.security.jgss.jmod is the JMOD file for JDK 11 Security JGSS (Java Generic Security Service) module.

JDK 11 Security JGSS module compiled class files are stored in \fyicenter\jdk-11.0.1\jmods\java.security.jgss.jmod.

JDK 11 Security JGSS module compiled class files are also linked and stored in the \fyicenter\jdk-11.0.1\lib\modules JImage file.

JDK 11 Security JGSS module source code files are stored in \fyicenter\jdk-11.0.1\lib\src.zip\java.security.jgss.

You can click and view the content of each source code file in the list below.

✍: FYIcenter

sun/security/jgss/krb5/CipherHelper.java

/*
 * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

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.Aes128Sha2;
import sun.security.krb5.internal.crypto.Aes256Sha2;
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;
import sun.security.krb5.internal.crypto.EType;

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;

    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:
        case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
        case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
            sgnAlg = -1;
            sealAlg = -1;
            break;

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported encryption type: " + etype);
        }
    }

    int getSgnAlg() {
        return sgnAlg;
    }

    int getSealAlg() {
        return sealAlg;
    }

    // new token format from draft-ietf-krb-wg-gssapi-cfx-07
    // proto is used to determine new GSS token format for "newer" etypes
    int getProto() {
        return EType.isNewer(etype) ? 1 : 0;
    }

    int getEType() {
        return etype;
    }

    boolean isArcFour() {
        boolean flag = false;
        if (etype == EncryptedData.ETYPE_ARCFOUR_HMAC) {
            flag = true;
        }
        return flag;
    }

    @SuppressWarnings("fallthrough")
    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;
            }

        case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
            try {
                byte[] answer = Aes128Sha2.calculateChecksum(keybytes, key_usage,
                        buf, 0, total);
                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_SHA384_192:
            try {
                byte[] answer = Aes256Sha2.calculateChecksum(keybytes, key_usage,
                        buf, 0, total);
                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;
            }

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported signing algorithm: " + sgnAlg);
        }
    }

    int getChecksumLength() throws GSSException {
        switch (etype) {
        case EncryptedData.ETYPE_DES_CBC_CRC:
        case EncryptedData.ETYPE_DES_CBC_MD5:
            return DES_CHECKSUM_SIZE;

        case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
            return Des3.getChecksumLength();

        case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
            return Aes128.getChecksumLength();
        case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
            return Aes256.getChecksumLength();

        case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
            return Aes128Sha2.getChecksumLength();
        case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
            return Aes256Sha2.getChecksumLength();

        case EncryptedData.ETYPE_ARCFOUR_HMAC:
            // only first 8 octets of HMAC Sgn_Cksum are used
            return HMAC_CHECKSUM_SIZE;

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported encryption type: " + etype);
        }
    }

    void decryptData(WrapToken token, byte[] ciphertext, int cStart, int cLen,
        byte[] plaintext, int pStart) throws GSSException {

        /*
        Krb5Token.debug("decryptData : ciphertext =  " +
                Krb5Token.getHexBytes(ciphertext));
        */

        switch (sealAlg) {
        case MessageToken.SEAL_ALG_DES:
            desCbcDecrypt(token, getDesEncryptionKey(keybytes),
                ciphertext, cStart, cLen, plaintext, pStart);
            break;

        case MessageToken.SEAL_ALG_DES3_KD:
            des3KdDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);
            break;

        case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
            arcFourDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);
            break;

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported seal algorithm: " + sealAlg);
        }
    }

    // decrypt data in the new GSS tokens
    void decryptData(WrapToken_v2 token, byte[] ciphertext, int cStart,
                int cLen, byte[] plaintext, int pStart, int key_usage)
        throws GSSException {

        /*
        Krb5Token.debug("decryptData : ciphertext =  " +
                Krb5Token.getHexBytes(ciphertext));
        */

        switch (etype) {
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
                    aes128Decrypt(token, ciphertext, cStart, cLen,
                                plaintext, pStart, key_usage);
                    break;
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
                    aes256Decrypt(token, ciphertext, cStart, cLen,
                                plaintext, pStart, key_usage);
                    break;
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
                    aes128Sha2Decrypt(token, ciphertext, cStart, cLen,
                            plaintext, pStart, key_usage);
                    break;
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
                    aes256Sha2Decrypt(token, ciphertext, cStart, cLen,
                            plaintext, pStart, key_usage);
                    break;
            default:
                    throw new GSSException(GSSException.FAILURE, -1,
                        "Unsupported etype: " + etype);
            }
    }

    void decryptData(WrapToken token, InputStream cipherStream, int cLen,
        byte[] plaintext, int pStart)
        throws GSSException, IOException {

        switch (sealAlg) {
        case MessageToken.SEAL_ALG_DES:
            desCbcDecrypt(token, getDesEncryptionKey(keybytes),
                cipherStream, cLen, plaintext, pStart);
            break;

        case MessageToken.SEAL_ALG_DES3_KD:

            // Read encrypted data from stream
            byte[] ciphertext = new byte[cLen];
            try {
                Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);
            } catch (IOException e) {
                GSSException ge = new GSSException(
                    GSSException.DEFECTIVE_TOKEN, -1,
                    "Cannot read complete token");
                ge.initCause(e);
                throw ge;
            }

            des3KdDecrypt(token, ciphertext, 0, cLen, plaintext, pStart);
            break;

        case MessageToken.SEAL_ALG_ARCFOUR_HMAC:

            // Read encrypted data from stream
            byte[] ctext = new byte[cLen];
            try {
                Krb5Token.readFully(cipherStream, ctext, 0, cLen);
            } catch (IOException e) {
                GSSException ge = new GSSException(
                    GSSException.DEFECTIVE_TOKEN, -1,
                    "Cannot read complete token");
                ge.initCause(e);
                throw ge;
            }

            arcFourDecrypt(token, ctext, 0, cLen, plaintext, pStart);
            break;

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported seal algorithm: " + sealAlg);
        }
    }

    void decryptData(WrapToken_v2 token, InputStream cipherStream, int cLen,
        byte[] plaintext, int pStart, int key_usage)
        throws GSSException, IOException {

        // Read encrypted data from stream
        byte[] ciphertext = new byte[cLen];
        try {
                Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);
        } catch (IOException e) {
                GSSException ge = new GSSException(
                    GSSException.DEFECTIVE_TOKEN, -1,
                    "Cannot read complete token");
                ge.initCause(e);
                throw ge;
        }
        switch (etype) {
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
                    aes128Decrypt(token, ciphertext, 0, cLen,
                                plaintext, pStart, key_usage);
                    break;
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
                    aes256Decrypt(token, ciphertext, 0, cLen,
                                plaintext, pStart, key_usage);
                    break;
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
                    aes128Sha2Decrypt(token, ciphertext, 0, cLen,
                            plaintext, pStart, key_usage);
                    break;
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
                    aes256Sha2Decrypt(token, ciphertext, 0, cLen,
                            plaintext, pStart, key_usage);
                    break;
            default:
                    throw new GSSException(GSSException.FAILURE, -1,
                        "Unsupported etype: " + etype);
        }
    }

    void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,
        int start, int len, byte[] padding, OutputStream os)
        throws GSSException, IOException {

        switch (sealAlg) {
        case MessageToken.SEAL_ALG_DES:
            // Encrypt on the fly and write
            Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),
                ZERO_IV);
            CipherOutputStream cos = new CipherOutputStream(os, des);
            // debug(getHexBytes(confounder, confounder.length));
            cos.write(confounder);
            // debug(" " + getHexBytes(plaintext, start, len));
            cos.write(plaintext, start, len);
            // debug(" " + getHexBytes(padding, padding.length));
            cos.write(padding);
            break;

        case MessageToken.SEAL_ALG_DES3_KD:
            byte[] ctext = des3KdEncrypt(confounder, plaintext, start, len,
                padding);

            // Write to stream
            os.write(ctext);
            break;

        case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
            byte[] ciphertext = arcFourEncrypt(token, confounder, plaintext,
                start, len, padding);

            // Write to stream
            os.write(ciphertext);
            break;

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported seal algorithm: " + sealAlg);
        }
    }

    /*
     * Encrypt data in the new GSS tokens
     *
     * Wrap Tokens (with confidentiality)
     * { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |
     *           12-byte HMAC }
     * where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}
     * HMAC is not encrypted; it is appended at the end.
     */
    byte[] encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
            byte[] plaintext, int start, int len, int key_usage)
            throws GSSException {

        switch (etype) {
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
                return aes128Encrypt(confounder, tokenHeader,
                            plaintext, start, len, key_usage);
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
                return aes256Encrypt(confounder, tokenHeader,
                            plaintext, start, len, key_usage);
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
                return aes128Sha2Encrypt(confounder, tokenHeader,
                        plaintext, start, len, key_usage);
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
                return aes256Sha2Encrypt(confounder, tokenHeader,
                        plaintext, start, len, key_usage);
            default:
                throw new GSSException(GSSException.FAILURE, -1,
                    "Unsupported etype: " + etype);
        }
    }

    void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,
        int pStart, int pLen, byte[] padding, byte[] ciphertext, int cStart)
        throws GSSException {

        switch (sealAlg) {
        case MessageToken.SEAL_ALG_DES:
            int pos = cStart;
            // Encrypt and write
            Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),
                ZERO_IV);
            try {
                // debug(getHexBytes(confounder, confounder.length));
                pos += des.update(confounder, 0, confounder.length,
                                  ciphertext, pos);
                // debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
                pos += des.update(plaintext, pStart, pLen,
                                  ciphertext, pos);
                // debug(" " + getHexBytes(padding, padding.length));
                des.update(padding, 0, padding.length,
                           ciphertext, pos);
                des.doFinal();
            } catch (GeneralSecurityException e) {
                GSSException ge = new GSSException(GSSException.FAILURE, -1,
                    "Could not use DES Cipher - " + e.getMessage());
                ge.initCause(e);
                throw ge;
            }
            break;

        case MessageToken.SEAL_ALG_DES3_KD:
            byte[] ctext = des3KdEncrypt(confounder, plaintext, pStart, pLen,
                padding);
            System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);
            break;

        case MessageToken.SEAL_ALG_ARCFOUR_HMAC:
            byte[] ctext2 = arcFourEncrypt(token, confounder, plaintext, pStart,
                pLen, padding);
            System.arraycopy(ctext2, 0, ciphertext, cStart, ctext2.length);
            break;

        default:
            throw new GSSException(GSSException.FAILURE, -1,
                "Unsupported seal algorithm: " + sealAlg);
        }
    }

    /*
     * Encrypt data in the new GSS tokens
     *
     * Wrap Tokens (with confidentiality)
     * { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |
     *           12-byte HMAC }
     * where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}
     * HMAC is not encrypted; it is appended at the end.
     */
    int encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,
        byte[] plaintext, int pStart, int pLen, byte[] ciphertext, int cStart,
        int key_usage) throws GSSException {

        byte[] ctext = null;
        switch (etype) {
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
                    ctext = aes128Encrypt(confounder, tokenHeader,
                                plaintext, pStart, pLen, key_usage);
                    break;
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
                    ctext = aes256Encrypt(confounder, tokenHeader,
                                plaintext, pStart, pLen, key_usage);
                    break;
            case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:
                    ctext = aes128Sha2Encrypt(confounder, tokenHeader,
                            plaintext, pStart, pLen, key_usage);
                    break;
            case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:
                    ctext = aes256Sha2Encrypt(confounder, tokenHeader,
                            plaintext, pStart, pLen, key_usage);
                    break;
            default:
                    throw new GSSException(GSSException.FAILURE, -1,
                        "Unsupported etype: " + etype);
        }
        System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);
        return ctext.length;
    }

    // --------------------- DES methods

    /**
     * Computes the DesCbc checksum based on the algorithm published in FIPS
     * Publication 113. This involves applying padding to the data passed
     * in, then performing DesCbc encryption on the data with a zero initial
     * vector, and finally returning the last 8 bytes of the encryption
     * result.
     *
     * @param key the bytes for the DES key
     * @param header a header to process first before the data is.
     * @param data the data to checksum
     * @param offset the offset where the data begins
     * @param len the length of the data
     * @throws GSSException when an error occuse in the encryption
     */
    private byte[] getDesCbcChecksum(byte key[],
                                     byte[] header,
                                     byte[] data, int offset, int len)
        throws GSSException {

        Cipher des = getInitializedDes(true, key, ZERO_IV);

        int blockSize = des.getBlockSize();

        /*
         * Here the data need not be a multiple of the blocksize
         * (8). Encrypt and throw away results for all blocks except for
         * the very last block.
         */

        byte[] finalBlock = new byte[blockSize];

        int numBlocks = len / blockSize;
        int lastBytes = len % blockSize;
        if (lastBytes == 0) {
            // No need for padding. Save last block from application data
            numBlocks -= 1;
            System.arraycopy(data, offset + numBlocks*blockSize,
                             finalBlock, 0, blockSize);
        } else {
            System.arraycopy(data, offset + numBlocks*blockSize,
                             finalBlock, 0, lastBytes);
            // Zero padding automatically done
        }

        try {
            byte[] temp = new byte[Math.max(blockSize,
                (header == null? blockSize : header.length))];

            if (header != null) {
                // header will be null when doing DES-MD5 Checksum
                des.update(header, 0, header.length, temp, 0);
            }

            // Iterate over all but the last block
            for (int i = 0; i < numBlocks; i++) {
                des.update(data, offset, blockSize,
                           temp, 0);
                offset += blockSize;
            }

            // Now process the final block
            byte[] retVal = new byte[blockSize];
            des.update(finalBlock, 0, blockSize, retVal, 0);
            des.doFinal();

            return retVal;
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use DES Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    /**
     * Obtains an initialized DES cipher.
     *
     * @param encryptMode true if encryption is desired, false is decryption
     * is desired.
     * @param key the bytes for the DES key
     * @param ivBytes the initial vector bytes
     */
    private final Cipher getInitializedDes(boolean encryptMode, byte[] key,
                                          byte[] ivBytes)
        throws  GSSException  {


        try {
            IvParameterSpec iv = new IvParameterSpec(ivBytes);
            SecretKey jceKey = (SecretKey) (new SecretKeySpec(key, "DES"));

            Cipher desCipher = Cipher.getInstance("DES/CBC/NoPadding");
            desCipher.init(
                (encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),
                jceKey, iv);
            return desCipher;
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    /**
     * Helper routine to decrypt fromm a byte array and write the
     * application data straight to an output array with minimal
     * buffer copies. The confounder and the padding are stored
     * separately and not copied into this output array.
     * @param key the DES key to use
     * @param cipherText the encrypted data
     * @param offset the offset for the encrypted data
     * @param len the length of the encrypted data
     * @param dataOutBuf the output buffer where the application data
     * should be writte
     * @param dataOffset the offser where the application data should
     * be written.
     * @throws GSSException is an error occurs while decrypting the
     * data
     */
    private void desCbcDecrypt(WrapToken token, byte[] key, byte[] cipherText,
        int offset, int len, byte[] dataOutBuf, int dataOffset)
         throws GSSException {

        try {

            int temp = 0;

            Cipher des = getInitializedDes(false, key, ZERO_IV);

            /*
             * Remove the counfounder first.
             * CONFOUNDER_SIZE is one DES block ie 8 bytes.
             */
            temp = des.update(cipherText, offset, WrapToken.CONFOUNDER_SIZE,
                              token.confounder);
            // temp should be CONFOUNDER_SIZE
            // debug("\n\ttemp is " + temp + " and CONFOUNDER_SIZE is "
            //  + CONFOUNDER_SIZE);

            offset += WrapToken.CONFOUNDER_SIZE;
            len -= WrapToken.CONFOUNDER_SIZE;

            /*
             * len is a multiple of 8 due to padding.
             * Decrypt all blocks directly into the output buffer except for
             * the very last block. Remove the trailing padding bytes from the
             * very last block and copy that into the output buffer.
             */

            int blockSize = des.getBlockSize();
            int numBlocks = len / blockSize - 1;

            // Iterate over all but the last block
            for (int i = 0; i < numBlocks; i++) {
                temp = des.update(cipherText, offset, blockSize,
                                  dataOutBuf, dataOffset);
                // temp should be blockSize
                // debug("\n\ttemp is " + temp + " and blockSize is "
                //    + blockSize);

                offset += blockSize;
                dataOffset += blockSize;
            }

            // Now process the last block
            byte[] finalBlock = new byte[blockSize];
            des.update(cipherText, offset, blockSize, finalBlock);

            des.doFinal();

            /*
             * There is always at least one padding byte. The padding bytes
             * are all the value of the number of padding bytes.
             */

            int padSize = finalBlock[blockSize - 1];
            if (padSize < 1  || padSize > 8)
                throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
                                        "Invalid padding on Wrap Token");
            token.padding = WrapToken.pads[padSize];
            blockSize -= padSize;

            // Copy this last block into the output buffer
            System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,
                             blockSize);

        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use DES cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    /**
     * Helper routine to decrypt from an InputStream and write the
     * application data straight to an output array with minimal
     * buffer copies. The confounder and the padding are stored
     * separately and not copied into this output array.
     * @param key the DES key to use
     * @param is the InputStream from which the cipher text should be
     * read
     * @param len the length of the ciphertext data
     * @param dataOutBuf the output buffer where the application data
     * should be writte
     * @param dataOffset the offser where the application data should
     * be written.
     * @throws GSSException is an error occurs while decrypting the
     * data
     */
    private void desCbcDecrypt(WrapToken token, byte[] key,
        InputStream is, int len, byte[] dataOutBuf, int dataOffset)
        throws GSSException, IOException {

        int temp = 0;

        Cipher des = getInitializedDes(false, key, ZERO_IV);

        WrapTokenInputStream truncatedInputStream =
            new WrapTokenInputStream(is, len);
        CipherInputStream cis = new CipherInputStream(truncatedInputStream,
                                                      des);
        /*
         * Remove the counfounder first.
         * CONFOUNDER_SIZE is one DES block ie 8 bytes.
         */
        temp = cis.read(token.confounder);

        len -= temp;
        // temp should be CONFOUNDER_SIZE
        // debug("Got " + temp + " bytes; CONFOUNDER_SIZE is "
        //     + CONFOUNDER_SIZE + "\n");
        // debug("Confounder is " + getHexBytes(confounder) + "\n");


        /*
         * len is a multiple of 8 due to padding.
         * Decrypt all blocks directly into the output buffer except for
         * the very last block. Remove the trailing padding bytes from the
         * very last block and copy that into the output buffer.
         */

        int blockSize = des.getBlockSize();
        int numBlocks = len / blockSize - 1;

        // Iterate over all but the last block
        for (int i = 0; i < numBlocks; i++) {
            // debug("dataOffset is " + dataOffset + "\n");
            temp = cis.read(dataOutBuf, dataOffset, blockSize);

            // temp should be blockSize
            // debug("Got " + temp + " bytes and blockSize is "
            //    + blockSize + "\n");
            // debug("Bytes are: "
            //    + getHexBytes(dataOutBuf, dataOffset, temp) + "\n");
            dataOffset += blockSize;
        }

        // Now process the last block
        byte[] finalBlock = new byte[blockSize];
        // debug("Will call read on finalBlock" + "\n");
        temp = cis.read(finalBlock);
        // temp should be blockSize
        /*
          debug("Got " + temp + " bytes and blockSize is "
          + blockSize + "\n");
          debug("Bytes are: "
          + getHexBytes(finalBlock, 0, temp) + "\n");
          debug("Will call doFinal" + "\n");
        */
        try {
            des.doFinal();
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use DES cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
         * There is always at least one padding byte. The padding bytes
         * are all the value of the number of padding bytes.
         */

        int padSize = finalBlock[blockSize - 1];
        if (padSize < 1  || padSize > 8)
            throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
                                   "Invalid padding on Wrap Token");
        token.padding = WrapToken.pads[padSize];
        blockSize -= padSize;

        // Copy this last block into the output buffer
        System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,
                         blockSize);
    }

    private static byte[] getDesEncryptionKey(byte[] key)
        throws GSSException {

        /*
         * To meet export control requirements, double check that the
         * key being used is no longer than 64 bits.
         *
         * Note that from a protocol point of view, an
         * algorithm that is not DES will be rejected before this
         * point. Also, a DES key that is not 64 bits will be
         * rejected by a good JCE provider.
         */
        if (key.length > 8)
            throw new GSSException(GSSException.FAILURE, -100,
                                   "Invalid DES Key!");

        byte[] retVal = new byte[key.length];
        for (int i = 0; i < key.length; i++)
            retVal[i] = (byte)(key[i] ^ 0xf0);  // RFC 1964, Section 1.2.2
        return retVal;
    }

    // ---- DES3-KD methods
    private void des3KdDecrypt(WrapToken token, byte[] ciphertext,
        int cStart, int cLen, byte[] plaintext, int pStart)
        throws GSSException {
        byte[] ptext;
        try {
            ptext = Des3.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,
                ciphertext, cStart, cLen);
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use DES3-KD Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
        Krb5Token.debug("\ndes3KdDecrypt in: " +
            Krb5Token.getHexBytes(ciphertext, cStart, cLen));
        Krb5Token.debug("\ndes3KdDecrypt plain: " +
            Krb5Token.getHexBytes(ptext));
        */

        // Strip out confounder and padding
        /*
         * There is always at least one padding byte. The padding bytes
         * are all the value of the number of padding bytes.
         */
        int padSize = ptext[ptext.length - 1];
        if (padSize < 1  || padSize > 8)
            throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
                "Invalid padding on Wrap Token");

        token.padding = WrapToken.pads[padSize];
        int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;

        System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,
            plaintext, pStart, len);

        // Needed to calculate checksum
        System.arraycopy(ptext, 0, token.confounder,
            0, WrapToken.CONFOUNDER_SIZE);
    }

    private byte[] des3KdEncrypt(byte[] confounder, byte[] plaintext,
        int start, int len, byte[] padding) throws GSSException {


        // [confounder | plaintext | padding]
        byte[] all = new byte[confounder.length + len + padding.length];
        System.arraycopy(confounder, 0, all, 0, confounder.length);
        System.arraycopy(plaintext, start, all, confounder.length, len);
        System.arraycopy(padding, 0, all, confounder.length + len,
            padding.length);

        // Krb5Token.debug("\ndes3KdEncrypt:" + Krb5Token.getHexBytes(all));

        // Encrypt
        try {
            byte[] answer = Des3.encryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,
                all, 0, all.length);
            // Krb5Token.debug("\ndes3KdEncrypt encrypted:" +
            //  Krb5Token.getHexBytes(answer));
            return answer;
        } catch (Exception e) {
            // GeneralSecurityException, KrbCryptoException
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use DES3-KD Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    // ---- RC4-HMAC methods
    private void arcFourDecrypt(WrapToken token, byte[] ciphertext,
        int cStart, int cLen, byte[] plaintext, int pStart)
        throws GSSException {

        // obtain Sequence number needed for decryption
        // first decrypt the Sequence Number using checksum
        byte[] seqNum = decryptSeq(token.getChecksum(),
                token.getEncSeqNumber(), 0, 8);

        byte[] ptext;
        try {
            ptext = ArcFourHmac.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,
                ciphertext, cStart, cLen, seqNum);
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use ArcFour Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
        Krb5Token.debug("\narcFourDecrypt in: " +
            Krb5Token.getHexBytes(ciphertext, cStart, cLen));
        Krb5Token.debug("\narcFourDecrypt plain: " +
            Krb5Token.getHexBytes(ptext));
        */

        // Strip out confounder and padding
        /*
         * There is always at least one padding byte. The padding bytes
         * are all the value of the number of padding bytes.
         */
        int padSize = ptext[ptext.length - 1];
        if (padSize < 1)
            throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
                "Invalid padding on Wrap Token");

        token.padding = WrapToken.pads[padSize];
        int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;

        System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,
            plaintext, pStart, len);

        // Krb5Token.debug("\narcFourDecrypt plaintext: " +
        //    Krb5Token.getHexBytes(plaintext));

        // Needed to calculate checksum
        System.arraycopy(ptext, 0, token.confounder,
            0, WrapToken.CONFOUNDER_SIZE);
    }

    private byte[] arcFourEncrypt(WrapToken token, byte[] confounder,
        byte[] plaintext, int start, int len, byte[] padding)
        throws GSSException {

        // [confounder | plaintext | padding]
        byte[] all = new byte[confounder.length + len + padding.length];
        System.arraycopy(confounder, 0, all, 0, confounder.length);
        System.arraycopy(plaintext, start, all, confounder.length, len);
        System.arraycopy(padding, 0, all, confounder.length + len,
            padding.length);

        // get the token Sequence Number required for encryption
        // Note: When using this RC4 based encryption type, the sequence number
        // is always sent in big-endian rather than little-endian order.
        byte[] seqNum = new byte[4];
        WrapToken.writeBigEndian(token.getSequenceNumber(), seqNum);

        // Krb5Token.debug("\narcFourEncrypt:" + Krb5Token.getHexBytes(all));

        // Encrypt
        try {
            byte[] answer = ArcFourHmac.encryptRaw(keybytes, KG_USAGE_SEAL,
                                        seqNum, all, 0, all.length);
            // Krb5Token.debug("\narcFourEncrypt encrypted:" +
            //  Krb5Token.getHexBytes(answer));
            return answer;
        } catch (Exception e) {
            // GeneralSecurityException, KrbCryptoException
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use ArcFour Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    // ---- AES methods
    private byte[] aes128Encrypt(byte[] confounder, byte[] tokenHeader,
        byte[] plaintext, int start, int len, int key_usage)
        throws GSSException {

        // encrypt { AES-plaintext-data | filler | header }
        // AES-plaintext-data { confounder | plaintext }
        // WrapToken = { tokenHeader |
        //      Encrypt (confounder | plaintext | tokenHeader ) | HMAC }

        byte[] all = new byte[confounder.length + len + tokenHeader.length];
        System.arraycopy(confounder, 0, all, 0, confounder.length);
        System.arraycopy(plaintext, start, all, confounder.length, len);
        System.arraycopy(tokenHeader, 0, all, confounder.length+len,
                                tokenHeader.length);

        // Krb5Token.debug("\naes128Encrypt:" + Krb5Token.getHexBytes(all));
        try {
            byte[] answer = Aes128.encryptRaw(keybytes, key_usage,
                                ZERO_IV_AES,
                                all, 0, all.length);
            // Krb5Token.debug("\naes128Encrypt encrypted:" +
            //                  Krb5Token.getHexBytes(answer));
            return answer;
        } catch (Exception e) {
            // GeneralSecurityException, KrbCryptoException
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use AES128 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    private byte[] aes128Sha2Encrypt(byte[] confounder, byte[] tokenHeader,
            byte[] plaintext, int start, int len, int key_usage)
            throws GSSException {

        // encrypt { AES-plaintext-data | filler | header }
        // AES-plaintext-data { confounder | plaintext }
        // WrapToken = { tokenHeader |
        //      Encrypt (confounder | plaintext | tokenHeader ) | HMAC }

        byte[] all = new byte[confounder.length + len + tokenHeader.length];
        System.arraycopy(confounder, 0, all, 0, confounder.length);
        System.arraycopy(plaintext, start, all, confounder.length, len);
        System.arraycopy(tokenHeader, 0, all, confounder.length+len,
                tokenHeader.length);

        // Krb5Token.debug("\naes128Sha2Encrypt:" + Krb5Token.getHexBytes(all));
        try {
            byte[] answer = Aes128Sha2.encryptRaw(keybytes, key_usage,
                    ZERO_IV_AES,
                    all, 0, all.length);
            // Krb5Token.debug("\naes128Sha2Encrypt encrypted:" +
            //                  Krb5Token.getHexBytes(answer));
            return answer;
        } catch (Exception e) {
            // GeneralSecurityException, KrbCryptoException
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                    "Could not use Aes128Sha2 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    private void aes128Decrypt(WrapToken_v2 token, byte[] ciphertext,
        int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
        throws GSSException {

        byte[] ptext = null;

        try {
            ptext = Aes128.decryptRaw(keybytes, key_usage,
                        ZERO_IV_AES, ciphertext, cStart, cLen);
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use AES128 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
        Krb5Token.debug("\naes128Decrypt in: " +
            Krb5Token.getHexBytes(ciphertext, cStart, cLen));
        Krb5Token.debug("\naes128Decrypt plain: " +
            Krb5Token.getHexBytes(ptext));
        Krb5Token.debug("\naes128Decrypt ptext: " +
            Krb5Token.getHexBytes(ptext));
        */

        // Strip out confounder and token header
        int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
                        WrapToken_v2.TOKEN_HEADER_SIZE;
        System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
                                plaintext, pStart, len);

        /*
        Krb5Token.debug("\naes128Decrypt plaintext: " +
            Krb5Token.getHexBytes(plaintext, pStart, len));
        */
    }

    private void aes128Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext,
            int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
            throws GSSException {

        byte[] ptext = null;

        try {
            ptext = Aes128Sha2.decryptRaw(keybytes, key_usage,
                    ZERO_IV_AES, ciphertext, cStart, cLen);
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                    "Could not use AES128Sha2 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
        Krb5Token.debug("\naes128Sha2Decrypt in: " +
            Krb5Token.getHexBytes(ciphertext, cStart, cLen));
        Krb5Token.debug("\naes128Sha2Decrypt plain: " +
            Krb5Token.getHexBytes(ptext));
        Krb5Token.debug("\naes128Sha2Decrypt ptext: " +
            Krb5Token.getHexBytes(ptext));
        */

        // Strip out confounder and token header
        int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
                WrapToken_v2.TOKEN_HEADER_SIZE;
        System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
                plaintext, pStart, len);

        /*
        Krb5Token.debug("\naes128Sha2Decrypt plaintext: " +
            Krb5Token.getHexBytes(plaintext, pStart, len));
        */
    }

    private byte[] aes256Encrypt(byte[] confounder, byte[] tokenHeader,
        byte[] plaintext, int start, int len, int key_usage)
        throws GSSException {

        // encrypt { AES-plaintext-data | filler | header }
        // AES-plaintext-data { confounder | plaintext }
        // WrapToken = { tokenHeader |
        //       Encrypt (confounder | plaintext | tokenHeader ) | HMAC }

        byte[] all = new byte[confounder.length + len + tokenHeader.length];
        System.arraycopy(confounder, 0, all, 0, confounder.length);
        System.arraycopy(plaintext, start, all, confounder.length, len);
        System.arraycopy(tokenHeader, 0, all, confounder.length+len,
                                tokenHeader.length);

        // Krb5Token.debug("\naes256Encrypt:" + Krb5Token.getHexBytes(all));

        try {
            byte[] answer = Aes256.encryptRaw(keybytes, key_usage,
                                ZERO_IV_AES, all, 0, all.length);
            // Krb5Token.debug("\naes256Encrypt encrypted:" +
            //  Krb5Token.getHexBytes(answer));
            return answer;
        } catch (Exception e) {
            // GeneralSecurityException, KrbCryptoException
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use AES256 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    private byte[] aes256Sha2Encrypt(byte[] confounder, byte[] tokenHeader,
            byte[] plaintext, int start, int len, int key_usage)
            throws GSSException {

        // encrypt { AES-plaintext-data | filler | header }
        // AES-plaintext-data { confounder | plaintext }
        // WrapToken = { tokenHeader |
        //       Encrypt (confounder | plaintext | tokenHeader ) | HMAC }

        byte[] all = new byte[confounder.length + len + tokenHeader.length];
        System.arraycopy(confounder, 0, all, 0, confounder.length);
        System.arraycopy(plaintext, start, all, confounder.length, len);
        System.arraycopy(tokenHeader, 0, all, confounder.length+len,
                tokenHeader.length);

        // Krb5Token.debug("\naes256Sha2Encrypt:" + Krb5Token.getHexBytes(all));

        try {
            byte[] answer = Aes256Sha2.encryptRaw(keybytes, key_usage,
                    ZERO_IV_AES, all, 0, all.length);
            // Krb5Token.debug("\naes256Sha2Encrypt encrypted:" +
            //  Krb5Token.getHexBytes(answer));
            return answer;
        } catch (Exception e) {
            // GeneralSecurityException, KrbCryptoException
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                    "Could not use Aes256Sha2 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }
    }

    private void aes256Decrypt(WrapToken_v2 token, byte[] ciphertext,
        int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
        throws GSSException {

        byte[] ptext;
        try {
            ptext = Aes256.decryptRaw(keybytes, key_usage,
                        ZERO_IV_AES, ciphertext, cStart, cLen);
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                "Could not use AES128 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
        Krb5Token.debug("\naes256Decrypt in: " +
            Krb5Token.getHexBytes(ciphertext, cStart, cLen));
        Krb5Token.debug("\naes256Decrypt plain: " +
            Krb5Token.getHexBytes(ptext));
        Krb5Token.debug("\naes256Decrypt ptext: " +
            Krb5Token.getHexBytes(ptext));
        */

        // Strip out confounder and token header
        int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
                        WrapToken_v2.TOKEN_HEADER_SIZE;
        System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
                                plaintext, pStart, len);

        /*
        Krb5Token.debug("\naes128Decrypt plaintext: " +
            Krb5Token.getHexBytes(plaintext, pStart, len));
        */

    }

    private void aes256Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext,
            int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)
            throws GSSException {

        byte[] ptext;
        try {
            ptext = Aes256Sha2.decryptRaw(keybytes, key_usage,
                    ZERO_IV_AES, ciphertext, cStart, cLen);
        } catch (GeneralSecurityException e) {
            GSSException ge = new GSSException(GSSException.FAILURE, -1,
                    "Could not use AES256Sha2 Cipher - " + e.getMessage());
            ge.initCause(e);
            throw ge;
        }

        /*
        Krb5Token.debug("\naes256Sha2Decrypt in: " +
            Krb5Token.getHexBytes(ciphertext, cStart, cLen));
        Krb5Token.debug("\naes256Sha2Decrypt plain: " +
            Krb5Token.getHexBytes(ptext));
        Krb5Token.debug("\naes256Sha2Decrypt ptext: " +
            Krb5Token.getHexBytes(ptext));
        */

        // Strip out confounder and token header
        int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -
                WrapToken_v2.TOKEN_HEADER_SIZE;
        System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,
                plaintext, pStart, len);

        /*
        Krb5Token.debug("\naes256Sha2Decrypt plaintext: " +
            Krb5Token.getHexBytes(plaintext, pStart, len));
        */

    }

    /**
     * This class provides a truncated inputstream needed by WrapToken. The
     * truncated inputstream is passed to CipherInputStream. It prevents
     * the CipherInputStream from treating the bytes of the following token
     * as part fo the ciphertext for this token.
     */
    class WrapTokenInputStream extends InputStream {

        private InputStream is;
        private int length;
        private int remaining;

        private int temp;

        public WrapTokenInputStream(InputStream is, int length) {
            this.is = is;
            this.length = length;
            remaining = length;
        }

        public final int read() throws IOException {
            if (remaining == 0)
                return -1;
            else {
                temp = is.read();
                if (temp != -1)
                    remaining -= temp;
                return temp;
            }
        }

        public final int read(byte[] b) throws IOException {
            if (remaining == 0)
                return -1;
            else {
                temp = Math.min(remaining, b.length);
                temp = is.read(b, 0, temp);
                if (temp != -1)
                    remaining -= temp;
                return temp;
            }
        }

        public final int read(byte[] b,
                              int off,
                              int len) throws IOException {
            if (remaining == 0)
                return -1;
            else {
                temp = Math.min(remaining, len);
                temp = is.read(b, off, temp);
                if (temp != -1)
                    remaining -= temp;
                return temp;
            }
        }

        public final long skip(long n)  throws IOException {
            if (remaining == 0)
                return 0;
            else {
                temp = (int) Math.min(remaining, n);
                temp = (int) is.skip(temp);
                remaining -= temp;
                return temp;
            }
        }

        public final int available() throws IOException {
            return Math.min(remaining, is.available());
        }

        public final void close() throws IOException {
            remaining = 0;
        }
    }
}

sun/security/jgss/krb5/CipherHelper.java

 

JDK 11 java.security.sasl.jmod - Security SASL Module

JDK 11 java.se.jmod - SE Module

Download and Use JDK 11

⇑⇑ FAQ for JDK (Java Development Kit)

2018-11-09, 5200👍, 0💬