1 /*
   2  * Copyright (c) 2014, 2015, 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 package javax.security.auth.kerberos;
  27 
  28 import java.util.Arrays;
  29 import java.util.Objects;
  30 import javax.crypto.SecretKey;
  31 import javax.security.auth.DestroyFailedException;
  32 
  33 /**
  34  * This class encapsulates an EncryptionKey used in Kerberos.<p>
  35  *
  36  * An EncryptionKey is defined in Section 4.2.9 of the Kerberos Protocol
  37  * Specification (<a href=http://www.ietf.org/rfc/rfc4120.txt>RFC 4120</a>) as:
  38  * <pre>
  39  *     EncryptionKey   ::= SEQUENCE {
  40  *             keytype         [0] Int32 -- actually encryption type --,
  41  *             keyvalue        [1] OCTET STRING
  42  *     }
  43  * </pre>
  44  * The key material of an {@code EncryptionKey} is defined as the value
  45  * of the {@code keyValue} above.
  46  *
  47  * @since 9
  48  */
  49 public final class EncryptionKey implements SecretKey {
  50 
  51     private static final long serialVersionUID = 9L;
  52 
  53    /**
  54     * {@code KeyImpl} is serialized by writing out the ASN.1 encoded bytes
  55     * of the encryption key.
  56     *
  57     * @serial
  58     */
  59     final private KeyImpl key;
  60 
  61     private transient boolean destroyed = false;
  62 
  63     /**
  64      * Constructs a {@code EncryptionKey} from the given bytes and
  65      * the key type.
  66      * <p>
  67      * The contents of the byte array are copied; subsequent modification of
  68      * the byte array does not affect the newly created key.
  69      *
  70      * @param keyBytes the key material for the key
  71      * @param keyType the key type for the key as defined by the
  72      *                Kerberos protocol specification.
  73      * @throws NullPointerException if keyBytes is null
  74      */
  75     public EncryptionKey(byte[] keyBytes, int keyType) {
  76         key = new KeyImpl(Objects.requireNonNull(keyBytes), keyType);
  77     }
  78 
  79     /**
  80      * Returns the key type for this key.
  81      *
  82      * @return the key type.
  83      * @throws IllegalStateException if the key is destroyed
  84      */
  85     public int getKeyType() {
  86         // KeyImpl already checked if destroyed
  87         return key.getKeyType();
  88     }
  89 
  90     /*
  91      * Methods from java.security.Key
  92      */
  93 
  94     /**
  95      * Returns the standard algorithm name for this key. The algorithm names
  96      * are the encryption type string defined on the IANA
  97      * <a href="https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1">Kerberos Encryption Type Numbers</a>
  98      * page.
  99      * <p>
 100      * This method can return the following value not defined on the IANA page:
 101      * <ol>
 102      *     <li>none: for etype equal to 0</li>
 103      *     <li>unknown: for etype greater than 0 but unsupported by
 104      *         the implementation</li>
 105      *     <li>private: for etype smaller than 0</li>
 106      * </ol>
 107      *
 108      * @return the name of the algorithm associated with this key.
 109      * @throws IllegalStateException if the key is destroyed
 110      */
 111     @Override
 112     public String getAlgorithm() {
 113         // KeyImpl already checked if destroyed
 114         return key.getAlgorithm();
 115     }
 116 
 117     /**
 118      * Returns the name of the encoding format for this key.
 119      *
 120      * @return the String "RAW"
 121      * @throws IllegalStateException if the key is destroyed
 122      */
 123     @Override
 124     public String getFormat() {
 125         // KeyImpl already checked if destroyed
 126         return key.getFormat();
 127     }
 128 
 129     /**
 130      * Returns the key material of this key.
 131      *
 132      * @return a newly allocated byte array that contains the key material
 133      * @throws IllegalStateException if the key is destroyed
 134      */
 135     @Override
 136     public byte[] getEncoded() {
 137         // KeyImpl already checked if destroyed
 138         return key.getEncoded();
 139     }
 140 
 141     /**
 142      * Destroys this key by clearing out the key material of this key.
 143      *
 144      * @throws DestroyFailedException if some error occurs while destorying
 145      * this key.
 146      */
 147     @Override
 148     public void destroy() throws DestroyFailedException {
 149         if (!destroyed) {
 150             key.destroy();
 151             destroyed = true;
 152         }
 153     }
 154 
 155 
 156     @Override
 157     public boolean isDestroyed() {
 158         return destroyed;
 159     }
 160 
 161     /**
 162      * Returns an informative textual representation of this {@code EncryptionKey}.
 163      *
 164      * @return an informative textual representation of this {@code EncryptionKey}.
 165      */
 166     @Override
 167     public String toString() {
 168         if (destroyed) {
 169             return "Destroyed EncryptionKey";
 170         }
 171         return "key "  + key.toString();
 172     }
 173 
 174     /**
 175      * Returns a hash code for this {@code EncryptionKey}.
 176      *
 177      * @return a hash code for this {@code EncryptionKey}.
 178      */
 179     @Override
 180     public int hashCode() {
 181         int result = 17;
 182         if (isDestroyed()) {
 183             return result;
 184         }
 185         result = 37 * result + Arrays.hashCode(getEncoded());
 186         return 37 * result + getKeyType();
 187     }
 188 
 189     /**
 190      * Compares the specified object with this key for equality.
 191      * Returns true if the given object is also an
 192      * {@code EncryptionKey} and the two
 193      * {@code EncryptionKey} instances are equivalent. More formally two
 194      * {@code EncryptionKey} instances are equal if they have equal key types
 195      * and key material.
 196      * A destroyed {@code EncryptionKey} object is only equal to itself.
 197      *
 198      * @param other the object to compare to
 199      * @return true if the specified object is equal to this
 200      * {@code EncryptionKey}, false otherwise.
 201      */
 202     @Override
 203     public boolean equals(Object other) {
 204 
 205         if (other == this)
 206             return true;
 207 
 208         if (! (other instanceof EncryptionKey)) {
 209             return false;
 210         }
 211 
 212         EncryptionKey otherKey = ((EncryptionKey) other);
 213         if (isDestroyed() || otherKey.isDestroyed()) {
 214             return false;
 215         }
 216 
 217         return getKeyType() == otherKey.getKeyType()
 218                 && Arrays.equals(getEncoded(), otherKey.getEncoded());
 219     }
 220 }