1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
/* * @(#)KerberosKey.java 1.20 06/04/21 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.security.auth.kerberos; import java.util.Arrays; import javax.crypto.SecretKey; import javax.security.auth.Destroyable; import javax.security.auth.DestroyFailedException; /** * This class encapsulates a long term secret key for a Kerberos * principal.<p> * * All Kerberos JAAS login modules that obtain a principal's password and * generate the secret key from it should use this class. Where available, * the login module might even read this secret key directly from a * Kerberos "keytab". Sometimes, such as when authenticating a server in * the absence of user-to-user authentication, the login module will store * an instance of this class in the private credential set of a * {@link javax.security.auth.Subject Subject} during the commit phase of the * authentication process.<p> * * It might be necessary for the application to be granted a * {@link javax.security.auth.PrivateCredentialPermission * PrivateCredentialPermission} if it needs to access the KerberosKey * instance from a Subject. This permission is not needed when the * application depends on the default JGSS Kerberos mechanism to access the * KerberosKey. In that case, however, the application will need an * appropriate * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}. * * @author Mayank Upadhyay * @version 1.20, 04/21/06 * @since 1.4 */ public class KerberosKey implements SecretKey, Destroyable { private static final long serialVersionUID = -4625402278148246993L; /** * The principal that this secret key belongs to. * * @serial */ private KerberosPrincipal principal; /** * the version number of this secret key * * @serial */ private int versionNum; /** * <code>KeyImpl</code> is serialized by writing out the ASN1 Encoded bytes * of the encryption key. The ASN1 encoding is defined in * RFC1510 and as follows: * <pre> * EncryptionKey ::= SEQUENCE { * keytype[0] INTEGER, * keyvalue[1] OCTET STRING * } * </pre> * * @serial */ private KeyImpl key; private transient boolean destroyed = false; /** * Constructs a KerberosKey from the given bytes when the key type and * key version number are known. This can be used when reading the secret * key information from a Kerberos "keytab". * * @param principal the principal that this secret key belongs to * @param keyBytes the raw bytes for the secret key * @param keyType the key type for the secret key as defined by the * Kerberos protocol specification. * @param versionNum the version number of this secret key */ public KerberosKey(KerberosPrincipal principal, byte[] keyBytes, int keyType, int versionNum) { this.principal = principal; this.versionNum = versionNum; key = new KeyImpl(keyBytes, keyType); } /** * Constructs a KerberosKey from a principal's password. * * @param principal the principal that this password belongs to * @param password the password that should be used to compute the key * @param algorithm the name for the algorithm that this key will be * used for. This parameter may be null in which case the default * algorithm "DES" will be assumed. * @throws IllegalArgumentException if the name of the * algorithm passed is unsupported. */ public KerberosKey(KerberosPrincipal principal, char[] password, String algorithm) { this.principal = principal; // Pass principal in for salt key = new KeyImpl(principal, password, algorithm); } /** * Returns the principal that this key belongs to. * * @return the principal this key belongs to. */ public final KerberosPrincipal getPrincipal() { if (destroyed) throw new IllegalStateException("This key is no longer valid"); return principal; } /** * Returns the key version number. * * @return the key version number. */ public final int getVersionNumber() { if (destroyed) throw new IllegalStateException("This key is no longer valid"); return versionNum; } /** * Returns the key type for this long-term key. * * @return the key type. */ public final int getKeyType() { if (destroyed) throw new IllegalStateException("This key is no longer valid"); return key.getKeyType(); } /* * Methods from java.security.Key */ /** * Returns the standard algorithm name for this key. For * example, "DES" would indicate that this key is a DES key. * See Appendix A in the <a href= * "../../../../../technotes/guides/security/crypto/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference * </a> * for information about standard algorithm names. * * @return the name of the algorithm associated with this key. */ public final String getAlgorithm() { if (destroyed) throw new IllegalStateException("This key is no longer valid"); return key.getAlgorithm(); } /** * Returns the name of the encoding format for this secret key. * * @return the String "RAW" */ public final String getFormat() { if (destroyed) throw new IllegalStateException("This key is no longer valid"); return key.getFormat(); } /** * Returns the key material of this secret key. * * @return the key material */ public final byte[] getEncoded() { if (destroyed) throw new IllegalStateException("This key is no longer valid"); return key.getEncoded(); } /** * Destroys this key. A call to any of its other methods after this * will cause an IllegalStateException to be thrown. * * @throws DestroyFailedException if some error occurs while destorying * this key. */ public void destroy() throws DestroyFailedException { if (!destroyed) { key.destroy(); principal = null; destroyed = true; } } /** Determines if this key has been destroyed.*/ public boolean isDestroyed() { return destroyed; } public String toString() { if (destroyed) { return "Destroyed Principal"; } return "Kerberos Principal " + principal.toString() + "Key Version " + versionNum + "key " + key.toString(); } /** * Returns a hashcode for this KerberosKey. * * @return a hashCode() for the <code>KerberosKey</code> * @since 1.6 */ public int hashCode() { int result = 17; if (isDestroyed()) { return result; } result = 37 * result + Arrays.hashCode(getEncoded()); result = 37 * result + getKeyType(); if (principal != null) { result = 37 * result + principal.hashCode(); } return result * 37 + versionNum; } /** * Compares the specified Object with this KerberosKey for equality. * Returns true if the given object is also a * <code>KerberosKey</code> and the two * <code>KerberosKey</code> instances are equivalent. * * @param other the Object to compare to * @return true if the specified object is equal to this KerberosKey, * false otherwise. NOTE: Returns false if either of the KerberosKey * objects has been destroyed. * @since 1.6 */ public boolean equals(Object other) { if (other == this) return true; if (! (other instanceof KerberosKey)) { return false; } KerberosKey otherKey = ((KerberosKey) other); if (isDestroyed() || otherKey.isDestroyed()) { return false; } if (versionNum != otherKey.getVersionNumber() || getKeyType() != otherKey.getKeyType() || !Arrays.equals(getEncoded(), otherKey.getEncoded())) { return false; } if (principal == null) { if (otherKey.getPrincipal() != null) { return false; } } else { if (!principal.equals(otherKey.getPrincipal())) { return false; } } return true; } }