Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/krb5/CipherHelper.java
41161 views
/*1* Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.jgss.krb5;2627import javax.crypto.Cipher;28import javax.crypto.SecretKey;29import javax.crypto.spec.IvParameterSpec;30import javax.crypto.spec.SecretKeySpec;31import javax.crypto.CipherInputStream;32import javax.crypto.CipherOutputStream;33import java.io.InputStream;34import java.io.OutputStream;35import java.io.IOException;36import org.ietf.jgss.*;3738import java.security.MessageDigest;39import java.security.GeneralSecurityException;40import java.security.NoSuchAlgorithmException;41import sun.security.krb5.*;42import sun.security.krb5.internal.crypto.Aes128Sha2;43import sun.security.krb5.internal.crypto.Aes256Sha2;44import sun.security.krb5.internal.crypto.Des3;45import sun.security.krb5.internal.crypto.Aes128;46import sun.security.krb5.internal.crypto.Aes256;47import sun.security.krb5.internal.crypto.ArcFourHmac;48import sun.security.krb5.internal.crypto.EType;4950class CipherHelper {5152// From draft-raeburn-cat-gssapi-krb5-3des-0053// Key usage values when deriving keys54private static final int KG_USAGE_SEAL = 22;55private static final int KG_USAGE_SIGN = 23;56private static final int KG_USAGE_SEQ = 24;5758private static final int DES_CHECKSUM_SIZE = 8;59private static final int DES_IV_SIZE = 8;60private static final int AES_IV_SIZE = 16;6162// ARCFOUR-HMAC63// Save first 8 octets of HMAC Sgn_Cksum64private static final int HMAC_CHECKSUM_SIZE = 8;65// key usage for MIC tokens used by MS66private static final int KG_USAGE_SIGN_MS = 15;6768// debug flag69private static final boolean DEBUG = Krb5Util.DEBUG;7071/**72* A zero initial vector to be used for checksum calculation and for73* DesCbc application data encryption/decryption.74*/75private static final byte[] ZERO_IV = new byte[DES_IV_SIZE];76private static final byte[] ZERO_IV_AES = new byte[AES_IV_SIZE];7778private int etype;79private int sgnAlg, sealAlg;80private byte[] keybytes;8182CipherHelper(EncryptionKey key) throws GSSException {83etype = key.getEType();84keybytes = key.getBytes();8586switch (etype) {87case EncryptedData.ETYPE_DES_CBC_CRC:88case EncryptedData.ETYPE_DES_CBC_MD5:89sgnAlg = MessageToken.SGN_ALG_DES_MAC_MD5;90sealAlg = MessageToken.SEAL_ALG_DES;91break;9293case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:94sgnAlg = MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD;95sealAlg = MessageToken.SEAL_ALG_DES3_KD;96break;9798case EncryptedData.ETYPE_ARCFOUR_HMAC:99sgnAlg = MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR;100sealAlg = MessageToken.SEAL_ALG_ARCFOUR_HMAC;101break;102103case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:104case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:105case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:106case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:107sgnAlg = -1;108sealAlg = -1;109break;110111default:112throw new GSSException(GSSException.FAILURE, -1,113"Unsupported encryption type: " + etype);114}115}116117int getSgnAlg() {118return sgnAlg;119}120121int getSealAlg() {122return sealAlg;123}124125// new token format from draft-ietf-krb-wg-gssapi-cfx-07126// proto is used to determine new GSS token format for "newer" etypes127int getProto() {128return EType.isNewer(etype) ? 1 : 0;129}130131int getEType() {132return etype;133}134135boolean isArcFour() {136boolean flag = false;137if (etype == EncryptedData.ETYPE_ARCFOUR_HMAC) {138flag = true;139}140return flag;141}142143@SuppressWarnings("fallthrough")144byte[] calculateChecksum(int alg, byte[] header, byte[] trailer,145byte[] data, int start, int len, int tokenId) throws GSSException {146147switch (alg) {148case MessageToken.SGN_ALG_DES_MAC_MD5:149/*150* With this sign algorithm, first an MD5 hash is computed on the151* application data. The 16 byte hash is then DesCbc encrypted.152*/153try {154MessageDigest md5 = MessageDigest.getInstance("MD5");155156// debug("\t\tdata=[");157158// debug(getHexBytes(checksumDataHeader,159// checksumDataHeader.length) + " ");160md5.update(header);161162// debug(getHexBytes(data, start, len));163md5.update(data, start, len);164165if (trailer != null) {166// debug(" " +167// getHexBytes(trailer,168// optionalTrailer.length));169md5.update(trailer);170}171// debug("]\n");172173data = md5.digest();174start = 0;175len = data.length;176// System.out.println("\tMD5 Checksum is [" +177// getHexBytes(data) + "]\n");178header = null;179trailer = null;180} catch (NoSuchAlgorithmException e) {181GSSException ge = new GSSException(GSSException.FAILURE, -1,182"Could not get MD5 Message Digest - " + e.getMessage());183ge.initCause(e);184throw ge;185}186// fall through to encrypt checksum187188case MessageToken.SGN_ALG_DES_MAC:189return getDesCbcChecksum(keybytes, header, data, start, len);190191case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:192byte[] buf;193int offset, total;194if (header == null && trailer == null) {195buf = data;196total = len;197offset = start;198} else {199total = ((header != null ? header.length : 0) + len +200(trailer != null ? trailer.length : 0));201202buf = new byte[total];203int pos = 0;204if (header != null) {205System.arraycopy(header, 0, buf, 0, header.length);206pos = header.length;207}208System.arraycopy(data, start, buf, pos, len);209pos += len;210if (trailer != null) {211System.arraycopy(trailer, 0, buf, pos, trailer.length);212}213214offset = 0;215}216217try {218219/*220Krb5Token.debug("\nkeybytes: " +221Krb5Token.getHexBytes(keybytes));222Krb5Token.debug("\nheader: " + (header == null ? "NONE" :223Krb5Token.getHexBytes(header)));224Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :225Krb5Token.getHexBytes(trailer)));226Krb5Token.debug("\ndata: " +227Krb5Token.getHexBytes(data, start, len));228Krb5Token.debug("\nbuf: " + Krb5Token.getHexBytes(buf, offset,229total));230*/231232byte[] answer = Des3.calculateChecksum(keybytes,233KG_USAGE_SIGN, buf, offset, total);234// Krb5Token.debug("\nanswer: " +235// Krb5Token.getHexBytes(answer));236return answer;237} catch (GeneralSecurityException e) {238GSSException ge = new GSSException(GSSException.FAILURE, -1,239"Could not use HMAC-SHA1-DES3-KD signing algorithm - " +240e.getMessage());241ge.initCause(e);242throw ge;243}244245case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:246byte[] buffer;247int off, tot;248if (header == null && trailer == null) {249buffer = data;250tot = len;251off = start;252} else {253tot = ((header != null ? header.length : 0) + len +254(trailer != null ? trailer.length : 0));255256buffer = new byte[tot];257int pos = 0;258259if (header != null) {260System.arraycopy(header, 0, buffer, 0, header.length);261pos = header.length;262}263System.arraycopy(data, start, buffer, pos, len);264pos += len;265if (trailer != null) {266System.arraycopy(trailer, 0, buffer, pos, trailer.length);267}268269off = 0;270}271272try {273274/*275Krb5Token.debug("\nkeybytes: " +276Krb5Token.getHexBytes(keybytes));277Krb5Token.debug("\nheader: " + (header == null ? "NONE" :278Krb5Token.getHexBytes(header)));279Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :280Krb5Token.getHexBytes(trailer)));281Krb5Token.debug("\ndata: " +282Krb5Token.getHexBytes(data, start, len));283Krb5Token.debug("\nbuffer: " +284Krb5Token.getHexBytes(buffer, off, tot));285*/286287// for MIC tokens, key derivation salt is 15288// NOTE: Required for interoperability. The RC4-HMAC spec289// defines key_usage of 23, however all Kerberos impl.290// MS/Solaris/MIT all use key_usage of 15 for MIC tokens291int key_usage = KG_USAGE_SIGN;292if (tokenId == Krb5Token.MIC_ID) {293key_usage = KG_USAGE_SIGN_MS;294}295byte[] answer = ArcFourHmac.calculateChecksum(keybytes,296key_usage, buffer, off, tot);297// Krb5Token.debug("\nanswer: " +298// Krb5Token.getHexBytes(answer));299300// Save first 8 octets of HMAC Sgn_Cksum301byte[] output = new byte[getChecksumLength()];302System.arraycopy(answer, 0, output, 0, output.length);303// Krb5Token.debug("\nanswer (trimmed): " +304// Krb5Token.getHexBytes(output));305return output;306} catch (GeneralSecurityException e) {307GSSException ge = new GSSException(GSSException.FAILURE, -1,308"Could not use HMAC_MD5_ARCFOUR signing algorithm - " +309e.getMessage());310ge.initCause(e);311throw ge;312}313314default:315throw new GSSException(GSSException.FAILURE, -1,316"Unsupported signing algorithm: " + sgnAlg);317}318}319320// calculate Checksum for the new GSS tokens321byte[] calculateChecksum(byte[] header, byte[] data, int start, int len,322int key_usage) throws GSSException {323324// total length325int total = ((header != null ? header.length : 0) + len);326327// get_mic("plaintext-data" | "header")328byte[] buf = new byte[total];329330// data331System.arraycopy(data, start, buf, 0, len);332333// token header334if (header != null) {335System.arraycopy(header, 0, buf, len, header.length);336}337338// Krb5Token.debug("\nAES calculate checksum on: " +339// Krb5Token.getHexBytes(buf));340switch (etype) {341case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:342try {343byte[] answer = Aes128.calculateChecksum(keybytes, key_usage,344buf, 0, total);345// Krb5Token.debug("\nAES128 checksum: " +346// Krb5Token.getHexBytes(answer));347return answer;348} catch (GeneralSecurityException e) {349GSSException ge = new GSSException(GSSException.FAILURE, -1,350"Could not use AES128 signing algorithm - " +351e.getMessage());352ge.initCause(e);353throw ge;354}355356case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:357try {358byte[] answer = Aes256.calculateChecksum(keybytes, key_usage,359buf, 0, total);360// Krb5Token.debug("\nAES256 checksum: " +361// Krb5Token.getHexBytes(answer));362return answer;363} catch (GeneralSecurityException e) {364GSSException ge = new GSSException(GSSException.FAILURE, -1,365"Could not use AES256 signing algorithm - " +366e.getMessage());367ge.initCause(e);368throw ge;369}370371case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:372try {373byte[] answer = Aes128Sha2.calculateChecksum(keybytes, key_usage,374buf, 0, total);375return answer;376} catch (GeneralSecurityException e) {377GSSException ge = new GSSException(GSSException.FAILURE, -1,378"Could not use AES128 signing algorithm - " +379e.getMessage());380ge.initCause(e);381throw ge;382}383384case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:385try {386byte[] answer = Aes256Sha2.calculateChecksum(keybytes, key_usage,387buf, 0, total);388return answer;389} catch (GeneralSecurityException e) {390GSSException ge = new GSSException(GSSException.FAILURE, -1,391"Could not use AES256 signing algorithm - " +392e.getMessage());393ge.initCause(e);394throw ge;395}396397398default:399throw new GSSException(GSSException.FAILURE, -1,400"Unsupported encryption type: " + etype);401}402}403404byte[] encryptSeq(byte[] ivec, byte[] plaintext, int start, int len)405throws GSSException {406407switch (sgnAlg) {408case MessageToken.SGN_ALG_DES_MAC_MD5:409case MessageToken.SGN_ALG_DES_MAC:410try {411Cipher des = getInitializedDes(true, keybytes, ivec);412return des.doFinal(plaintext, start, len);413414} catch (GeneralSecurityException e) {415GSSException ge = new GSSException(GSSException.FAILURE, -1,416"Could not encrypt sequence number using DES - " +417e.getMessage());418ge.initCause(e);419throw ge;420}421422case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:423byte[] iv;424if (ivec.length == DES_IV_SIZE) {425iv = ivec;426} else {427iv = new byte[DES_IV_SIZE];428System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);429}430try {431return Des3.encryptRaw(keybytes, KG_USAGE_SEQ, iv,432plaintext, start, len);433} catch (Exception e) {434// GeneralSecurityException, KrbCryptoException435GSSException ge = new GSSException(GSSException.FAILURE, -1,436"Could not encrypt sequence number using DES3-KD - " +437e.getMessage());438ge.initCause(e);439throw ge;440}441442case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:443// ivec passed is the checksum444byte[] checksum;445if (ivec.length == HMAC_CHECKSUM_SIZE) {446checksum = ivec;447} else {448checksum = new byte[HMAC_CHECKSUM_SIZE];449System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);450}451452try {453return ArcFourHmac.encryptSeq(keybytes, KG_USAGE_SEQ, checksum,454plaintext, start, len);455} catch (Exception e) {456// GeneralSecurityException, KrbCryptoException457GSSException ge = new GSSException(GSSException.FAILURE, -1,458"Could not encrypt sequence number using RC4-HMAC - " +459e.getMessage());460ge.initCause(e);461throw ge;462}463464default:465throw new GSSException(GSSException.FAILURE, -1,466"Unsupported signing algorithm: " + sgnAlg);467}468}469470byte[] decryptSeq(byte[] ivec, byte[] ciphertext, int start, int len)471throws GSSException {472473switch (sgnAlg) {474case MessageToken.SGN_ALG_DES_MAC_MD5:475case MessageToken.SGN_ALG_DES_MAC:476try {477Cipher des = getInitializedDes(false, keybytes, ivec);478return des.doFinal(ciphertext, start, len);479} catch (GeneralSecurityException e) {480GSSException ge = new GSSException(GSSException.FAILURE, -1,481"Could not decrypt sequence number using DES - " +482e.getMessage());483ge.initCause(e);484throw ge;485}486487case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:488byte[] iv;489if (ivec.length == DES_IV_SIZE) {490iv = ivec;491} else {492iv = new byte[8];493System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);494}495496try {497return Des3.decryptRaw(keybytes, KG_USAGE_SEQ, iv,498ciphertext, start, len);499} catch (Exception e) {500// GeneralSecurityException, KrbCryptoException501GSSException ge = new GSSException(GSSException.FAILURE, -1,502"Could not decrypt sequence number using DES3-KD - " +503e.getMessage());504ge.initCause(e);505throw ge;506}507508case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:509// ivec passed is the checksum510byte[] checksum;511if (ivec.length == HMAC_CHECKSUM_SIZE) {512checksum = ivec;513} else {514checksum = new byte[HMAC_CHECKSUM_SIZE];515System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);516}517518try {519return ArcFourHmac.decryptSeq(keybytes, KG_USAGE_SEQ, checksum,520ciphertext, start, len);521} catch (Exception e) {522// GeneralSecurityException, KrbCryptoException523GSSException ge = new GSSException(GSSException.FAILURE, -1,524"Could not decrypt sequence number using RC4-HMAC - " +525e.getMessage());526ge.initCause(e);527throw ge;528}529530default:531throw new GSSException(GSSException.FAILURE, -1,532"Unsupported signing algorithm: " + sgnAlg);533}534}535536int getChecksumLength() throws GSSException {537switch (etype) {538case EncryptedData.ETYPE_DES_CBC_CRC:539case EncryptedData.ETYPE_DES_CBC_MD5:540return DES_CHECKSUM_SIZE;541542case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:543return Des3.getChecksumLength();544545case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:546return Aes128.getChecksumLength();547case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:548return Aes256.getChecksumLength();549550case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:551return Aes128Sha2.getChecksumLength();552case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:553return Aes256Sha2.getChecksumLength();554555case EncryptedData.ETYPE_ARCFOUR_HMAC:556// only first 8 octets of HMAC Sgn_Cksum are used557return HMAC_CHECKSUM_SIZE;558559default:560throw new GSSException(GSSException.FAILURE, -1,561"Unsupported encryption type: " + etype);562}563}564565void decryptData(WrapToken token, byte[] ciphertext, int cStart, int cLen,566byte[] plaintext, int pStart) throws GSSException {567568/*569Krb5Token.debug("decryptData : ciphertext = " +570Krb5Token.getHexBytes(ciphertext));571*/572573switch (sealAlg) {574case MessageToken.SEAL_ALG_DES:575desCbcDecrypt(token, getDesEncryptionKey(keybytes),576ciphertext, cStart, cLen, plaintext, pStart);577break;578579case MessageToken.SEAL_ALG_DES3_KD:580des3KdDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);581break;582583case MessageToken.SEAL_ALG_ARCFOUR_HMAC:584arcFourDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);585break;586587default:588throw new GSSException(GSSException.FAILURE, -1,589"Unsupported seal algorithm: " + sealAlg);590}591}592593// decrypt data in the new GSS tokens594void decryptData(WrapToken_v2 token, byte[] ciphertext, int cStart,595int cLen, byte[] plaintext, int pStart, int key_usage)596throws GSSException {597598/*599Krb5Token.debug("decryptData : ciphertext = " +600Krb5Token.getHexBytes(ciphertext));601*/602603switch (etype) {604case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:605aes128Decrypt(token, ciphertext, cStart, cLen,606plaintext, pStart, key_usage);607break;608case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:609aes256Decrypt(token, ciphertext, cStart, cLen,610plaintext, pStart, key_usage);611break;612case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:613aes128Sha2Decrypt(token, ciphertext, cStart, cLen,614plaintext, pStart, key_usage);615break;616case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:617aes256Sha2Decrypt(token, ciphertext, cStart, cLen,618plaintext, pStart, key_usage);619break;620default:621throw new GSSException(GSSException.FAILURE, -1,622"Unsupported etype: " + etype);623}624}625626void decryptData(WrapToken token, InputStream cipherStream, int cLen,627byte[] plaintext, int pStart)628throws GSSException, IOException {629630switch (sealAlg) {631case MessageToken.SEAL_ALG_DES:632desCbcDecrypt(token, getDesEncryptionKey(keybytes),633cipherStream, cLen, plaintext, pStart);634break;635636case MessageToken.SEAL_ALG_DES3_KD:637638// Read encrypted data from stream639byte[] ciphertext = new byte[cLen];640try {641Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);642} catch (IOException e) {643GSSException ge = new GSSException(644GSSException.DEFECTIVE_TOKEN, -1,645"Cannot read complete token");646ge.initCause(e);647throw ge;648}649650des3KdDecrypt(token, ciphertext, 0, cLen, plaintext, pStart);651break;652653case MessageToken.SEAL_ALG_ARCFOUR_HMAC:654655// Read encrypted data from stream656byte[] ctext = new byte[cLen];657try {658Krb5Token.readFully(cipherStream, ctext, 0, cLen);659} catch (IOException e) {660GSSException ge = new GSSException(661GSSException.DEFECTIVE_TOKEN, -1,662"Cannot read complete token");663ge.initCause(e);664throw ge;665}666667arcFourDecrypt(token, ctext, 0, cLen, plaintext, pStart);668break;669670default:671throw new GSSException(GSSException.FAILURE, -1,672"Unsupported seal algorithm: " + sealAlg);673}674}675676void decryptData(WrapToken_v2 token, InputStream cipherStream, int cLen,677byte[] plaintext, int pStart, int key_usage)678throws GSSException, IOException {679680// Read encrypted data from stream681byte[] ciphertext = new byte[cLen];682try {683Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);684} catch (IOException e) {685GSSException ge = new GSSException(686GSSException.DEFECTIVE_TOKEN, -1,687"Cannot read complete token");688ge.initCause(e);689throw ge;690}691switch (etype) {692case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:693aes128Decrypt(token, ciphertext, 0, cLen,694plaintext, pStart, key_usage);695break;696case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:697aes256Decrypt(token, ciphertext, 0, cLen,698plaintext, pStart, key_usage);699break;700case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:701aes128Sha2Decrypt(token, ciphertext, 0, cLen,702plaintext, pStart, key_usage);703break;704case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:705aes256Sha2Decrypt(token, ciphertext, 0, cLen,706plaintext, pStart, key_usage);707break;708default:709throw new GSSException(GSSException.FAILURE, -1,710"Unsupported etype: " + etype);711}712}713714void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,715int start, int len, byte[] padding, OutputStream os)716throws GSSException, IOException {717718switch (sealAlg) {719case MessageToken.SEAL_ALG_DES:720// Encrypt on the fly and write721Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),722ZERO_IV);723CipherOutputStream cos = new CipherOutputStream(os, des);724// debug(getHexBytes(confounder, confounder.length));725cos.write(confounder);726// debug(" " + getHexBytes(plaintext, start, len));727cos.write(plaintext, start, len);728// debug(" " + getHexBytes(padding, padding.length));729cos.write(padding);730break;731732case MessageToken.SEAL_ALG_DES3_KD:733byte[] ctext = des3KdEncrypt(confounder, plaintext, start, len,734padding);735736// Write to stream737os.write(ctext);738break;739740case MessageToken.SEAL_ALG_ARCFOUR_HMAC:741byte[] ciphertext = arcFourEncrypt(token, confounder, plaintext,742start, len, padding);743744// Write to stream745os.write(ciphertext);746break;747748default:749throw new GSSException(GSSException.FAILURE, -1,750"Unsupported seal algorithm: " + sealAlg);751}752}753754/*755* Encrypt data in the new GSS tokens756*757* Wrap Tokens (with confidentiality)758* { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |759* 12-byte HMAC }760* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}761* HMAC is not encrypted; it is appended at the end.762*/763byte[] encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,764byte[] plaintext, int start, int len, int key_usage)765throws GSSException {766767switch (etype) {768case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:769return aes128Encrypt(confounder, tokenHeader,770plaintext, start, len, key_usage);771case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:772return aes256Encrypt(confounder, tokenHeader,773plaintext, start, len, key_usage);774case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:775return aes128Sha2Encrypt(confounder, tokenHeader,776plaintext, start, len, key_usage);777case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:778return aes256Sha2Encrypt(confounder, tokenHeader,779plaintext, start, len, key_usage);780default:781throw new GSSException(GSSException.FAILURE, -1,782"Unsupported etype: " + etype);783}784}785786void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,787int pStart, int pLen, byte[] padding, byte[] ciphertext, int cStart)788throws GSSException {789790switch (sealAlg) {791case MessageToken.SEAL_ALG_DES:792int pos = cStart;793// Encrypt and write794Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),795ZERO_IV);796try {797// debug(getHexBytes(confounder, confounder.length));798pos += des.update(confounder, 0, confounder.length,799ciphertext, pos);800// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));801pos += des.update(plaintext, pStart, pLen,802ciphertext, pos);803// debug(" " + getHexBytes(padding, padding.length));804des.update(padding, 0, padding.length,805ciphertext, pos);806des.doFinal();807} catch (GeneralSecurityException e) {808GSSException ge = new GSSException(GSSException.FAILURE, -1,809"Could not use DES Cipher - " + e.getMessage());810ge.initCause(e);811throw ge;812}813break;814815case MessageToken.SEAL_ALG_DES3_KD:816byte[] ctext = des3KdEncrypt(confounder, plaintext, pStart, pLen,817padding);818System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);819break;820821case MessageToken.SEAL_ALG_ARCFOUR_HMAC:822byte[] ctext2 = arcFourEncrypt(token, confounder, plaintext, pStart,823pLen, padding);824System.arraycopy(ctext2, 0, ciphertext, cStart, ctext2.length);825break;826827default:828throw new GSSException(GSSException.FAILURE, -1,829"Unsupported seal algorithm: " + sealAlg);830}831}832833/*834* Encrypt data in the new GSS tokens835*836* Wrap Tokens (with confidentiality)837* { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |838* 12-byte HMAC }839* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}840* HMAC is not encrypted; it is appended at the end.841*/842int encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,843byte[] plaintext, int pStart, int pLen, byte[] ciphertext, int cStart,844int key_usage) throws GSSException {845846byte[] ctext = null;847switch (etype) {848case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:849ctext = aes128Encrypt(confounder, tokenHeader,850plaintext, pStart, pLen, key_usage);851break;852case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:853ctext = aes256Encrypt(confounder, tokenHeader,854plaintext, pStart, pLen, key_usage);855break;856case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128:857ctext = aes128Sha2Encrypt(confounder, tokenHeader,858plaintext, pStart, pLen, key_usage);859break;860case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192:861ctext = aes256Sha2Encrypt(confounder, tokenHeader,862plaintext, pStart, pLen, key_usage);863break;864default:865throw new GSSException(GSSException.FAILURE, -1,866"Unsupported etype: " + etype);867}868System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);869return ctext.length;870}871872// --------------------- DES methods873874/**875* Computes the DesCbc checksum based on the algorithm published in FIPS876* Publication 113. This involves applying padding to the data passed877* in, then performing DesCbc encryption on the data with a zero initial878* vector, and finally returning the last 8 bytes of the encryption879* result.880*881* @param key the bytes for the DES key882* @param header a header to process first before the data is.883* @param data the data to checksum884* @param offset the offset where the data begins885* @param len the length of the data886* @throws GSSException when an error occuse in the encryption887*/888private byte[] getDesCbcChecksum(byte key[],889byte[] header,890byte[] data, int offset, int len)891throws GSSException {892893Cipher des = getInitializedDes(true, key, ZERO_IV);894895int blockSize = des.getBlockSize();896897/*898* Here the data need not be a multiple of the blocksize899* (8). Encrypt and throw away results for all blocks except for900* the very last block.901*/902903byte[] finalBlock = new byte[blockSize];904905int numBlocks = len / blockSize;906int lastBytes = len % blockSize;907if (lastBytes == 0) {908// No need for padding. Save last block from application data909numBlocks -= 1;910System.arraycopy(data, offset + numBlocks*blockSize,911finalBlock, 0, blockSize);912} else {913System.arraycopy(data, offset + numBlocks*blockSize,914finalBlock, 0, lastBytes);915// Zero padding automatically done916}917918try {919byte[] temp = new byte[Math.max(blockSize,920(header == null? blockSize : header.length))];921922if (header != null) {923// header will be null when doing DES-MD5 Checksum924des.update(header, 0, header.length, temp, 0);925}926927// Iterate over all but the last block928for (int i = 0; i < numBlocks; i++) {929des.update(data, offset, blockSize,930temp, 0);931offset += blockSize;932}933934// Now process the final block935byte[] retVal = new byte[blockSize];936des.update(finalBlock, 0, blockSize, retVal, 0);937des.doFinal();938939return retVal;940} catch (GeneralSecurityException e) {941GSSException ge = new GSSException(GSSException.FAILURE, -1,942"Could not use DES Cipher - " + e.getMessage());943ge.initCause(e);944throw ge;945}946}947948/**949* Obtains an initialized DES cipher.950*951* @param encryptMode true if encryption is desired, false is decryption952* is desired.953* @param key the bytes for the DES key954* @param ivBytes the initial vector bytes955*/956private final Cipher getInitializedDes(boolean encryptMode, byte[] key,957byte[] ivBytes)958throws GSSException {959960961try {962IvParameterSpec iv = new IvParameterSpec(ivBytes);963SecretKey jceKey = (SecretKey) (new SecretKeySpec(key, "DES"));964965Cipher desCipher = Cipher.getInstance("DES/CBC/NoPadding");966desCipher.init(967(encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),968jceKey, iv);969return desCipher;970} catch (GeneralSecurityException e) {971GSSException ge = new GSSException(GSSException.FAILURE, -1,972e.getMessage());973ge.initCause(e);974throw ge;975}976}977978/**979* Helper routine to decrypt fromm a byte array and write the980* application data straight to an output array with minimal981* buffer copies. The confounder and the padding are stored982* separately and not copied into this output array.983* @param key the DES key to use984* @param cipherText the encrypted data985* @param offset the offset for the encrypted data986* @param len the length of the encrypted data987* @param dataOutBuf the output buffer where the application data988* should be writte989* @param dataOffset the offser where the application data should990* be written.991* @throws GSSException is an error occurs while decrypting the992* data993*/994private void desCbcDecrypt(WrapToken token, byte[] key, byte[] cipherText,995int offset, int len, byte[] dataOutBuf, int dataOffset)996throws GSSException {997998try {9991000int temp = 0;10011002Cipher des = getInitializedDes(false, key, ZERO_IV);10031004/*1005* Remove the counfounder first.1006* CONFOUNDER_SIZE is one DES block ie 8 bytes.1007*/1008temp = des.update(cipherText, offset, WrapToken.CONFOUNDER_SIZE,1009token.confounder);1010// temp should be CONFOUNDER_SIZE1011// debug("\n\ttemp is " + temp + " and CONFOUNDER_SIZE is "1012// + CONFOUNDER_SIZE);10131014offset += WrapToken.CONFOUNDER_SIZE;1015len -= WrapToken.CONFOUNDER_SIZE;10161017/*1018* len is a multiple of 8 due to padding.1019* Decrypt all blocks directly into the output buffer except for1020* the very last block. Remove the trailing padding bytes from the1021* very last block and copy that into the output buffer.1022*/10231024int blockSize = des.getBlockSize();1025int numBlocks = len / blockSize - 1;10261027// Iterate over all but the last block1028for (int i = 0; i < numBlocks; i++) {1029temp = des.update(cipherText, offset, blockSize,1030dataOutBuf, dataOffset);1031// temp should be blockSize1032// debug("\n\ttemp is " + temp + " and blockSize is "1033// + blockSize);10341035offset += blockSize;1036dataOffset += blockSize;1037}10381039// Now process the last block1040byte[] finalBlock = new byte[blockSize];1041des.update(cipherText, offset, blockSize, finalBlock);10421043des.doFinal();10441045/*1046* There is always at least one padding byte. The padding bytes1047* are all the value of the number of padding bytes.1048*/10491050int padSize = finalBlock[blockSize - 1];1051if (padSize < 1 || padSize > 8)1052throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1053"Invalid padding on Wrap Token");1054token.padding = WrapToken.pads[padSize];1055blockSize -= padSize;10561057// Copy this last block into the output buffer1058System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,1059blockSize);10601061} catch (GeneralSecurityException e) {1062GSSException ge = new GSSException(GSSException.FAILURE, -1,1063"Could not use DES cipher - " + e.getMessage());1064ge.initCause(e);1065throw ge;1066}1067}10681069/**1070* Helper routine to decrypt from an InputStream and write the1071* application data straight to an output array with minimal1072* buffer copies. The confounder and the padding are stored1073* separately and not copied into this output array.1074* @param key the DES key to use1075* @param is the InputStream from which the cipher text should be1076* read1077* @param len the length of the ciphertext data1078* @param dataOutBuf the output buffer where the application data1079* should be writte1080* @param dataOffset the offser where the application data should1081* be written.1082* @throws GSSException is an error occurs while decrypting the1083* data1084*/1085private void desCbcDecrypt(WrapToken token, byte[] key,1086InputStream is, int len, byte[] dataOutBuf, int dataOffset)1087throws GSSException, IOException {10881089int temp = 0;10901091Cipher des = getInitializedDes(false, key, ZERO_IV);10921093WrapTokenInputStream truncatedInputStream =1094new WrapTokenInputStream(is, len);1095CipherInputStream cis = new CipherInputStream(truncatedInputStream,1096des);1097/*1098* Remove the counfounder first.1099* CONFOUNDER_SIZE is one DES block ie 8 bytes.1100*/1101temp = cis.read(token.confounder);11021103len -= temp;1104// temp should be CONFOUNDER_SIZE1105// debug("Got " + temp + " bytes; CONFOUNDER_SIZE is "1106// + CONFOUNDER_SIZE + "\n");1107// debug("Confounder is " + getHexBytes(confounder) + "\n");110811091110/*1111* len is a multiple of 8 due to padding.1112* Decrypt all blocks directly into the output buffer except for1113* the very last block. Remove the trailing padding bytes from the1114* very last block and copy that into the output buffer.1115*/11161117int blockSize = des.getBlockSize();1118int numBlocks = len / blockSize - 1;11191120// Iterate over all but the last block1121for (int i = 0; i < numBlocks; i++) {1122// debug("dataOffset is " + dataOffset + "\n");1123temp = cis.read(dataOutBuf, dataOffset, blockSize);11241125// temp should be blockSize1126// debug("Got " + temp + " bytes and blockSize is "1127// + blockSize + "\n");1128// debug("Bytes are: "1129// + getHexBytes(dataOutBuf, dataOffset, temp) + "\n");1130dataOffset += blockSize;1131}11321133// Now process the last block1134byte[] finalBlock = new byte[blockSize];1135// debug("Will call read on finalBlock" + "\n");1136temp = cis.read(finalBlock);1137// temp should be blockSize1138/*1139debug("Got " + temp + " bytes and blockSize is "1140+ blockSize + "\n");1141debug("Bytes are: "1142+ getHexBytes(finalBlock, 0, temp) + "\n");1143debug("Will call doFinal" + "\n");1144*/1145try {1146des.doFinal();1147} catch (GeneralSecurityException e) {1148GSSException ge = new GSSException(GSSException.FAILURE, -1,1149"Could not use DES cipher - " + e.getMessage());1150ge.initCause(e);1151throw ge;1152}11531154/*1155* There is always at least one padding byte. The padding bytes1156* are all the value of the number of padding bytes.1157*/11581159int padSize = finalBlock[blockSize - 1];1160if (padSize < 1 || padSize > 8)1161throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1162"Invalid padding on Wrap Token");1163token.padding = WrapToken.pads[padSize];1164blockSize -= padSize;11651166// Copy this last block into the output buffer1167System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,1168blockSize);1169}11701171private static byte[] getDesEncryptionKey(byte[] key)1172throws GSSException {11731174/*1175* To meet export control requirements, double check that the1176* key being used is no longer than 64 bits.1177*1178* Note that from a protocol point of view, an1179* algorithm that is not DES will be rejected before this1180* point. Also, a DES key that is not 64 bits will be1181* rejected by a good JCE provider.1182*/1183if (key.length > 8)1184throw new GSSException(GSSException.FAILURE, -100,1185"Invalid DES Key!");11861187byte[] retVal = new byte[key.length];1188for (int i = 0; i < key.length; i++)1189retVal[i] = (byte)(key[i] ^ 0xf0); // RFC 1964, Section 1.2.21190return retVal;1191}11921193// ---- DES3-KD methods1194private void des3KdDecrypt(WrapToken token, byte[] ciphertext,1195int cStart, int cLen, byte[] plaintext, int pStart)1196throws GSSException {1197byte[] ptext;1198try {1199ptext = Des3.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,1200ciphertext, cStart, cLen);1201} catch (GeneralSecurityException e) {1202GSSException ge = new GSSException(GSSException.FAILURE, -1,1203"Could not use DES3-KD Cipher - " + e.getMessage());1204ge.initCause(e);1205throw ge;1206}12071208/*1209Krb5Token.debug("\ndes3KdDecrypt in: " +1210Krb5Token.getHexBytes(ciphertext, cStart, cLen));1211Krb5Token.debug("\ndes3KdDecrypt plain: " +1212Krb5Token.getHexBytes(ptext));1213*/12141215// Strip out confounder and padding1216/*1217* There is always at least one padding byte. The padding bytes1218* are all the value of the number of padding bytes.1219*/1220int padSize = ptext[ptext.length - 1];1221if (padSize < 1 || padSize > 8)1222throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1223"Invalid padding on Wrap Token");12241225token.padding = WrapToken.pads[padSize];1226int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;12271228System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,1229plaintext, pStart, len);12301231// Needed to calculate checksum1232System.arraycopy(ptext, 0, token.confounder,12330, WrapToken.CONFOUNDER_SIZE);1234}12351236private byte[] des3KdEncrypt(byte[] confounder, byte[] plaintext,1237int start, int len, byte[] padding) throws GSSException {123812391240// [confounder | plaintext | padding]1241byte[] all = new byte[confounder.length + len + padding.length];1242System.arraycopy(confounder, 0, all, 0, confounder.length);1243System.arraycopy(plaintext, start, all, confounder.length, len);1244System.arraycopy(padding, 0, all, confounder.length + len,1245padding.length);12461247// Krb5Token.debug("\ndes3KdEncrypt:" + Krb5Token.getHexBytes(all));12481249// Encrypt1250try {1251byte[] answer = Des3.encryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,1252all, 0, all.length);1253// Krb5Token.debug("\ndes3KdEncrypt encrypted:" +1254// Krb5Token.getHexBytes(answer));1255return answer;1256} catch (Exception e) {1257// GeneralSecurityException, KrbCryptoException1258GSSException ge = new GSSException(GSSException.FAILURE, -1,1259"Could not use DES3-KD Cipher - " + e.getMessage());1260ge.initCause(e);1261throw ge;1262}1263}12641265// ---- RC4-HMAC methods1266private void arcFourDecrypt(WrapToken token, byte[] ciphertext,1267int cStart, int cLen, byte[] plaintext, int pStart)1268throws GSSException {12691270// obtain Sequence number needed for decryption1271// first decrypt the Sequence Number using checksum1272byte[] seqNum = decryptSeq(token.getChecksum(),1273token.getEncSeqNumber(), 0, 8);12741275byte[] ptext;1276try {1277ptext = ArcFourHmac.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,1278ciphertext, cStart, cLen, seqNum);1279} catch (GeneralSecurityException e) {1280GSSException ge = new GSSException(GSSException.FAILURE, -1,1281"Could not use ArcFour Cipher - " + e.getMessage());1282ge.initCause(e);1283throw ge;1284}12851286/*1287Krb5Token.debug("\narcFourDecrypt in: " +1288Krb5Token.getHexBytes(ciphertext, cStart, cLen));1289Krb5Token.debug("\narcFourDecrypt plain: " +1290Krb5Token.getHexBytes(ptext));1291*/12921293// Strip out confounder and padding1294/*1295* There is always at least one padding byte. The padding bytes1296* are all the value of the number of padding bytes.1297*/1298int padSize = ptext[ptext.length - 1];1299if (padSize < 1)1300throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1301"Invalid padding on Wrap Token");13021303token.padding = WrapToken.pads[padSize];1304int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;13051306System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,1307plaintext, pStart, len);13081309// Krb5Token.debug("\narcFourDecrypt plaintext: " +1310// Krb5Token.getHexBytes(plaintext));13111312// Needed to calculate checksum1313System.arraycopy(ptext, 0, token.confounder,13140, WrapToken.CONFOUNDER_SIZE);1315}13161317private byte[] arcFourEncrypt(WrapToken token, byte[] confounder,1318byte[] plaintext, int start, int len, byte[] padding)1319throws GSSException {13201321// [confounder | plaintext | padding]1322byte[] all = new byte[confounder.length + len + padding.length];1323System.arraycopy(confounder, 0, all, 0, confounder.length);1324System.arraycopy(plaintext, start, all, confounder.length, len);1325System.arraycopy(padding, 0, all, confounder.length + len,1326padding.length);13271328// get the token Sequence Number required for encryption1329// Note: When using this RC4 based encryption type, the sequence number1330// is always sent in big-endian rather than little-endian order.1331byte[] seqNum = new byte[4];1332WrapToken.writeBigEndian(token.getSequenceNumber(), seqNum);13331334// Krb5Token.debug("\narcFourEncrypt:" + Krb5Token.getHexBytes(all));13351336// Encrypt1337try {1338byte[] answer = ArcFourHmac.encryptRaw(keybytes, KG_USAGE_SEAL,1339seqNum, all, 0, all.length);1340// Krb5Token.debug("\narcFourEncrypt encrypted:" +1341// Krb5Token.getHexBytes(answer));1342return answer;1343} catch (Exception e) {1344// GeneralSecurityException, KrbCryptoException1345GSSException ge = new GSSException(GSSException.FAILURE, -1,1346"Could not use ArcFour Cipher - " + e.getMessage());1347ge.initCause(e);1348throw ge;1349}1350}13511352// ---- AES methods1353private byte[] aes128Encrypt(byte[] confounder, byte[] tokenHeader,1354byte[] plaintext, int start, int len, int key_usage)1355throws GSSException {13561357// encrypt { AES-plaintext-data | filler | header }1358// AES-plaintext-data { confounder | plaintext }1359// WrapToken = { tokenHeader |1360// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }13611362byte[] all = new byte[confounder.length + len + tokenHeader.length];1363System.arraycopy(confounder, 0, all, 0, confounder.length);1364System.arraycopy(plaintext, start, all, confounder.length, len);1365System.arraycopy(tokenHeader, 0, all, confounder.length+len,1366tokenHeader.length);13671368// Krb5Token.debug("\naes128Encrypt:" + Krb5Token.getHexBytes(all));1369try {1370byte[] answer = Aes128.encryptRaw(keybytes, key_usage,1371ZERO_IV_AES,1372all, 0, all.length);1373// Krb5Token.debug("\naes128Encrypt encrypted:" +1374// Krb5Token.getHexBytes(answer));1375return answer;1376} catch (Exception e) {1377// GeneralSecurityException, KrbCryptoException1378GSSException ge = new GSSException(GSSException.FAILURE, -1,1379"Could not use AES128 Cipher - " + e.getMessage());1380ge.initCause(e);1381throw ge;1382}1383}13841385private byte[] aes128Sha2Encrypt(byte[] confounder, byte[] tokenHeader,1386byte[] plaintext, int start, int len, int key_usage)1387throws GSSException {13881389// encrypt { AES-plaintext-data | filler | header }1390// AES-plaintext-data { confounder | plaintext }1391// WrapToken = { tokenHeader |1392// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }13931394byte[] all = new byte[confounder.length + len + tokenHeader.length];1395System.arraycopy(confounder, 0, all, 0, confounder.length);1396System.arraycopy(plaintext, start, all, confounder.length, len);1397System.arraycopy(tokenHeader, 0, all, confounder.length+len,1398tokenHeader.length);13991400// Krb5Token.debug("\naes128Sha2Encrypt:" + Krb5Token.getHexBytes(all));1401try {1402byte[] answer = Aes128Sha2.encryptRaw(keybytes, key_usage,1403ZERO_IV_AES,1404all, 0, all.length);1405// Krb5Token.debug("\naes128Sha2Encrypt encrypted:" +1406// Krb5Token.getHexBytes(answer));1407return answer;1408} catch (Exception e) {1409// GeneralSecurityException, KrbCryptoException1410GSSException ge = new GSSException(GSSException.FAILURE, -1,1411"Could not use Aes128Sha2 Cipher - " + e.getMessage());1412ge.initCause(e);1413throw ge;1414}1415}14161417private void aes128Decrypt(WrapToken_v2 token, byte[] ciphertext,1418int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)1419throws GSSException {14201421byte[] ptext = null;14221423try {1424ptext = Aes128.decryptRaw(keybytes, key_usage,1425ZERO_IV_AES, ciphertext, cStart, cLen);1426} catch (GeneralSecurityException e) {1427GSSException ge = new GSSException(GSSException.FAILURE, -1,1428"Could not use AES128 Cipher - " + e.getMessage());1429ge.initCause(e);1430throw ge;1431}14321433/*1434Krb5Token.debug("\naes128Decrypt in: " +1435Krb5Token.getHexBytes(ciphertext, cStart, cLen));1436Krb5Token.debug("\naes128Decrypt plain: " +1437Krb5Token.getHexBytes(ptext));1438Krb5Token.debug("\naes128Decrypt ptext: " +1439Krb5Token.getHexBytes(ptext));1440*/14411442// Strip out confounder and token header1443int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -1444WrapToken_v2.TOKEN_HEADER_SIZE;1445System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,1446plaintext, pStart, len);14471448/*1449Krb5Token.debug("\naes128Decrypt plaintext: " +1450Krb5Token.getHexBytes(plaintext, pStart, len));1451*/1452}14531454private void aes128Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext,1455int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)1456throws GSSException {14571458byte[] ptext = null;14591460try {1461ptext = Aes128Sha2.decryptRaw(keybytes, key_usage,1462ZERO_IV_AES, ciphertext, cStart, cLen);1463} catch (GeneralSecurityException e) {1464GSSException ge = new GSSException(GSSException.FAILURE, -1,1465"Could not use AES128Sha2 Cipher - " + e.getMessage());1466ge.initCause(e);1467throw ge;1468}14691470/*1471Krb5Token.debug("\naes128Sha2Decrypt in: " +1472Krb5Token.getHexBytes(ciphertext, cStart, cLen));1473Krb5Token.debug("\naes128Sha2Decrypt plain: " +1474Krb5Token.getHexBytes(ptext));1475Krb5Token.debug("\naes128Sha2Decrypt ptext: " +1476Krb5Token.getHexBytes(ptext));1477*/14781479// Strip out confounder and token header1480int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -1481WrapToken_v2.TOKEN_HEADER_SIZE;1482System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,1483plaintext, pStart, len);14841485/*1486Krb5Token.debug("\naes128Sha2Decrypt plaintext: " +1487Krb5Token.getHexBytes(plaintext, pStart, len));1488*/1489}14901491private byte[] aes256Encrypt(byte[] confounder, byte[] tokenHeader,1492byte[] plaintext, int start, int len, int key_usage)1493throws GSSException {14941495// encrypt { AES-plaintext-data | filler | header }1496// AES-plaintext-data { confounder | plaintext }1497// WrapToken = { tokenHeader |1498// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }14991500byte[] all = new byte[confounder.length + len + tokenHeader.length];1501System.arraycopy(confounder, 0, all, 0, confounder.length);1502System.arraycopy(plaintext, start, all, confounder.length, len);1503System.arraycopy(tokenHeader, 0, all, confounder.length+len,1504tokenHeader.length);15051506// Krb5Token.debug("\naes256Encrypt:" + Krb5Token.getHexBytes(all));15071508try {1509byte[] answer = Aes256.encryptRaw(keybytes, key_usage,1510ZERO_IV_AES, all, 0, all.length);1511// Krb5Token.debug("\naes256Encrypt encrypted:" +1512// Krb5Token.getHexBytes(answer));1513return answer;1514} catch (Exception e) {1515// GeneralSecurityException, KrbCryptoException1516GSSException ge = new GSSException(GSSException.FAILURE, -1,1517"Could not use AES256 Cipher - " + e.getMessage());1518ge.initCause(e);1519throw ge;1520}1521}15221523private byte[] aes256Sha2Encrypt(byte[] confounder, byte[] tokenHeader,1524byte[] plaintext, int start, int len, int key_usage)1525throws GSSException {15261527// encrypt { AES-plaintext-data | filler | header }1528// AES-plaintext-data { confounder | plaintext }1529// WrapToken = { tokenHeader |1530// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }15311532byte[] all = new byte[confounder.length + len + tokenHeader.length];1533System.arraycopy(confounder, 0, all, 0, confounder.length);1534System.arraycopy(plaintext, start, all, confounder.length, len);1535System.arraycopy(tokenHeader, 0, all, confounder.length+len,1536tokenHeader.length);15371538// Krb5Token.debug("\naes256Sha2Encrypt:" + Krb5Token.getHexBytes(all));15391540try {1541byte[] answer = Aes256Sha2.encryptRaw(keybytes, key_usage,1542ZERO_IV_AES, all, 0, all.length);1543// Krb5Token.debug("\naes256Sha2Encrypt encrypted:" +1544// Krb5Token.getHexBytes(answer));1545return answer;1546} catch (Exception e) {1547// GeneralSecurityException, KrbCryptoException1548GSSException ge = new GSSException(GSSException.FAILURE, -1,1549"Could not use Aes256Sha2 Cipher - " + e.getMessage());1550ge.initCause(e);1551throw ge;1552}1553}15541555private void aes256Decrypt(WrapToken_v2 token, byte[] ciphertext,1556int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)1557throws GSSException {15581559byte[] ptext;1560try {1561ptext = Aes256.decryptRaw(keybytes, key_usage,1562ZERO_IV_AES, ciphertext, cStart, cLen);1563} catch (GeneralSecurityException e) {1564GSSException ge = new GSSException(GSSException.FAILURE, -1,1565"Could not use AES128 Cipher - " + e.getMessage());1566ge.initCause(e);1567throw ge;1568}15691570/*1571Krb5Token.debug("\naes256Decrypt in: " +1572Krb5Token.getHexBytes(ciphertext, cStart, cLen));1573Krb5Token.debug("\naes256Decrypt plain: " +1574Krb5Token.getHexBytes(ptext));1575Krb5Token.debug("\naes256Decrypt ptext: " +1576Krb5Token.getHexBytes(ptext));1577*/15781579// Strip out confounder and token header1580int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -1581WrapToken_v2.TOKEN_HEADER_SIZE;1582System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,1583plaintext, pStart, len);15841585/*1586Krb5Token.debug("\naes128Decrypt plaintext: " +1587Krb5Token.getHexBytes(plaintext, pStart, len));1588*/15891590}15911592private void aes256Sha2Decrypt(WrapToken_v2 token, byte[] ciphertext,1593int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)1594throws GSSException {15951596byte[] ptext;1597try {1598ptext = Aes256Sha2.decryptRaw(keybytes, key_usage,1599ZERO_IV_AES, ciphertext, cStart, cLen);1600} catch (GeneralSecurityException e) {1601GSSException ge = new GSSException(GSSException.FAILURE, -1,1602"Could not use AES256Sha2 Cipher - " + e.getMessage());1603ge.initCause(e);1604throw ge;1605}16061607/*1608Krb5Token.debug("\naes256Sha2Decrypt in: " +1609Krb5Token.getHexBytes(ciphertext, cStart, cLen));1610Krb5Token.debug("\naes256Sha2Decrypt plain: " +1611Krb5Token.getHexBytes(ptext));1612Krb5Token.debug("\naes256Sha2Decrypt ptext: " +1613Krb5Token.getHexBytes(ptext));1614*/16151616// Strip out confounder and token header1617int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -1618WrapToken_v2.TOKEN_HEADER_SIZE;1619System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,1620plaintext, pStart, len);16211622/*1623Krb5Token.debug("\naes256Sha2Decrypt plaintext: " +1624Krb5Token.getHexBytes(plaintext, pStart, len));1625*/16261627}16281629/**1630* This class provides a truncated inputstream needed by WrapToken. The1631* truncated inputstream is passed to CipherInputStream. It prevents1632* the CipherInputStream from treating the bytes of the following token1633* as part fo the ciphertext for this token.1634*/1635class WrapTokenInputStream extends InputStream {16361637private InputStream is;1638private int length;1639private int remaining;16401641private int temp;16421643public WrapTokenInputStream(InputStream is, int length) {1644this.is = is;1645this.length = length;1646remaining = length;1647}16481649public final int read() throws IOException {1650if (remaining == 0)1651return -1;1652else {1653temp = is.read();1654if (temp != -1)1655remaining -= temp;1656return temp;1657}1658}16591660public final int read(byte[] b) throws IOException {1661if (remaining == 0)1662return -1;1663else {1664temp = Math.min(remaining, b.length);1665temp = is.read(b, 0, temp);1666if (temp != -1)1667remaining -= temp;1668return temp;1669}1670}16711672public final int read(byte[] b,1673int off,1674int len) throws IOException {1675if (remaining == 0)1676return -1;1677else {1678temp = Math.min(remaining, len);1679temp = is.read(b, off, temp);1680if (temp != -1)1681remaining -= temp;1682return temp;1683}1684}16851686public final long skip(long n) throws IOException {1687if (remaining == 0)1688return 0;1689else {1690temp = (int) Math.min(remaining, n);1691temp = (int) is.skip(temp);1692remaining -= temp;1693return temp;1694}1695}16961697public final int available() throws IOException {1698return Math.min(remaining, is.available());1699}17001701public final void close() throws IOException {1702remaining = 0;1703}1704}1705}170617071708