Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/jgss/krb5/CipherHelper.java
38922 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.Des3;43import sun.security.krb5.internal.crypto.Aes128;44import sun.security.krb5.internal.crypto.Aes256;45import sun.security.krb5.internal.crypto.ArcFourHmac;46import sun.security.krb5.internal.crypto.EType;4748class CipherHelper {4950// From draft-raeburn-cat-gssapi-krb5-3des-0051// Key usage values when deriving keys52private static final int KG_USAGE_SEAL = 22;53private static final int KG_USAGE_SIGN = 23;54private static final int KG_USAGE_SEQ = 24;5556private static final int DES_CHECKSUM_SIZE = 8;57private static final int DES_IV_SIZE = 8;58private static final int AES_IV_SIZE = 16;5960// ARCFOUR-HMAC61// Save first 8 octets of HMAC Sgn_Cksum62private static final int HMAC_CHECKSUM_SIZE = 8;63// key usage for MIC tokens used by MS64private static final int KG_USAGE_SIGN_MS = 15;6566// debug flag67private static final boolean DEBUG = Krb5Util.DEBUG;6869/**70* A zero initial vector to be used for checksum calculation and for71* DesCbc application data encryption/decryption.72*/73private static final byte[] ZERO_IV = new byte[DES_IV_SIZE];74private static final byte[] ZERO_IV_AES = new byte[AES_IV_SIZE];7576private int etype;77private int sgnAlg, sealAlg;78private byte[] keybytes;7980CipherHelper(EncryptionKey key) throws GSSException {81etype = key.getEType();82keybytes = key.getBytes();8384switch (etype) {85case EncryptedData.ETYPE_DES_CBC_CRC:86case EncryptedData.ETYPE_DES_CBC_MD5:87sgnAlg = MessageToken.SGN_ALG_DES_MAC_MD5;88sealAlg = MessageToken.SEAL_ALG_DES;89break;9091case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:92sgnAlg = MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD;93sealAlg = MessageToken.SEAL_ALG_DES3_KD;94break;9596case EncryptedData.ETYPE_ARCFOUR_HMAC:97sgnAlg = MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR;98sealAlg = MessageToken.SEAL_ALG_ARCFOUR_HMAC;99break;100101case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:102case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:103sgnAlg = -1;104sealAlg = -1;105break;106107default:108throw new GSSException(GSSException.FAILURE, -1,109"Unsupported encryption type: " + etype);110}111}112113int getSgnAlg() {114return sgnAlg;115}116117int getSealAlg() {118return sealAlg;119}120121// new token format from draft-ietf-krb-wg-gssapi-cfx-07122// proto is used to determine new GSS token format for "newer" etypes123int getProto() {124return EType.isNewer(etype) ? 1 : 0;125}126127int getEType() {128return etype;129}130131boolean isArcFour() {132boolean flag = false;133if (etype == EncryptedData.ETYPE_ARCFOUR_HMAC) {134flag = true;135}136return flag;137}138139@SuppressWarnings("fallthrough")140byte[] calculateChecksum(int alg, byte[] header, byte[] trailer,141byte[] data, int start, int len, int tokenId) throws GSSException {142143switch (alg) {144case MessageToken.SGN_ALG_DES_MAC_MD5:145/*146* With this sign algorithm, first an MD5 hash is computed on the147* application data. The 16 byte hash is then DesCbc encrypted.148*/149try {150MessageDigest md5 = MessageDigest.getInstance("MD5");151152// debug("\t\tdata=[");153154// debug(getHexBytes(checksumDataHeader,155// checksumDataHeader.length) + " ");156md5.update(header);157158// debug(getHexBytes(data, start, len));159md5.update(data, start, len);160161if (trailer != null) {162// debug(" " +163// getHexBytes(trailer,164// optionalTrailer.length));165md5.update(trailer);166}167// debug("]\n");168169data = md5.digest();170start = 0;171len = data.length;172// System.out.println("\tMD5 Checksum is [" +173// getHexBytes(data) + "]\n");174header = null;175trailer = null;176} catch (NoSuchAlgorithmException e) {177GSSException ge = new GSSException(GSSException.FAILURE, -1,178"Could not get MD5 Message Digest - " + e.getMessage());179ge.initCause(e);180throw ge;181}182// fall through to encrypt checksum183184case MessageToken.SGN_ALG_DES_MAC:185return getDesCbcChecksum(keybytes, header, data, start, len);186187case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:188byte[] buf;189int offset, total;190if (header == null && trailer == null) {191buf = data;192total = len;193offset = start;194} else {195total = ((header != null ? header.length : 0) + len +196(trailer != null ? trailer.length : 0));197198buf = new byte[total];199int pos = 0;200if (header != null) {201System.arraycopy(header, 0, buf, 0, header.length);202pos = header.length;203}204System.arraycopy(data, start, buf, pos, len);205pos += len;206if (trailer != null) {207System.arraycopy(trailer, 0, buf, pos, trailer.length);208}209210offset = 0;211}212213try {214215/*216Krb5Token.debug("\nkeybytes: " +217Krb5Token.getHexBytes(keybytes));218Krb5Token.debug("\nheader: " + (header == null ? "NONE" :219Krb5Token.getHexBytes(header)));220Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :221Krb5Token.getHexBytes(trailer)));222Krb5Token.debug("\ndata: " +223Krb5Token.getHexBytes(data, start, len));224Krb5Token.debug("\nbuf: " + Krb5Token.getHexBytes(buf, offset,225total));226*/227228byte[] answer = Des3.calculateChecksum(keybytes,229KG_USAGE_SIGN, buf, offset, total);230// Krb5Token.debug("\nanswer: " +231// Krb5Token.getHexBytes(answer));232return answer;233} catch (GeneralSecurityException e) {234GSSException ge = new GSSException(GSSException.FAILURE, -1,235"Could not use HMAC-SHA1-DES3-KD signing algorithm - " +236e.getMessage());237ge.initCause(e);238throw ge;239}240241case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:242byte[] buffer;243int off, tot;244if (header == null && trailer == null) {245buffer = data;246tot = len;247off = start;248} else {249tot = ((header != null ? header.length : 0) + len +250(trailer != null ? trailer.length : 0));251252buffer = new byte[tot];253int pos = 0;254255if (header != null) {256System.arraycopy(header, 0, buffer, 0, header.length);257pos = header.length;258}259System.arraycopy(data, start, buffer, pos, len);260pos += len;261if (trailer != null) {262System.arraycopy(trailer, 0, buffer, pos, trailer.length);263}264265off = 0;266}267268try {269270/*271Krb5Token.debug("\nkeybytes: " +272Krb5Token.getHexBytes(keybytes));273Krb5Token.debug("\nheader: " + (header == null ? "NONE" :274Krb5Token.getHexBytes(header)));275Krb5Token.debug("\ntrailer: " + (trailer == null ? "NONE" :276Krb5Token.getHexBytes(trailer)));277Krb5Token.debug("\ndata: " +278Krb5Token.getHexBytes(data, start, len));279Krb5Token.debug("\nbuffer: " +280Krb5Token.getHexBytes(buffer, off, tot));281*/282283// for MIC tokens, key derivation salt is 15284// NOTE: Required for interoperability. The RC4-HMAC spec285// defines key_usage of 23, however all Kerberos impl.286// MS/Solaris/MIT all use key_usage of 15 for MIC tokens287int key_usage = KG_USAGE_SIGN;288if (tokenId == Krb5Token.MIC_ID) {289key_usage = KG_USAGE_SIGN_MS;290}291byte[] answer = ArcFourHmac.calculateChecksum(keybytes,292key_usage, buffer, off, tot);293// Krb5Token.debug("\nanswer: " +294// Krb5Token.getHexBytes(answer));295296// Save first 8 octets of HMAC Sgn_Cksum297byte[] output = new byte[getChecksumLength()];298System.arraycopy(answer, 0, output, 0, output.length);299// Krb5Token.debug("\nanswer (trimmed): " +300// Krb5Token.getHexBytes(output));301return output;302} catch (GeneralSecurityException e) {303GSSException ge = new GSSException(GSSException.FAILURE, -1,304"Could not use HMAC_MD5_ARCFOUR signing algorithm - " +305e.getMessage());306ge.initCause(e);307throw ge;308}309310default:311throw new GSSException(GSSException.FAILURE, -1,312"Unsupported signing algorithm: " + sgnAlg);313}314}315316// calculate Checksum for the new GSS tokens317byte[] calculateChecksum(byte[] header, byte[] data, int start, int len,318int key_usage) throws GSSException {319320// total length321int total = ((header != null ? header.length : 0) + len);322323// get_mic("plaintext-data" | "header")324byte[] buf = new byte[total];325326// data327System.arraycopy(data, start, buf, 0, len);328329// token header330if (header != null) {331System.arraycopy(header, 0, buf, len, header.length);332}333334// Krb5Token.debug("\nAES calculate checksum on: " +335// Krb5Token.getHexBytes(buf));336switch (etype) {337case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:338try {339byte[] answer = Aes128.calculateChecksum(keybytes, key_usage,340buf, 0, total);341// Krb5Token.debug("\nAES128 checksum: " +342// Krb5Token.getHexBytes(answer));343return answer;344} catch (GeneralSecurityException e) {345GSSException ge = new GSSException(GSSException.FAILURE, -1,346"Could not use AES128 signing algorithm - " +347e.getMessage());348ge.initCause(e);349throw ge;350}351352case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:353try {354byte[] answer = Aes256.calculateChecksum(keybytes, key_usage,355buf, 0, total);356// Krb5Token.debug("\nAES256 checksum: " +357// Krb5Token.getHexBytes(answer));358return answer;359} catch (GeneralSecurityException e) {360GSSException ge = new GSSException(GSSException.FAILURE, -1,361"Could not use AES256 signing algorithm - " +362e.getMessage());363ge.initCause(e);364throw ge;365}366367default:368throw new GSSException(GSSException.FAILURE, -1,369"Unsupported encryption type: " + etype);370}371}372373byte[] encryptSeq(byte[] ivec, byte[] plaintext, int start, int len)374throws GSSException {375376switch (sgnAlg) {377case MessageToken.SGN_ALG_DES_MAC_MD5:378case MessageToken.SGN_ALG_DES_MAC:379try {380Cipher des = getInitializedDes(true, keybytes, ivec);381return des.doFinal(plaintext, start, len);382383} catch (GeneralSecurityException e) {384GSSException ge = new GSSException(GSSException.FAILURE, -1,385"Could not encrypt sequence number using DES - " +386e.getMessage());387ge.initCause(e);388throw ge;389}390391case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:392byte[] iv;393if (ivec.length == DES_IV_SIZE) {394iv = ivec;395} else {396iv = new byte[DES_IV_SIZE];397System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);398}399try {400return Des3.encryptRaw(keybytes, KG_USAGE_SEQ, iv,401plaintext, start, len);402} catch (Exception e) {403// GeneralSecurityException, KrbCryptoException404GSSException ge = new GSSException(GSSException.FAILURE, -1,405"Could not encrypt sequence number using DES3-KD - " +406e.getMessage());407ge.initCause(e);408throw ge;409}410411case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:412// ivec passed is the checksum413byte[] checksum;414if (ivec.length == HMAC_CHECKSUM_SIZE) {415checksum = ivec;416} else {417checksum = new byte[HMAC_CHECKSUM_SIZE];418System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);419}420421try {422return ArcFourHmac.encryptSeq(keybytes, KG_USAGE_SEQ, checksum,423plaintext, start, len);424} catch (Exception e) {425// GeneralSecurityException, KrbCryptoException426GSSException ge = new GSSException(GSSException.FAILURE, -1,427"Could not encrypt sequence number using RC4-HMAC - " +428e.getMessage());429ge.initCause(e);430throw ge;431}432433default:434throw new GSSException(GSSException.FAILURE, -1,435"Unsupported signing algorithm: " + sgnAlg);436}437}438439byte[] decryptSeq(byte[] ivec, byte[] ciphertext, int start, int len)440throws GSSException {441442switch (sgnAlg) {443case MessageToken.SGN_ALG_DES_MAC_MD5:444case MessageToken.SGN_ALG_DES_MAC:445try {446Cipher des = getInitializedDes(false, keybytes, ivec);447return des.doFinal(ciphertext, start, len);448} catch (GeneralSecurityException e) {449GSSException ge = new GSSException(GSSException.FAILURE, -1,450"Could not decrypt sequence number using DES - " +451e.getMessage());452ge.initCause(e);453throw ge;454}455456case MessageToken.SGN_ALG_HMAC_SHA1_DES3_KD:457byte[] iv;458if (ivec.length == DES_IV_SIZE) {459iv = ivec;460} else {461iv = new byte[8];462System.arraycopy(ivec, 0, iv, 0, DES_IV_SIZE);463}464465try {466return Des3.decryptRaw(keybytes, KG_USAGE_SEQ, iv,467ciphertext, start, len);468} catch (Exception e) {469// GeneralSecurityException, KrbCryptoException470GSSException ge = new GSSException(GSSException.FAILURE, -1,471"Could not decrypt sequence number using DES3-KD - " +472e.getMessage());473ge.initCause(e);474throw ge;475}476477case MessageToken.SGN_ALG_HMAC_MD5_ARCFOUR:478// ivec passed is the checksum479byte[] checksum;480if (ivec.length == HMAC_CHECKSUM_SIZE) {481checksum = ivec;482} else {483checksum = new byte[HMAC_CHECKSUM_SIZE];484System.arraycopy(ivec, 0, checksum, 0, HMAC_CHECKSUM_SIZE);485}486487try {488return ArcFourHmac.decryptSeq(keybytes, KG_USAGE_SEQ, checksum,489ciphertext, start, len);490} catch (Exception e) {491// GeneralSecurityException, KrbCryptoException492GSSException ge = new GSSException(GSSException.FAILURE, -1,493"Could not decrypt sequence number using RC4-HMAC - " +494e.getMessage());495ge.initCause(e);496throw ge;497}498499default:500throw new GSSException(GSSException.FAILURE, -1,501"Unsupported signing algorithm: " + sgnAlg);502}503}504505int getChecksumLength() throws GSSException {506switch (etype) {507case EncryptedData.ETYPE_DES_CBC_CRC:508case EncryptedData.ETYPE_DES_CBC_MD5:509return DES_CHECKSUM_SIZE;510511case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:512return Des3.getChecksumLength();513514case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:515return Aes128.getChecksumLength();516case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:517return Aes256.getChecksumLength();518519case EncryptedData.ETYPE_ARCFOUR_HMAC:520// only first 8 octets of HMAC Sgn_Cksum are used521return HMAC_CHECKSUM_SIZE;522523default:524throw new GSSException(GSSException.FAILURE, -1,525"Unsupported encryption type: " + etype);526}527}528529void decryptData(WrapToken token, byte[] ciphertext, int cStart, int cLen,530byte[] plaintext, int pStart) throws GSSException {531532/*533Krb5Token.debug("decryptData : ciphertext = " +534Krb5Token.getHexBytes(ciphertext));535*/536537switch (sealAlg) {538case MessageToken.SEAL_ALG_DES:539desCbcDecrypt(token, getDesEncryptionKey(keybytes),540ciphertext, cStart, cLen, plaintext, pStart);541break;542543case MessageToken.SEAL_ALG_DES3_KD:544des3KdDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);545break;546547case MessageToken.SEAL_ALG_ARCFOUR_HMAC:548arcFourDecrypt(token, ciphertext, cStart, cLen, plaintext, pStart);549break;550551default:552throw new GSSException(GSSException.FAILURE, -1,553"Unsupported seal algorithm: " + sealAlg);554}555}556557// decrypt data in the new GSS tokens558void decryptData(WrapToken_v2 token, byte[] ciphertext, int cStart,559int cLen, byte[] plaintext, int pStart, int key_usage)560throws GSSException {561562/*563Krb5Token.debug("decryptData : ciphertext = " +564Krb5Token.getHexBytes(ciphertext));565*/566567switch (etype) {568case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:569aes128Decrypt(token, ciphertext, cStart, cLen,570plaintext, pStart, key_usage);571break;572case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:573aes256Decrypt(token, ciphertext, cStart, cLen,574plaintext, pStart, key_usage);575break;576default:577throw new GSSException(GSSException.FAILURE, -1,578"Unsupported etype: " + etype);579}580}581582void decryptData(WrapToken token, InputStream cipherStream, int cLen,583byte[] plaintext, int pStart)584throws GSSException, IOException {585586switch (sealAlg) {587case MessageToken.SEAL_ALG_DES:588desCbcDecrypt(token, getDesEncryptionKey(keybytes),589cipherStream, cLen, plaintext, pStart);590break;591592case MessageToken.SEAL_ALG_DES3_KD:593594// Read encrypted data from stream595byte[] ciphertext = new byte[cLen];596try {597Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);598} catch (IOException e) {599GSSException ge = new GSSException(600GSSException.DEFECTIVE_TOKEN, -1,601"Cannot read complete token");602ge.initCause(e);603throw ge;604}605606des3KdDecrypt(token, ciphertext, 0, cLen, plaintext, pStart);607break;608609case MessageToken.SEAL_ALG_ARCFOUR_HMAC:610611// Read encrypted data from stream612byte[] ctext = new byte[cLen];613try {614Krb5Token.readFully(cipherStream, ctext, 0, cLen);615} catch (IOException e) {616GSSException ge = new GSSException(617GSSException.DEFECTIVE_TOKEN, -1,618"Cannot read complete token");619ge.initCause(e);620throw ge;621}622623arcFourDecrypt(token, ctext, 0, cLen, plaintext, pStart);624break;625626default:627throw new GSSException(GSSException.FAILURE, -1,628"Unsupported seal algorithm: " + sealAlg);629}630}631632void decryptData(WrapToken_v2 token, InputStream cipherStream, int cLen,633byte[] plaintext, int pStart, int key_usage)634throws GSSException, IOException {635636// Read encrypted data from stream637byte[] ciphertext = new byte[cLen];638try {639Krb5Token.readFully(cipherStream, ciphertext, 0, cLen);640} catch (IOException e) {641GSSException ge = new GSSException(642GSSException.DEFECTIVE_TOKEN, -1,643"Cannot read complete token");644ge.initCause(e);645throw ge;646}647switch (etype) {648case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:649aes128Decrypt(token, ciphertext, 0, cLen,650plaintext, pStart, key_usage);651break;652case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:653aes256Decrypt(token, ciphertext, 0, cLen,654plaintext, pStart, key_usage);655break;656default:657throw new GSSException(GSSException.FAILURE, -1,658"Unsupported etype: " + etype);659}660}661662void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,663int start, int len, byte[] padding, OutputStream os)664throws GSSException, IOException {665666switch (sealAlg) {667case MessageToken.SEAL_ALG_DES:668// Encrypt on the fly and write669Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),670ZERO_IV);671CipherOutputStream cos = new CipherOutputStream(os, des);672// debug(getHexBytes(confounder, confounder.length));673cos.write(confounder);674// debug(" " + getHexBytes(plaintext, start, len));675cos.write(plaintext, start, len);676// debug(" " + getHexBytes(padding, padding.length));677cos.write(padding);678break;679680case MessageToken.SEAL_ALG_DES3_KD:681byte[] ctext = des3KdEncrypt(confounder, plaintext, start, len,682padding);683684// Write to stream685os.write(ctext);686break;687688case MessageToken.SEAL_ALG_ARCFOUR_HMAC:689byte[] ciphertext = arcFourEncrypt(token, confounder, plaintext,690start, len, padding);691692// Write to stream693os.write(ciphertext);694break;695696default:697throw new GSSException(GSSException.FAILURE, -1,698"Unsupported seal algorithm: " + sealAlg);699}700}701702/*703* Encrypt data in the new GSS tokens704*705* Wrap Tokens (with confidentiality)706* { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |707* 12-byte HMAC }708* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}709* HMAC is not encrypted; it is appended at the end.710*/711byte[] encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,712byte[] plaintext, int start, int len, int key_usage)713throws GSSException {714715switch (etype) {716case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:717return aes128Encrypt(confounder, tokenHeader,718plaintext, start, len, key_usage);719case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:720return aes256Encrypt(confounder, tokenHeader,721plaintext, start, len, key_usage);722default:723throw new GSSException(GSSException.FAILURE, -1,724"Unsupported etype: " + etype);725}726}727728void encryptData(WrapToken token, byte[] confounder, byte[] plaintext,729int pStart, int pLen, byte[] padding, byte[] ciphertext, int cStart)730throws GSSException {731732switch (sealAlg) {733case MessageToken.SEAL_ALG_DES:734int pos = cStart;735// Encrypt and write736Cipher des = getInitializedDes(true, getDesEncryptionKey(keybytes),737ZERO_IV);738try {739// debug(getHexBytes(confounder, confounder.length));740pos += des.update(confounder, 0, confounder.length,741ciphertext, pos);742// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));743pos += des.update(plaintext, pStart, pLen,744ciphertext, pos);745// debug(" " + getHexBytes(padding, padding.length));746des.update(padding, 0, padding.length,747ciphertext, pos);748des.doFinal();749} catch (GeneralSecurityException e) {750GSSException ge = new GSSException(GSSException.FAILURE, -1,751"Could not use DES Cipher - " + e.getMessage());752ge.initCause(e);753throw ge;754}755break;756757case MessageToken.SEAL_ALG_DES3_KD:758byte[] ctext = des3KdEncrypt(confounder, plaintext, pStart, pLen,759padding);760System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);761break;762763case MessageToken.SEAL_ALG_ARCFOUR_HMAC:764byte[] ctext2 = arcFourEncrypt(token, confounder, plaintext, pStart,765pLen, padding);766System.arraycopy(ctext2, 0, ciphertext, cStart, ctext2.length);767break;768769default:770throw new GSSException(GSSException.FAILURE, -1,771"Unsupported seal algorithm: " + sealAlg);772}773}774775/*776* Encrypt data in the new GSS tokens777*778* Wrap Tokens (with confidentiality)779* { Encrypt(16-byte confounder | plaintext | 16-byte token_header) |780* 12-byte HMAC }781* where HMAC is on {16-byte confounder | plaintext | 16-byte token_header}782* HMAC is not encrypted; it is appended at the end.783*/784int encryptData(WrapToken_v2 token, byte[] confounder, byte[] tokenHeader,785byte[] plaintext, int pStart, int pLen, byte[] ciphertext, int cStart,786int key_usage) throws GSSException {787788byte[] ctext = null;789switch (etype) {790case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:791ctext = aes128Encrypt(confounder, tokenHeader,792plaintext, pStart, pLen, key_usage);793break;794case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:795ctext = aes256Encrypt(confounder, tokenHeader,796plaintext, pStart, pLen, key_usage);797break;798default:799throw new GSSException(GSSException.FAILURE, -1,800"Unsupported etype: " + etype);801}802System.arraycopy(ctext, 0, ciphertext, cStart, ctext.length);803return ctext.length;804}805806// --------------------- DES methods807808/**809* Computes the DesCbc checksum based on the algorithm published in FIPS810* Publication 113. This involves applying padding to the data passed811* in, then performing DesCbc encryption on the data with a zero initial812* vector, and finally returning the last 8 bytes of the encryption813* result.814*815* @param key the bytes for the DES key816* @param header a header to process first before the data is.817* @param data the data to checksum818* @param offset the offset where the data begins819* @param len the length of the data820* @throws GSSException when an error occuse in the encryption821*/822private byte[] getDesCbcChecksum(byte key[],823byte[] header,824byte[] data, int offset, int len)825throws GSSException {826827Cipher des = getInitializedDes(true, key, ZERO_IV);828829int blockSize = des.getBlockSize();830831/*832* Here the data need not be a multiple of the blocksize833* (8). Encrypt and throw away results for all blocks except for834* the very last block.835*/836837byte[] finalBlock = new byte[blockSize];838839int numBlocks = len / blockSize;840int lastBytes = len % blockSize;841if (lastBytes == 0) {842// No need for padding. Save last block from application data843numBlocks -= 1;844System.arraycopy(data, offset + numBlocks*blockSize,845finalBlock, 0, blockSize);846} else {847System.arraycopy(data, offset + numBlocks*blockSize,848finalBlock, 0, lastBytes);849// Zero padding automatically done850}851852try {853byte[] temp = new byte[Math.max(blockSize,854(header == null? blockSize : header.length))];855856if (header != null) {857// header will be null when doing DES-MD5 Checksum858des.update(header, 0, header.length, temp, 0);859}860861// Iterate over all but the last block862for (int i = 0; i < numBlocks; i++) {863des.update(data, offset, blockSize,864temp, 0);865offset += blockSize;866}867868// Now process the final block869byte[] retVal = new byte[blockSize];870des.update(finalBlock, 0, blockSize, retVal, 0);871des.doFinal();872873return retVal;874} catch (GeneralSecurityException e) {875GSSException ge = new GSSException(GSSException.FAILURE, -1,876"Could not use DES Cipher - " + e.getMessage());877ge.initCause(e);878throw ge;879}880}881882/**883* Obtains an initialized DES cipher.884*885* @param encryptMode true if encryption is desired, false is decryption886* is desired.887* @param key the bytes for the DES key888* @param ivBytes the initial vector bytes889*/890private final Cipher getInitializedDes(boolean encryptMode, byte[] key,891byte[] ivBytes)892throws GSSException {893894895try {896IvParameterSpec iv = new IvParameterSpec(ivBytes);897SecretKey jceKey = (SecretKey) (new SecretKeySpec(key, "DES"));898899Cipher desCipher = Cipher.getInstance("DES/CBC/NoPadding");900desCipher.init(901(encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),902jceKey, iv);903return desCipher;904} catch (GeneralSecurityException e) {905GSSException ge = new GSSException(GSSException.FAILURE, -1,906e.getMessage());907ge.initCause(e);908throw ge;909}910}911912/**913* Helper routine to decrypt fromm a byte array and write the914* application data straight to an output array with minimal915* buffer copies. The confounder and the padding are stored916* separately and not copied into this output array.917* @param key the DES key to use918* @param cipherText the encrypted data919* @param offset the offset for the encrypted data920* @param len the length of the encrypted data921* @param dataOutBuf the output buffer where the application data922* should be writte923* @param dataOffset the offser where the application data should924* be written.925* @throws GSSException is an error occurs while decrypting the926* data927*/928private void desCbcDecrypt(WrapToken token, byte[] key, byte[] cipherText,929int offset, int len, byte[] dataOutBuf, int dataOffset)930throws GSSException {931932try {933934int temp = 0;935936Cipher des = getInitializedDes(false, key, ZERO_IV);937938/*939* Remove the counfounder first.940* CONFOUNDER_SIZE is one DES block ie 8 bytes.941*/942temp = des.update(cipherText, offset, WrapToken.CONFOUNDER_SIZE,943token.confounder);944// temp should be CONFOUNDER_SIZE945// debug("\n\ttemp is " + temp + " and CONFOUNDER_SIZE is "946// + CONFOUNDER_SIZE);947948offset += WrapToken.CONFOUNDER_SIZE;949len -= WrapToken.CONFOUNDER_SIZE;950951/*952* len is a multiple of 8 due to padding.953* Decrypt all blocks directly into the output buffer except for954* the very last block. Remove the trailing padding bytes from the955* very last block and copy that into the output buffer.956*/957958int blockSize = des.getBlockSize();959int numBlocks = len / blockSize - 1;960961// Iterate over all but the last block962for (int i = 0; i < numBlocks; i++) {963temp = des.update(cipherText, offset, blockSize,964dataOutBuf, dataOffset);965// temp should be blockSize966// debug("\n\ttemp is " + temp + " and blockSize is "967// + blockSize);968969offset += blockSize;970dataOffset += blockSize;971}972973// Now process the last block974byte[] finalBlock = new byte[blockSize];975des.update(cipherText, offset, blockSize, finalBlock);976977des.doFinal();978979/*980* There is always at least one padding byte. The padding bytes981* are all the value of the number of padding bytes.982*/983984int padSize = finalBlock[blockSize - 1];985if (padSize < 1 || padSize > 8)986throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,987"Invalid padding on Wrap Token");988token.padding = WrapToken.pads[padSize];989blockSize -= padSize;990991// Copy this last block into the output buffer992System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,993blockSize);994995} catch (GeneralSecurityException e) {996GSSException ge = new GSSException(GSSException.FAILURE, -1,997"Could not use DES cipher - " + e.getMessage());998ge.initCause(e);999throw ge;1000}1001}10021003/**1004* Helper routine to decrypt from an InputStream and write the1005* application data straight to an output array with minimal1006* buffer copies. The confounder and the padding are stored1007* separately and not copied into this output array.1008* @param key the DES key to use1009* @param is the InputStream from which the cipher text should be1010* read1011* @param len the length of the ciphertext data1012* @param dataOutBuf the output buffer where the application data1013* should be writte1014* @param dataOffset the offser where the application data should1015* be written.1016* @throws GSSException is an error occurs while decrypting the1017* data1018*/1019private void desCbcDecrypt(WrapToken token, byte[] key,1020InputStream is, int len, byte[] dataOutBuf, int dataOffset)1021throws GSSException, IOException {10221023int temp = 0;10241025Cipher des = getInitializedDes(false, key, ZERO_IV);10261027WrapTokenInputStream truncatedInputStream =1028new WrapTokenInputStream(is, len);1029CipherInputStream cis = new CipherInputStream(truncatedInputStream,1030des);1031/*1032* Remove the counfounder first.1033* CONFOUNDER_SIZE is one DES block ie 8 bytes.1034*/1035temp = cis.read(token.confounder);10361037len -= temp;1038// temp should be CONFOUNDER_SIZE1039// debug("Got " + temp + " bytes; CONFOUNDER_SIZE is "1040// + CONFOUNDER_SIZE + "\n");1041// debug("Confounder is " + getHexBytes(confounder) + "\n");104210431044/*1045* len is a multiple of 8 due to padding.1046* Decrypt all blocks directly into the output buffer except for1047* the very last block. Remove the trailing padding bytes from the1048* very last block and copy that into the output buffer.1049*/10501051int blockSize = des.getBlockSize();1052int numBlocks = len / blockSize - 1;10531054// Iterate over all but the last block1055for (int i = 0; i < numBlocks; i++) {1056// debug("dataOffset is " + dataOffset + "\n");1057temp = cis.read(dataOutBuf, dataOffset, blockSize);10581059// temp should be blockSize1060// debug("Got " + temp + " bytes and blockSize is "1061// + blockSize + "\n");1062// debug("Bytes are: "1063// + getHexBytes(dataOutBuf, dataOffset, temp) + "\n");1064dataOffset += blockSize;1065}10661067// Now process the last block1068byte[] finalBlock = new byte[blockSize];1069// debug("Will call read on finalBlock" + "\n");1070temp = cis.read(finalBlock);1071// temp should be blockSize1072/*1073debug("Got " + temp + " bytes and blockSize is "1074+ blockSize + "\n");1075debug("Bytes are: "1076+ getHexBytes(finalBlock, 0, temp) + "\n");1077debug("Will call doFinal" + "\n");1078*/1079try {1080des.doFinal();1081} catch (GeneralSecurityException e) {1082GSSException ge = new GSSException(GSSException.FAILURE, -1,1083"Could not use DES cipher - " + e.getMessage());1084ge.initCause(e);1085throw ge;1086}10871088/*1089* There is always at least one padding byte. The padding bytes1090* are all the value of the number of padding bytes.1091*/10921093int padSize = finalBlock[blockSize - 1];1094if (padSize < 1 || padSize > 8)1095throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1096"Invalid padding on Wrap Token");1097token.padding = WrapToken.pads[padSize];1098blockSize -= padSize;10991100// Copy this last block into the output buffer1101System.arraycopy(finalBlock, 0, dataOutBuf, dataOffset,1102blockSize);1103}11041105private static byte[] getDesEncryptionKey(byte[] key)1106throws GSSException {11071108/*1109* To meet export control requirements, double check that the1110* key being used is no longer than 64 bits.1111*1112* Note that from a protocol point of view, an1113* algorithm that is not DES will be rejected before this1114* point. Also, a DES key that is not 64 bits will be1115* rejected by a good JCE provider.1116*/1117if (key.length > 8)1118throw new GSSException(GSSException.FAILURE, -100,1119"Invalid DES Key!");11201121byte[] retVal = new byte[key.length];1122for (int i = 0; i < key.length; i++)1123retVal[i] = (byte)(key[i] ^ 0xf0); // RFC 1964, Section 1.2.21124return retVal;1125}11261127// ---- DES3-KD methods1128private void des3KdDecrypt(WrapToken token, byte[] ciphertext,1129int cStart, int cLen, byte[] plaintext, int pStart)1130throws GSSException {1131byte[] ptext;1132try {1133ptext = Des3.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,1134ciphertext, cStart, cLen);1135} catch (GeneralSecurityException e) {1136GSSException ge = new GSSException(GSSException.FAILURE, -1,1137"Could not use DES3-KD Cipher - " + e.getMessage());1138ge.initCause(e);1139throw ge;1140}11411142/*1143Krb5Token.debug("\ndes3KdDecrypt in: " +1144Krb5Token.getHexBytes(ciphertext, cStart, cLen));1145Krb5Token.debug("\ndes3KdDecrypt plain: " +1146Krb5Token.getHexBytes(ptext));1147*/11481149// Strip out confounder and padding1150/*1151* There is always at least one padding byte. The padding bytes1152* are all the value of the number of padding bytes.1153*/1154int padSize = ptext[ptext.length - 1];1155if (padSize < 1 || padSize > 8)1156throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1157"Invalid padding on Wrap Token");11581159token.padding = WrapToken.pads[padSize];1160int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;11611162System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,1163plaintext, pStart, len);11641165// Needed to calculate checksum1166System.arraycopy(ptext, 0, token.confounder,11670, WrapToken.CONFOUNDER_SIZE);1168}11691170private byte[] des3KdEncrypt(byte[] confounder, byte[] plaintext,1171int start, int len, byte[] padding) throws GSSException {117211731174// [confounder | plaintext | padding]1175byte[] all = new byte[confounder.length + len + padding.length];1176System.arraycopy(confounder, 0, all, 0, confounder.length);1177System.arraycopy(plaintext, start, all, confounder.length, len);1178System.arraycopy(padding, 0, all, confounder.length + len,1179padding.length);11801181// Krb5Token.debug("\ndes3KdEncrypt:" + Krb5Token.getHexBytes(all));11821183// Encrypt1184try {1185byte[] answer = Des3.encryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,1186all, 0, all.length);1187// Krb5Token.debug("\ndes3KdEncrypt encrypted:" +1188// Krb5Token.getHexBytes(answer));1189return answer;1190} catch (Exception e) {1191// GeneralSecurityException, KrbCryptoException1192GSSException ge = new GSSException(GSSException.FAILURE, -1,1193"Could not use DES3-KD Cipher - " + e.getMessage());1194ge.initCause(e);1195throw ge;1196}1197}11981199// ---- RC4-HMAC methods1200private void arcFourDecrypt(WrapToken token, byte[] ciphertext,1201int cStart, int cLen, byte[] plaintext, int pStart)1202throws GSSException {12031204// obtain Sequence number needed for decryption1205// first decrypt the Sequence Number using checksum1206byte[] seqNum = decryptSeq(token.getChecksum(),1207token.getEncSeqNumber(), 0, 8);12081209byte[] ptext;1210try {1211ptext = ArcFourHmac.decryptRaw(keybytes, KG_USAGE_SEAL, ZERO_IV,1212ciphertext, cStart, cLen, seqNum);1213} catch (GeneralSecurityException e) {1214GSSException ge = new GSSException(GSSException.FAILURE, -1,1215"Could not use ArcFour Cipher - " + e.getMessage());1216ge.initCause(e);1217throw ge;1218}12191220/*1221Krb5Token.debug("\narcFourDecrypt in: " +1222Krb5Token.getHexBytes(ciphertext, cStart, cLen));1223Krb5Token.debug("\narcFourDecrypt plain: " +1224Krb5Token.getHexBytes(ptext));1225*/12261227// Strip out confounder and padding1228/*1229* There is always at least one padding byte. The padding bytes1230* are all the value of the number of padding bytes.1231*/1232int padSize = ptext[ptext.length - 1];1233if (padSize < 1)1234throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,1235"Invalid padding on Wrap Token");12361237token.padding = WrapToken.pads[padSize];1238int len = ptext.length - WrapToken.CONFOUNDER_SIZE - padSize;12391240System.arraycopy(ptext, WrapToken.CONFOUNDER_SIZE,1241plaintext, pStart, len);12421243// Krb5Token.debug("\narcFourDecrypt plaintext: " +1244// Krb5Token.getHexBytes(plaintext));12451246// Needed to calculate checksum1247System.arraycopy(ptext, 0, token.confounder,12480, WrapToken.CONFOUNDER_SIZE);1249}12501251private byte[] arcFourEncrypt(WrapToken token, byte[] confounder,1252byte[] plaintext, int start, int len, byte[] padding)1253throws GSSException {12541255// [confounder | plaintext | padding]1256byte[] all = new byte[confounder.length + len + padding.length];1257System.arraycopy(confounder, 0, all, 0, confounder.length);1258System.arraycopy(plaintext, start, all, confounder.length, len);1259System.arraycopy(padding, 0, all, confounder.length + len,1260padding.length);12611262// get the token Sequence Number required for encryption1263// Note: When using this RC4 based encryption type, the sequence number1264// is always sent in big-endian rather than little-endian order.1265byte[] seqNum = new byte[4];1266WrapToken.writeBigEndian(token.getSequenceNumber(), seqNum);12671268// Krb5Token.debug("\narcFourEncrypt:" + Krb5Token.getHexBytes(all));12691270// Encrypt1271try {1272byte[] answer = ArcFourHmac.encryptRaw(keybytes, KG_USAGE_SEAL,1273seqNum, all, 0, all.length);1274// Krb5Token.debug("\narcFourEncrypt encrypted:" +1275// Krb5Token.getHexBytes(answer));1276return answer;1277} catch (Exception e) {1278// GeneralSecurityException, KrbCryptoException1279GSSException ge = new GSSException(GSSException.FAILURE, -1,1280"Could not use ArcFour Cipher - " + e.getMessage());1281ge.initCause(e);1282throw ge;1283}1284}12851286// ---- AES methods1287private byte[] aes128Encrypt(byte[] confounder, byte[] tokenHeader,1288byte[] plaintext, int start, int len, int key_usage)1289throws GSSException {12901291// encrypt { AES-plaintext-data | filler | header }1292// AES-plaintext-data { confounder | plaintext }1293// WrapToken = { tokenHeader |1294// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }12951296byte[] all = new byte[confounder.length + len + tokenHeader.length];1297System.arraycopy(confounder, 0, all, 0, confounder.length);1298System.arraycopy(plaintext, start, all, confounder.length, len);1299System.arraycopy(tokenHeader, 0, all, confounder.length+len,1300tokenHeader.length);13011302// Krb5Token.debug("\naes128Encrypt:" + Krb5Token.getHexBytes(all));1303try {1304byte[] answer = Aes128.encryptRaw(keybytes, key_usage,1305ZERO_IV_AES,1306all, 0, all.length);1307// Krb5Token.debug("\naes128Encrypt encrypted:" +1308// Krb5Token.getHexBytes(answer));1309return answer;1310} catch (Exception e) {1311// GeneralSecurityException, KrbCryptoException1312GSSException ge = new GSSException(GSSException.FAILURE, -1,1313"Could not use AES128 Cipher - " + e.getMessage());1314ge.initCause(e);1315throw ge;1316}1317}13181319private void aes128Decrypt(WrapToken_v2 token, byte[] ciphertext,1320int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)1321throws GSSException {13221323byte[] ptext = null;13241325try {1326ptext = Aes128.decryptRaw(keybytes, key_usage,1327ZERO_IV_AES, ciphertext, cStart, cLen);1328} catch (GeneralSecurityException e) {1329GSSException ge = new GSSException(GSSException.FAILURE, -1,1330"Could not use AES128 Cipher - " + e.getMessage());1331ge.initCause(e);1332throw ge;1333}13341335/*1336Krb5Token.debug("\naes128Decrypt in: " +1337Krb5Token.getHexBytes(ciphertext, cStart, cLen));1338Krb5Token.debug("\naes128Decrypt plain: " +1339Krb5Token.getHexBytes(ptext));1340Krb5Token.debug("\naes128Decrypt ptext: " +1341Krb5Token.getHexBytes(ptext));1342*/13431344// Strip out confounder and token header1345int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -1346WrapToken_v2.TOKEN_HEADER_SIZE;1347System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,1348plaintext, pStart, len);13491350/*1351Krb5Token.debug("\naes128Decrypt plaintext: " +1352Krb5Token.getHexBytes(plaintext, pStart, len));1353*/1354}13551356private byte[] aes256Encrypt(byte[] confounder, byte[] tokenHeader,1357byte[] plaintext, int start, int len, int key_usage)1358throws GSSException {13591360// encrypt { AES-plaintext-data | filler | header }1361// AES-plaintext-data { confounder | plaintext }1362// WrapToken = { tokenHeader |1363// Encrypt (confounder | plaintext | tokenHeader ) | HMAC }13641365byte[] all = new byte[confounder.length + len + tokenHeader.length];1366System.arraycopy(confounder, 0, all, 0, confounder.length);1367System.arraycopy(plaintext, start, all, confounder.length, len);1368System.arraycopy(tokenHeader, 0, all, confounder.length+len,1369tokenHeader.length);13701371// Krb5Token.debug("\naes256Encrypt:" + Krb5Token.getHexBytes(all));13721373try {1374byte[] answer = Aes256.encryptRaw(keybytes, key_usage,1375ZERO_IV_AES, all, 0, all.length);1376// Krb5Token.debug("\naes256Encrypt encrypted:" +1377// Krb5Token.getHexBytes(answer));1378return answer;1379} catch (Exception e) {1380// GeneralSecurityException, KrbCryptoException1381GSSException ge = new GSSException(GSSException.FAILURE, -1,1382"Could not use AES256 Cipher - " + e.getMessage());1383ge.initCause(e);1384throw ge;1385}1386}13871388private void aes256Decrypt(WrapToken_v2 token, byte[] ciphertext,1389int cStart, int cLen, byte[] plaintext, int pStart, int key_usage)1390throws GSSException {13911392byte[] ptext;1393try {1394ptext = Aes256.decryptRaw(keybytes, key_usage,1395ZERO_IV_AES, ciphertext, cStart, cLen);1396} catch (GeneralSecurityException e) {1397GSSException ge = new GSSException(GSSException.FAILURE, -1,1398"Could not use AES128 Cipher - " + e.getMessage());1399ge.initCause(e);1400throw ge;1401}14021403/*1404Krb5Token.debug("\naes256Decrypt in: " +1405Krb5Token.getHexBytes(ciphertext, cStart, cLen));1406Krb5Token.debug("\naes256Decrypt plain: " +1407Krb5Token.getHexBytes(ptext));1408Krb5Token.debug("\naes256Decrypt ptext: " +1409Krb5Token.getHexBytes(ptext));1410*/14111412// Strip out confounder and token header1413int len = ptext.length - WrapToken_v2.CONFOUNDER_SIZE -1414WrapToken_v2.TOKEN_HEADER_SIZE;1415System.arraycopy(ptext, WrapToken_v2.CONFOUNDER_SIZE,1416plaintext, pStart, len);14171418/*1419Krb5Token.debug("\naes128Decrypt plaintext: " +1420Krb5Token.getHexBytes(plaintext, pStart, len));1421*/14221423}14241425/**1426* This class provides a truncated inputstream needed by WrapToken. The1427* truncated inputstream is passed to CipherInputStream. It prevents1428* the CipherInputStream from treating the bytes of the following token1429* as part fo the ciphertext for this token.1430*/1431class WrapTokenInputStream extends InputStream {14321433private InputStream is;1434private int length;1435private int remaining;14361437private int temp;14381439public WrapTokenInputStream(InputStream is, int length) {1440this.is = is;1441this.length = length;1442remaining = length;1443}14441445public final int read() throws IOException {1446if (remaining == 0)1447return -1;1448else {1449temp = is.read();1450if (temp != -1)1451remaining -= temp;1452return temp;1453}1454}14551456public final int read(byte[] b) throws IOException {1457if (remaining == 0)1458return -1;1459else {1460temp = Math.min(remaining, b.length);1461temp = is.read(b, 0, temp);1462if (temp != -1)1463remaining -= temp;1464return temp;1465}1466}14671468public final int read(byte[] b,1469int off,1470int len) throws IOException {1471if (remaining == 0)1472return -1;1473else {1474temp = Math.min(remaining, len);1475temp = is.read(b, off, temp);1476if (temp != -1)1477remaining -= temp;1478return temp;1479}1480}14811482public final long skip(long n) throws IOException {1483if (remaining == 0)1484return 0;1485else {1486temp = (int) Math.min(remaining, n);1487temp = (int) is.skip(temp);1488remaining -= temp;1489return temp;1490}1491}14921493public final int available() throws IOException {1494return Math.min(remaining, is.available());1495}14961497public final void close() throws IOException {1498remaining = 0;1499}1500}1501}150215031504