| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
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;  | 
 | 
import sun.security.krb5.internal.crypto.EType;  | 
 | 
 | 
 | 
class CipherHelper { | 
 | 
 | 
 | 
    // From draft-raeburn-cat-gssapi-krb5-3des-00  | 
 | 
      | 
 | 
    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  | 
 | 
      | 
 | 
    private static final int HMAC_CHECKSUM_SIZE = 8;  | 
 | 
      | 
 | 
    private static final int KG_USAGE_SIGN_MS = 15;  | 
 | 
 | 
 | 
      | 
 | 
    private static final boolean DEBUG = Krb5Util.DEBUG;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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:  | 
 | 
            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  | 
 | 
      | 
 | 
    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:  | 
 | 
              | 
 | 
 | 
 | 
 | 
 | 
             */  | 
 | 
            try { | 
 | 
                MessageDigest md5 = MessageDigest.getInstance("MD5"); | 
 | 
 | 
 | 
                // debug("\t\tdata=["); | 
 | 
 | 
 | 
                // debug(getHexBytes(checksumDataHeader,  | 
 | 
                  | 
 | 
                md5.update(header);  | 
 | 
 | 
 | 
                  | 
 | 
                md5.update(data, start, len);  | 
 | 
 | 
 | 
                if (trailer != null) { | 
 | 
                    // debug(" " + | 
 | 
                    //       getHexBytes(trailer,  | 
 | 
                      | 
 | 
                    md5.update(trailer);  | 
 | 
                }  | 
 | 
                //          debug("]\n"); | 
 | 
 | 
 | 
                data = md5.digest();  | 
 | 
                start = 0;  | 
 | 
                len = data.length;  | 
 | 
                //          System.out.println("\tMD5 Checksum is [" + | 
 | 
                  | 
 | 
                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: " + | 
 | 
                  | 
 | 
                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.  | 
 | 
                  | 
 | 
                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));  | 
 | 
 | 
 | 
                  | 
 | 
                byte[] output = new byte[getChecksumLength()];  | 
 | 
                System.arraycopy(answer, 0, output, 0, output.length);  | 
 | 
                // Krb5Token.debug("\nanswer (trimmed): " + | 
 | 
                  | 
 | 
                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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    byte[] calculateChecksum(byte[] header, byte[] data, int start, int len,  | 
 | 
        int key_usage) throws GSSException { | 
 | 
 | 
 | 
          | 
 | 
        int total = ((header != null ? header.length : 0) + len);  | 
 | 
 | 
 | 
          | 
 | 
        byte[] buf = new byte[total];  | 
 | 
 | 
 | 
          | 
 | 
        System.arraycopy(data, start, buf, 0, len);  | 
 | 
 | 
 | 
          | 
 | 
        if (header != null) { | 
 | 
            System.arraycopy(header, 0, buf, len, header.length);  | 
 | 
        }  | 
 | 
 | 
 | 
        // Krb5Token.debug("\nAES calculate checksum on: " + | 
 | 
          | 
 | 
        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: " + | 
 | 
                  | 
 | 
                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: " + | 
 | 
                  | 
 | 
                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) { | 
 | 
                  | 
 | 
                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:  | 
 | 
              | 
 | 
            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) { | 
 | 
                  | 
 | 
                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) { | 
 | 
                  | 
 | 
                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:  | 
 | 
              | 
 | 
            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) { | 
 | 
                  | 
 | 
                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_ARCFOUR_HMAC:  | 
 | 
              | 
 | 
            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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    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;  | 
 | 
            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:  | 
 | 
 | 
 | 
              | 
 | 
            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:  | 
 | 
 | 
 | 
              | 
 | 
            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 { | 
 | 
 | 
 | 
          | 
 | 
        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;  | 
 | 
            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:  | 
 | 
              | 
 | 
            Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),  | 
 | 
                ZERO_IV);  | 
 | 
            CipherOutputStream cos = new CipherOutputStream(os, des);  | 
 | 
              | 
 | 
            cos.write(confounder);  | 
 | 
              | 
 | 
            cos.write(plaintext, start, len);  | 
 | 
              | 
 | 
            cos.write(padding);  | 
 | 
            break;  | 
 | 
 | 
 | 
        case MessageToken.SEAL_ALG_DES3_KD:  | 
 | 
            byte[] ctext = des3KdEncrypt(confounder, plaintext, start, len,  | 
 | 
                padding);  | 
 | 
 | 
 | 
              | 
 | 
            os.write(ctext);  | 
 | 
            break;  | 
 | 
 | 
 | 
        case MessageToken.SEAL_ALG_ARCFOUR_HMAC:  | 
 | 
            byte[] ciphertext = arcFourEncrypt(token, confounder, plaintext,  | 
 | 
                start, len, padding);  | 
 | 
 | 
 | 
              | 
 | 
            os.write(ciphertext);  | 
 | 
            break;  | 
 | 
 | 
 | 
        default:  | 
 | 
            throw new GSSException(GSSException.FAILURE, -1,  | 
 | 
                "Unsupported seal algorithm: " + sealAlg);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
            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;  | 
 | 
              | 
 | 
            Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),  | 
 | 
                ZERO_IV);  | 
 | 
            try { | 
 | 
                  | 
 | 
                pos += des.update(confounder, 0, confounder.length,  | 
 | 
                                  ciphertext, pos);  | 
 | 
                  | 
 | 
                pos += des.update(plaintext, pStart, pLen,  | 
 | 
                                  ciphertext, pos);  | 
 | 
                  | 
 | 
                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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
            default:  | 
 | 
                    throw new GSSException(GSSException.FAILURE, -1,  | 
 | 
                        "Unsupported etype: " + etype);  | 
 | 
        }  | 
 | 
        System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);  | 
 | 
        return ctext.length;  | 
 | 
    }  | 
 | 
 | 
 | 
    // --------------------- DES methods  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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) { | 
 | 
              | 
 | 
            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) { | 
 | 
                  | 
 | 
                des.update(header, 0, header.length, temp, 0);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            for (int i = 0; i < numBlocks; i++) { | 
 | 
                des.update(data, offset, blockSize,  | 
 | 
                           temp, 0);  | 
 | 
                offset += blockSize;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            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;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
 | 
 | 
              | 
 | 
 | 
 | 
 | 
 | 
             */  | 
 | 
            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;  | 
 | 
 | 
 | 
              | 
 | 
            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;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            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;  | 
 | 
 | 
 | 
              | 
 | 
            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;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        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;  | 
 | 
 | 
 | 
          | 
 | 
        for (int i = 0; i < numBlocks; i++) { | 
 | 
              | 
 | 
            temp = cis.read(dataOutBuf, dataOffset, blockSize);  | 
 | 
 | 
 | 
            // temp should be blockSize  | 
 | 
            // debug("Got " + temp + " bytes and blockSize is " | 
 | 
            //    + blockSize + "\n");  | 
 | 
            // debug("Bytes are: " | 
 | 
              | 
 | 
            dataOffset += blockSize;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        byte[] finalBlock = new byte[blockSize];  | 
 | 
          | 
 | 
        temp = cis.read(finalBlock);  | 
 | 
        // temp should be blockSize  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
        */  | 
 | 
        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;  | 
 | 
 | 
 | 
          | 
 | 
        System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,  | 
 | 
                         blockSize);  | 
 | 
    }  | 
 | 
 | 
 | 
    private static byte[] getDesEncryptionKey(byte[] key)  | 
 | 
        throws GSSException { | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        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);    | 
 | 
        return retVal;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    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  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        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);  | 
 | 
 | 
 | 
          | 
 | 
        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 { | 
 | 
 | 
 | 
 | 
 | 
          | 
 | 
        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)); | 
 | 
 | 
 | 
          | 
 | 
        try { | 
 | 
            byte[] answer = Des3.encryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,  | 
 | 
                all, 0, all.length);  | 
 | 
            // Krb5Token.debug("\ndes3KdEncrypt encrypted:" + | 
 | 
              | 
 | 
            return answer;  | 
 | 
        } catch (Exception e) { | 
 | 
              | 
 | 
            GSSException ge = new GSSException(GSSException.FAILURE, -1,  | 
 | 
                "Could not use DES3-KD Cipher - " + e.getMessage());  | 
 | 
            ge.initCause(e);  | 
 | 
            throw ge;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private void arcFourDecrypt(WrapToken token, byte[] ciphertext,  | 
 | 
        int cStart, int cLen, byte[] plaintext, int pStart)  | 
 | 
        throws GSSException { | 
 | 
 | 
 | 
        // obtain Sequence number needed for decryption  | 
 | 
          | 
 | 
        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  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        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));  | 
 | 
 | 
 | 
          | 
 | 
        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 { | 
 | 
 | 
 | 
          | 
 | 
        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  | 
 | 
          | 
 | 
        byte[] seqNum = new byte[4];  | 
 | 
        WrapToken.writeBigEndian(token.getSequenceNumber(), seqNum);  | 
 | 
 | 
 | 
        // Krb5Token.debug("\narcFourEncrypt:" + Krb5Token.getHexBytes(all)); | 
 | 
 | 
 | 
          | 
 | 
        try { | 
 | 
            byte[] answer = ArcFourHmac.encryptRaw(keybytes, KG_USAGE_SEAL,  | 
 | 
                                        seqNum, all, 0, all.length);  | 
 | 
            // Krb5Token.debug("\narcFourEncrypt encrypted:" + | 
 | 
              | 
 | 
            return answer;  | 
 | 
        } catch (Exception e) { | 
 | 
              | 
 | 
            GSSException ge = new GSSException(GSSException.FAILURE, -1,  | 
 | 
                "Could not use ArcFour Cipher - " + e.getMessage());  | 
 | 
            ge.initCause(e);  | 
 | 
            throw ge;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    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);  | 
 | 
 | 
 | 
          | 
 | 
        try { | 
 | 
            byte[] answer = Aes128.encryptRaw(keybytes, key_usage,  | 
 | 
                                ZERO_IV_AES,  | 
 | 
                                all, 0, all.length);  | 
 | 
            // Krb5Token.debug("\naes128Encrypt encrypted:" + | 
 | 
              | 
 | 
            return answer;  | 
 | 
        } catch (Exception e) { | 
 | 
              | 
 | 
            GSSException ge = new GSSException(GSSException.FAILURE, -1,  | 
 | 
                "Could not use AES128 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));  | 
 | 
        */  | 
 | 
 | 
 | 
          | 
 | 
        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 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:" + | 
 | 
              | 
 | 
            return answer;  | 
 | 
        } catch (Exception e) { | 
 | 
              | 
 | 
            GSSException ge = new GSSException(GSSException.FAILURE, -1,  | 
 | 
                "Could not use AES256 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));  | 
 | 
        */  | 
 | 
 | 
 | 
          | 
 | 
        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));  | 
 | 
        */  | 
 | 
 | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |