1. /*
  2. * @(#)KeyImpl.java 1.13 04/04/01
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.security.auth.kerberos;
  8. import java.io.*;
  9. import java.util.Arrays;
  10. import javax.crypto.SecretKey;
  11. import javax.security.auth.Destroyable;
  12. import javax.security.auth.DestroyFailedException;
  13. import sun.misc.HexDumpEncoder;
  14. import sun.security.krb5.Asn1Exception;
  15. import sun.security.krb5.PrincipalName;
  16. import sun.security.krb5.EncryptionKey;
  17. import sun.security.krb5.EncryptedData;
  18. import sun.security.krb5.KrbException;
  19. import sun.security.krb5.KrbCryptoException;
  20. import sun.security.util.DerValue;
  21. /**
  22. * This class encapsulates a Kerberos encryption key. It is not associated
  23. * with a principal and may represent an ephemeral session key.
  24. *
  25. * @author Mayank Upadhyay
  26. * @version 1.13, 04/01/04
  27. * @since 1.4
  28. *
  29. * @serial include
  30. */
  31. class KeyImpl implements SecretKey, Destroyable, Serializable {
  32. private static final long serialVersionUID = -7889313790214321193L;
  33. private transient byte[] keyBytes;
  34. private transient int keyType;
  35. private transient boolean destroyed = false;
  36. /**
  37. * Constructs a KeyImpl from the given bytes.
  38. *
  39. * @param keyBytes the raw bytes for the secret key
  40. * @param keyType the key type for the secret key as defined by the
  41. * Kerberos protocol specification.
  42. */
  43. public KeyImpl(byte[] keyBytes,
  44. int keyType) {
  45. this.keyBytes = (byte[]) keyBytes.clone();
  46. this.keyType = keyType;
  47. }
  48. /**
  49. * Constructs a KeyImpl from a password.
  50. *
  51. * @param principal the principal from which to derive the salt
  52. * @param password the password that should be used to compute the
  53. * key.
  54. * @param algorithm the name for the algorithm that this key wil be
  55. * used for. This parameter may be null in which case "DES" will be
  56. * assumed.
  57. */
  58. public KeyImpl(KerberosPrincipal principal,
  59. char[] password,
  60. String algorithm) {
  61. try {
  62. PrincipalName princ = new PrincipalName(principal.getName());
  63. EncryptionKey key =
  64. new EncryptionKey(password, princ.getSalt(),algorithm);
  65. this.keyBytes = key.getBytes();
  66. this.keyType = key.getEType();
  67. } catch (KrbException e) {
  68. throw new IllegalArgumentException(e.getMessage());
  69. }
  70. }
  71. /**
  72. * Returns the keyType for this key as defined in the Kerberos Spec.
  73. */
  74. public final int getKeyType() {
  75. if (destroyed)
  76. throw new IllegalStateException("This key is no longer valid");
  77. return keyType;
  78. }
  79. /*
  80. * Methods from java.security.Key
  81. */
  82. public final String getAlgorithm() {
  83. return getAlgorithmName(keyType);
  84. }
  85. private String getAlgorithmName(int eType) {
  86. if (destroyed)
  87. throw new IllegalStateException("This key is no longer valid");
  88. switch (eType) {
  89. case EncryptedData.ETYPE_DES_CBC_CRC:
  90. case EncryptedData.ETYPE_DES_CBC_MD5:
  91. return "DES";
  92. case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD:
  93. return "DESede";
  94. case EncryptedData.ETYPE_NULL:
  95. return "NULL";
  96. default:
  97. throw new IllegalArgumentException(
  98. "Unsupported encryption type: " + eType);
  99. }
  100. }
  101. public final String getFormat() {
  102. if (destroyed)
  103. throw new IllegalStateException("This key is no longer valid");
  104. return "RAW";
  105. }
  106. public final byte[] getEncoded() {
  107. if (destroyed)
  108. throw new IllegalStateException("This key is no longer valid");
  109. return (byte[])keyBytes.clone();
  110. }
  111. public void destroy() throws DestroyFailedException {
  112. if (!destroyed) {
  113. Arrays.fill(keyBytes, (byte) 0);
  114. destroyed = true;
  115. }
  116. }
  117. public boolean isDestroyed() {
  118. return destroyed;
  119. }
  120. /**
  121. * @serialData this <code>KeyImpl</code> is serialized by
  122. * writing out the ASN1 Encoded bytes of the
  123. * encryption key. The ASN1 encoding is defined in
  124. * RFC1510 and as follows:
  125. * EncryptionKey ::= SEQUENCE {
  126. * keytype[0] INTEGER,
  127. * keyvalue[1] OCTET STRING
  128. * }
  129. **/
  130. private synchronized void writeObject(ObjectOutputStream ois)
  131. throws IOException {
  132. if (destroyed) {
  133. throw new IOException ("This key is no longer valid");
  134. }
  135. try {
  136. ois.writeObject((new EncryptionKey(keyType,keyBytes)).asn1Encode());
  137. } catch (Asn1Exception ae) {
  138. throw new IOException(ae.getMessage());
  139. }
  140. }
  141. private synchronized void readObject(ObjectInputStream ois)
  142. throws IOException , ClassNotFoundException {
  143. try {
  144. EncryptionKey encKey = new EncryptionKey(new
  145. DerValue((byte[])ois.readObject()));
  146. keyType = encKey.getEType();
  147. keyBytes = encKey.getBytes();
  148. } catch (Asn1Exception ae) {
  149. throw new IOException (ae.getMessage());
  150. }
  151. }
  152. public String toString() {
  153. HexDumpEncoder hd = new HexDumpEncoder();
  154. return new String("EncryptionKey: keyType=" + keyType
  155. + " keyBytes (hex dump)="
  156. + (keyBytes == null || keyBytes.length == 0 ?
  157. " Empty Key" :
  158. '\n' + hd.encode(keyBytes)
  159. + '\n'));
  160. }
  161. }