You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
6.5 KiB
245 lines
6.5 KiB
/*
|
|
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.security.auth.kerberos;
|
|
|
|
import java.io.*;
|
|
import java.util.Arrays;
|
|
import javax.crypto.SecretKey;
|
|
import javax.security.auth.Destroyable;
|
|
import javax.security.auth.DestroyFailedException;
|
|
import sun.misc.HexDumpEncoder;
|
|
import sun.security.krb5.Asn1Exception;
|
|
import sun.security.krb5.PrincipalName;
|
|
import sun.security.krb5.EncryptionKey;
|
|
import sun.security.krb5.EncryptedData;
|
|
import sun.security.krb5.KrbException;
|
|
import sun.security.krb5.KrbCryptoException;
|
|
import sun.security.util.DerValue;
|
|
|
|
/**
|
|
* This class encapsulates a Kerberos encryption key. It is not associated
|
|
* with a principal and may represent an ephemeral session key.
|
|
*
|
|
* @author Mayank Upadhyay
|
|
* @since 1.4
|
|
*
|
|
* @serial include
|
|
*/
|
|
class KeyImpl implements SecretKey, Destroyable, Serializable {
|
|
|
|
private static final long serialVersionUID = -7889313790214321193L;
|
|
|
|
private transient byte[] keyBytes;
|
|
private transient int keyType;
|
|
private transient volatile boolean destroyed = false;
|
|
|
|
|
|
/**
|
|
* Constructs a KeyImpl from the given bytes.
|
|
*
|
|
* @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.
|
|
*/
|
|
public KeyImpl(byte[] keyBytes,
|
|
int keyType) {
|
|
this.keyBytes = keyBytes.clone();
|
|
this.keyType = keyType;
|
|
}
|
|
|
|
/**
|
|
* Constructs a KeyImpl from a password.
|
|
*
|
|
* @param principal the principal from which to derive the salt
|
|
* @param password the password that should be used to compute the
|
|
* key.
|
|
* @param algorithm the name for the algorithm that this key wil be
|
|
* used for. This parameter may be null in which case "DES" will be
|
|
* assumed.
|
|
*/
|
|
public KeyImpl(KerberosPrincipal principal,
|
|
char[] password,
|
|
String algorithm) {
|
|
|
|
try {
|
|
PrincipalName princ = new PrincipalName(principal.getName());
|
|
EncryptionKey key =
|
|
new EncryptionKey(password, princ.getSalt(), algorithm);
|
|
this.keyBytes = key.getBytes();
|
|
this.keyType = key.getEType();
|
|
} catch (KrbException e) {
|
|
throw new IllegalArgumentException(e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the keyType for this key as defined in the Kerberos Spec.
|
|
*/
|
|
public final int getKeyType() {
|
|
if (destroyed)
|
|
throw new IllegalStateException("This key is no longer valid");
|
|
return keyType;
|
|
}
|
|
|
|
/*
|
|
* Methods from java.security.Key
|
|
*/
|
|
|
|
public final String getAlgorithm() {
|
|
return getAlgorithmName(keyType);
|
|
}
|
|
|
|
private String getAlgorithmName(int eType) {
|
|
if (destroyed)
|
|
throw new IllegalStateException("This key is no longer valid");
|
|
|
|
switch (eType) {
|
|
case EncryptedData.ETYPE_DES_CBC_CRC:
|
|
case EncryptedData.ETYPE_DES_CBC_MD5:
|
|
return "DES";
|
|
|
|
case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
|
|
return "DESede";
|
|
|
|
case EncryptedData.ETYPE_ARCFOUR_HMAC:
|
|
return "ArcFourHmac";
|
|
|
|
case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96:
|
|
return "AES128";
|
|
|
|
case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96:
|
|
return "AES256";
|
|
|
|
case EncryptedData.ETYPE_NULL:
|
|
return "NULL";
|
|
|
|
default:
|
|
throw new IllegalArgumentException(
|
|
"Unsupported encryption type: " + eType);
|
|
}
|
|
}
|
|
|
|
public final String getFormat() {
|
|
if (destroyed)
|
|
throw new IllegalStateException("This key is no longer valid");
|
|
return "RAW";
|
|
}
|
|
|
|
public final byte[] getEncoded() {
|
|
if (destroyed)
|
|
throw new IllegalStateException("This key is no longer valid");
|
|
return keyBytes.clone();
|
|
}
|
|
|
|
public void destroy() throws DestroyFailedException {
|
|
if (!destroyed) {
|
|
destroyed = true;
|
|
Arrays.fill(keyBytes, (byte) 0);
|
|
}
|
|
}
|
|
|
|
public boolean isDestroyed() {
|
|
return destroyed;
|
|
}
|
|
|
|
/**
|
|
* @serialData this {@code KeyImpl} is serialized by
|
|
* writing out the ASN1 Encoded bytes of the encryption key.
|
|
* The ASN1 encoding is defined in RFC4120 and as follows:
|
|
* EncryptionKey ::= SEQUENCE {
|
|
* keytype [0] Int32 -- actually encryption type --,
|
|
* keyvalue [1] OCTET STRING
|
|
* }
|
|
*/
|
|
private void writeObject(ObjectOutputStream ois)
|
|
throws IOException {
|
|
if (destroyed) {
|
|
throw new IOException("This key is no longer valid");
|
|
}
|
|
|
|
try {
|
|
ois.writeObject((new EncryptionKey(keyType, keyBytes)).asn1Encode());
|
|
} catch (Asn1Exception ae) {
|
|
throw new IOException(ae.getMessage());
|
|
}
|
|
}
|
|
|
|
private void readObject(ObjectInputStream ois)
|
|
throws IOException, ClassNotFoundException {
|
|
try {
|
|
EncryptionKey encKey = new EncryptionKey(new
|
|
DerValue((byte[])ois.readObject()));
|
|
keyType = encKey.getEType();
|
|
keyBytes = encKey.getBytes();
|
|
} catch (Asn1Exception ae) {
|
|
throw new IOException(ae.getMessage());
|
|
}
|
|
}
|
|
|
|
public String toString() {
|
|
HexDumpEncoder hd = new HexDumpEncoder();
|
|
return "EncryptionKey: keyType=" + keyType
|
|
+ " keyBytes (hex dump)="
|
|
+ (keyBytes == null || keyBytes.length == 0 ?
|
|
" Empty Key" :
|
|
'\n' + hd.encodeBuffer(keyBytes)
|
|
+ '\n');
|
|
|
|
|
|
}
|
|
|
|
public int hashCode() {
|
|
int result = 17;
|
|
if(isDestroyed()) {
|
|
return result;
|
|
}
|
|
result = 37 * result + Arrays.hashCode(keyBytes);
|
|
return 37 * result + keyType;
|
|
}
|
|
|
|
public boolean equals(Object other) {
|
|
|
|
if (other == this)
|
|
return true;
|
|
|
|
if (! (other instanceof KeyImpl)) {
|
|
return false;
|
|
}
|
|
|
|
KeyImpl otherKey = ((KeyImpl) other);
|
|
if (isDestroyed() || otherKey.isDestroyed()) {
|
|
return false;
|
|
}
|
|
|
|
if(keyType != otherKey.getKeyType() ||
|
|
!Arrays.equals(keyBytes, otherKey.getEncoded())) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|