src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java
changeset 47216 71c04702a3d5
parent 32003 acb12269398a
child 48651 67abfee27e69
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 /*
       
    27  *
       
    28  *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
       
    29  *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
       
    30  */
       
    31 
       
    32 package sun.security.krb5;
       
    33 
       
    34 import sun.security.util.*;
       
    35 import sun.security.krb5.internal.crypto.*;
       
    36 import sun.security.krb5.internal.*;
       
    37 import java.io.IOException;
       
    38 import java.math.BigInteger;
       
    39 
       
    40 /**
       
    41  * This class encapsulates Kerberos encrypted data. It allows
       
    42  * callers access to both the ASN.1 encoded form of the EncryptedData
       
    43  * type as well as the raw cipher text.
       
    44  */
       
    45 
       
    46 public class EncryptedData implements Cloneable {
       
    47     int eType;
       
    48     Integer kvno; // optional
       
    49     byte[] cipher;
       
    50     byte[] plain; // not part of ASN.1 encoding
       
    51 
       
    52     // ----------------+-----------+----------+----------------+---------------
       
    53     // Encryption type |etype value|block size|minimum pad size|confounder size
       
    54     // ----------------+-----------+----------+----------------+---------------
       
    55     public static final int
       
    56         ETYPE_NULL        = 0;       // 1          0                0
       
    57     public static final int
       
    58         ETYPE_DES_CBC_CRC = 1;       // 8          4                8
       
    59     public static final int
       
    60         ETYPE_DES_CBC_MD4 = 2;       // 8          0                8
       
    61     public static final int
       
    62         ETYPE_DES_CBC_MD5 = 3;       // 8          0                8
       
    63 
       
    64     // draft-brezak-win2k-krb-rc4-hmac-04.txt
       
    65     public static final int
       
    66         ETYPE_ARCFOUR_HMAC = 23;     // 1
       
    67     // NOTE: the exportable RC4-HMAC is not supported;
       
    68     // it is no longer a usable encryption type
       
    69     public static final int
       
    70         ETYPE_ARCFOUR_HMAC_EXP = 24; // 1
       
    71 
       
    72      // draft-ietf-krb-wg-crypto-07.txt
       
    73     public static final int
       
    74         ETYPE_DES3_CBC_HMAC_SHA1_KD = 16; // 8     0                8
       
    75 
       
    76     // draft-raeburn-krb-rijndael-krb-07.txt
       
    77     public static final int
       
    78          ETYPE_AES128_CTS_HMAC_SHA1_96 = 17; // 16      0           16
       
    79     public static final int
       
    80          ETYPE_AES256_CTS_HMAC_SHA1_96 = 18; // 16      0           16
       
    81 
       
    82     /* used by self */
       
    83     private EncryptedData() {
       
    84     }
       
    85 
       
    86     public Object clone() {
       
    87         EncryptedData new_encryptedData = new EncryptedData();
       
    88         new_encryptedData.eType = eType;
       
    89         if (kvno != null) {
       
    90             new_encryptedData.kvno = kvno.intValue();
       
    91         }
       
    92         if (cipher != null) {
       
    93             new_encryptedData.cipher = new byte[cipher.length];
       
    94             System.arraycopy(cipher, 0, new_encryptedData.cipher,
       
    95                              0, cipher.length);
       
    96         }
       
    97         return new_encryptedData;
       
    98     }
       
    99 
       
   100      // Used in JSSE (com.sun.net.ssl.internal.KerberosPreMasterSecret)
       
   101     public EncryptedData(
       
   102                          int new_eType,
       
   103                          Integer new_kvno,
       
   104                          byte[] new_cipher) {
       
   105         eType = new_eType;
       
   106         kvno = new_kvno;
       
   107         cipher = new_cipher;
       
   108     }
       
   109 
       
   110     /*
       
   111     // Not used.
       
   112     public EncryptedData(
       
   113                          EncryptionKey key,
       
   114                          byte[] plaintext)
       
   115         throws KdcErrException, KrbCryptoException {
       
   116         EType etypeEngine = EType.getInstance(key.getEType());
       
   117         cipher = etypeEngine.encrypt(plaintext, key.getBytes());
       
   118         eType = key.getEType();
       
   119         kvno = key.getKeyVersionNumber();
       
   120     }
       
   121     */
       
   122 
       
   123      // used in KrbApRep, KrbApReq, KrbAsReq, KrbCred, KrbPriv
       
   124      // Used in JSSE (com.sun.net.ssl.internal.KerberosPreMasterSecret)
       
   125     public EncryptedData(
       
   126                          EncryptionKey key,
       
   127                          byte[] plaintext,
       
   128                          int usage)
       
   129         throws KdcErrException, KrbCryptoException {
       
   130         EType etypeEngine = EType.getInstance(key.getEType());
       
   131         cipher = etypeEngine.encrypt(plaintext, key.getBytes(), usage);
       
   132         eType = key.getEType();
       
   133         kvno = key.getKeyVersionNumber();
       
   134     }
       
   135 
       
   136     /*
       
   137     // Not used.
       
   138     public EncryptedData(
       
   139                          EncryptionKey key,
       
   140                          byte[] ivec,
       
   141                          byte[] plaintext)
       
   142         throws KdcErrException, KrbCryptoException {
       
   143         EType etypeEngine = EType.getInstance(key.getEType());
       
   144         cipher = etypeEngine.encrypt(plaintext, key.getBytes(), ivec);
       
   145         eType = key.getEType();
       
   146         kvno = key.getKeyVersionNumber();
       
   147     }
       
   148     */
       
   149 
       
   150     /*
       
   151     // Not used.
       
   152     EncryptedData(
       
   153                   StringBuffer password,
       
   154                   byte[] plaintext)
       
   155         throws KdcErrException, KrbCryptoException {
       
   156         EncryptionKey key = new EncryptionKey(password);
       
   157         EType etypeEngine = EType.getInstance(key.getEType());
       
   158         cipher = etypeEngine.encrypt(plaintext, key.getBytes());
       
   159         eType = key.getEType();
       
   160         kvno = key.getKeyVersionNumber();
       
   161     }
       
   162     */
       
   163     public byte[] decrypt(
       
   164                           EncryptionKey key, int usage)
       
   165         throws KdcErrException, KrbApErrException, KrbCryptoException {
       
   166             if (eType != key.getEType()) {
       
   167                 throw new KrbCryptoException(
       
   168                     "EncryptedData is encrypted using keytype " +
       
   169                     EType.toString(eType) +
       
   170                     " but decryption key is of type " +
       
   171                     EType.toString(key.getEType()));
       
   172             }
       
   173 
       
   174             EType etypeEngine = EType.getInstance(eType);
       
   175             plain = etypeEngine.decrypt(cipher, key.getBytes(), usage);
       
   176             // The service ticket will be used in S4U2proxy request. Therefore
       
   177             // the raw ticket is still needed.
       
   178             //cipher = null;
       
   179             return etypeEngine.decryptedData(plain);
       
   180         }
       
   181 
       
   182     /*
       
   183     // currently destructive on cipher
       
   184     // Not used.
       
   185     public byte[] decrypt(
       
   186                           EncryptionKey key,
       
   187                           byte[] ivec, int usage)
       
   188         throws KdcErrException, KrbApErrException, KrbCryptoException {
       
   189             // XXX check for matching eType and kvno here
       
   190             EType etypeEngine = EType.getInstance(eType);
       
   191             plain = etypeEngine.decrypt(cipher, key.getBytes(), ivec, usage);
       
   192             cipher = null;
       
   193             return etypeEngine.decryptedData(plain);
       
   194         }
       
   195 
       
   196     // currently destructive on cipher
       
   197     // Not used.
       
   198     byte[] decrypt(StringBuffer password)
       
   199         throws KdcErrException, KrbApErrException, KrbCryptoException {
       
   200             EncryptionKey key = new EncryptionKey(password);
       
   201             // XXX check for matching eType here
       
   202             EType etypeEngine = EType.getInstance(eType);
       
   203             plain = etypeEngine.decrypt(cipher, key.getBytes());
       
   204             cipher = null;
       
   205             return etypeEngine.decryptedData(plain);
       
   206         }
       
   207     */
       
   208 
       
   209     private byte[] decryptedData() throws KdcErrException {
       
   210         if (plain != null) {
       
   211             EType etypeEngine = EType.getInstance(eType);
       
   212             return etypeEngine.decryptedData(plain);
       
   213         }
       
   214         return null;
       
   215     }
       
   216 
       
   217     /**
       
   218      * Constructs an instance of EncryptedData type.
       
   219      * @param encoding a single DER-encoded value.
       
   220      * @exception Asn1Exception if an error occurs while decoding an
       
   221      * ASN1 encoded data.
       
   222      * @exception IOException if an I/O error occurs while reading encoded
       
   223      * data.
       
   224      *
       
   225      */
       
   226     /* Used by self */
       
   227     private EncryptedData(DerValue encoding)
       
   228         throws Asn1Exception, IOException {
       
   229 
       
   230         DerValue der = null;
       
   231         if (encoding.getTag() != DerValue.tag_Sequence) {
       
   232             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
       
   233         }
       
   234         der = encoding.getData().getDerValue();
       
   235         if ((der.getTag() & (byte)0x1F) == (byte)0x00) {
       
   236             eType = (der.getData().getBigInteger()).intValue();
       
   237         } else {
       
   238             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
       
   239         }
       
   240 
       
   241         if ((encoding.getData().peekByte() & 0x1F) == 1) {
       
   242             der = encoding.getData().getDerValue();
       
   243             int i = (der.getData().getBigInteger()).intValue();
       
   244             kvno = i;
       
   245         } else {
       
   246             kvno = null;
       
   247         }
       
   248         der = encoding.getData().getDerValue();
       
   249         if ((der.getTag() & (byte)0x1F) == (byte)0x02) {
       
   250             cipher = der.getData().getOctetString();
       
   251         } else {
       
   252             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
       
   253         }
       
   254         if (encoding.getData().available() > 0) {
       
   255             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
       
   256         }
       
   257     }
       
   258 
       
   259     /**
       
   260      * Returns an ASN.1 encoded EncryptedData type.
       
   261      *
       
   262      * <pre>{@code
       
   263      * EncryptedData   ::= SEQUENCE {
       
   264      *     etype   [0] Int32 -- EncryptionType --,
       
   265      *     kvno    [1] UInt32 OPTIONAL,
       
   266      *     cipher  [2] OCTET STRING -- ciphertext
       
   267      * }
       
   268      * }</pre>
       
   269      *
       
   270      * <p>
       
   271      * This definition reflects the Network Working Group RFC 4120
       
   272      * specification available at
       
   273      * <a href="http://www.ietf.org/rfc/rfc4120.txt">
       
   274      * http://www.ietf.org/rfc/rfc4120.txt</a>.
       
   275      *
       
   276      * @return byte array of encoded EncryptedData object.
       
   277      * @exception Asn1Exception if an error occurs while decoding an
       
   278      * ASN1 encoded data.
       
   279      * @exception IOException if an I/O error occurs while reading
       
   280      * encoded data.
       
   281      *
       
   282      */
       
   283     public byte[] asn1Encode() throws Asn1Exception, IOException {
       
   284         DerOutputStream bytes = new DerOutputStream();
       
   285         DerOutputStream temp = new DerOutputStream();
       
   286         temp.putInteger(BigInteger.valueOf(this.eType));
       
   287         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
       
   288                                        true, (byte)0x00), temp);
       
   289         temp = new DerOutputStream();
       
   290         if (kvno != null) {
       
   291             // encode as an unsigned integer (UInt32)
       
   292             temp.putInteger(BigInteger.valueOf(this.kvno.longValue()));
       
   293             bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
       
   294                                            true, (byte)0x01), temp);
       
   295             temp = new DerOutputStream();
       
   296         }
       
   297         temp.putOctetString(this.cipher);
       
   298         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
       
   299                         (byte)0x02), temp);
       
   300         temp = new DerOutputStream();
       
   301         temp.write(DerValue.tag_Sequence, bytes);
       
   302         return temp.toByteArray();
       
   303     }
       
   304 
       
   305 
       
   306     /**
       
   307      * Parse (unmarshal) an EncryptedData from a DER input stream.  This form
       
   308      * parsing might be used when expanding a value which is part of
       
   309      * a constructed sequence and uses explicitly tagged type.
       
   310      *
       
   311      * @param data the Der input stream value, which contains one or more
       
   312      *        marshaled value.
       
   313      * @param explicitTag tag number.
       
   314      * @param optional indicate if this data field is optional
       
   315      * @exception Asn1Exception if an error occurs while decoding an
       
   316      * ASN1 encoded data.
       
   317      * @exception IOException if an I/O error occurs while reading
       
   318      * encoded data.
       
   319      * @return an instance of EncryptedData.
       
   320      *
       
   321      */
       
   322     public static EncryptedData parse(DerInputStream data,
       
   323                                       byte explicitTag,
       
   324                                       boolean optional)
       
   325         throws Asn1Exception, IOException {
       
   326         if ((optional) &&
       
   327             (((byte)data.peekByte() & (byte)0x1F) != explicitTag))
       
   328             return null;
       
   329         DerValue der = data.getDerValue();
       
   330         if (explicitTag != (der.getTag() & (byte)0x1F))  {
       
   331             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
       
   332         } else {
       
   333             DerValue subDer = der.getData().getDerValue();
       
   334             return new EncryptedData(subDer);
       
   335         }
       
   336     }
       
   337 
       
   338     /**
       
   339      * Reset asn.1 data stream after decryption, remove redundant bytes.
       
   340      * @param data the decrypted data from decrypt().
       
   341      * @return the reset byte array which holds exactly one asn1 datum
       
   342      * including its tag and length.
       
   343      *
       
   344      */
       
   345     public byte[] reset(byte[] data) {
       
   346         byte[]  bytes = null;
       
   347         // for asn.1 encoded data, we use length field to
       
   348         // determine the data length and remove redundant paddings.
       
   349         if ((data[1] & 0xFF) < 128) {
       
   350             bytes = new byte[data[1] + 2];
       
   351             System.arraycopy(data, 0, bytes, 0, data[1] + 2);
       
   352         } else {
       
   353             if ((data[1] & 0xFF) > 128) {
       
   354                 int len = data[1] & (byte)0x7F;
       
   355                 int result = 0;
       
   356                 for (int i = 0; i < len; i++) {
       
   357                     result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1));
       
   358                 }
       
   359                 bytes = new byte[result + len + 2];
       
   360                 System.arraycopy(data, 0, bytes, 0, result + len + 2);
       
   361             }
       
   362         }
       
   363         return bytes;
       
   364     }
       
   365 
       
   366     public int getEType() {
       
   367         return eType;
       
   368     }
       
   369 
       
   370     public Integer getKeyVersionNumber() {
       
   371         return kvno;
       
   372     }
       
   373 
       
   374     /**
       
   375      * Returns the raw cipher text bytes, not in ASN.1 encoding.
       
   376      */
       
   377     public byte[] getBytes() {
       
   378         return cipher;
       
   379     }
       
   380 }