001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.shared.kerberos.components; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025import java.security.MessageDigest; 026import java.util.Arrays; 027 028import org.apache.directory.api.asn1.Asn1Object; 029import org.apache.directory.api.asn1.EncoderException; 030import org.apache.directory.api.asn1.ber.tlv.BerValue; 031import org.apache.directory.api.asn1.ber.tlv.TLV; 032import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 033import org.apache.directory.api.util.Strings; 034import org.apache.directory.server.i18n.I18n; 035import org.apache.directory.shared.kerberos.KerberosConstants; 036import org.apache.directory.shared.kerberos.codec.types.EncryptionType; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040 041/** 042 * A Kerberos symmetric encryption key, which includes metadata support for 043 * the associated key type and key version number. 044 * 045 * The ASN.1 description for this structure is : 046 * <pre> 047 * EncryptionKey ::= SEQUENCE { 048 * keytype [0] Int32 -- actually encryption type --, 049 * keyvalue [1] OCTET STRING 050 * } 051 * </pre> 052 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 053 */ 054public class EncryptionKey implements Asn1Object 055{ 056 /** The logger */ 057 private static final Logger log = LoggerFactory.getLogger( EncryptionKey.class ); 058 059 /** Speedup for logs */ 060 private static final boolean IS_DEBUG = log.isDebugEnabled(); 061 062 /** The encryption type */ 063 private EncryptionType keyType; 064 065 /** The encrypted value */ 066 private byte[] keyValue; 067 068 /** The key version */ 069 private int keyVersion; 070 071 // Storage for computed lengths 072 private int keyTypeLength; 073 private int keyValueLength; 074 private int encryptionKeyLength; 075 076 077 /** 078 * Creates a new instance of EncryptionKey. 079 */ 080 public EncryptionKey() 081 { 082 } 083 084 085 /** 086 * Creates a new instance of EncryptionKey. 087 * 088 * @param keyType The encryptionType 089 * @param keyValue The value 090 */ 091 public EncryptionKey( EncryptionType keyType, byte[] keyValue ) 092 { 093 this.keyType = keyType; 094 this.keyValue = keyValue; 095 } 096 097 098 /** 099 * Creates a new instance of EncryptionKey. 100 * 101 * @param keyType The encryptionType 102 * @param keyValue The value 103 * @param keyVersion ??? 104 */ 105 public EncryptionKey( EncryptionType keyType, byte[] keyValue, int keyVersion ) 106 { 107 this.keyType = keyType; 108 this.keyValue = keyValue; 109 this.keyVersion = keyVersion; 110 } 111 112 113 /** 114 * Destroys this key by overwriting the symmetric key material with zeros. 115 */ 116 public synchronized void destroy() 117 { 118 if ( keyValue != null ) 119 { 120 Arrays.fill( keyValue, ( byte ) 0x00 ); 121 } 122 } 123 124 125 /** 126 * Returns the key type. 127 * 128 * @return The key type. 129 */ 130 public EncryptionType getKeyType() 131 { 132 return keyType; 133 } 134 135 136 /** 137 * Set the encryption type 138 * @param keyType The encryption type 139 */ 140 public void setKeyType( EncryptionType keyType ) 141 { 142 this.keyType = keyType; 143 } 144 145 146 /** 147 * Returns the key value. 148 * 149 * @return The key value. 150 */ 151 public byte[] getKeyValue() 152 { 153 return keyValue; 154 } 155 156 157 /** 158 * Returns the key version. 159 * 160 * @return The key version. 161 */ 162 public int getKeyVersion() 163 { 164 return keyVersion; 165 } 166 167 168 /** 169 * Set the key value 170 * @param keyVersion The key version 171 */ 172 public void setKeyVersion( int keyVersion ) 173 { 174 this.keyVersion = keyVersion; 175 } 176 177 178 /** 179 * Set the key value 180 * @param keyValue The key value 181 */ 182 public void setKeyValue( byte[] keyValue ) 183 { 184 this.keyValue = keyValue; 185 } 186 187 188 /** 189 * {@inheritDoc} 190 */ 191 @Override 192 public int hashCode() 193 { 194 int hash = 37; 195 hash = hash * 17 + keyType.hashCode(); 196 hash = hash * 17 + Arrays.hashCode( keyValue ); 197 198 return hash; 199 } 200 201 202 /** 203 * @see Object#equals(Object) 204 */ 205 @Override 206 public boolean equals( Object o ) 207 { 208 if ( this == o ) 209 { 210 return true; 211 } 212 213 if ( !( o instanceof EncryptionKey ) ) 214 { 215 return false; 216 } 217 218 EncryptionKey that = ( EncryptionKey ) o; 219 return ( this.keyType == that.keyType ) && ( MessageDigest.isEqual( this.keyValue, that.keyValue ) ); 220 } 221 222 223 /** 224 * Compute the EncryptionKey length 225 * <pre> 226 * EncryptionKey : 227 * 228 * 0x30 L1 EncryptionKey 229 * | 230 * +--> 0xA0 L2 keyType tag 231 * | | 232 * | +--> 0x02 L2-1 keyType (int) 233 * | 234 * +--> 0xA1 L3 keyValue tag 235 * | 236 * +--> 0x04 L3-1 keyValue (OCTET STRING) 237 * 238 * where L1 = L2 + lenght(0xA0) + length(L2) + 239 * L3 + lenght(0xA1) + length(L3) 240 * and 241 * L2 = L2-1 + length(0x02) + length( L2-1) 242 * L3 = L3-1 + length(0x04) + length( L3-1) 243 * </pre> 244 */ 245 public int computeLength() 246 { 247 // Compute the keyType. The Length will always be cobntained in 1 byte 248 keyTypeLength = 1 + 1 + BerValue.getNbBytes( keyType.getValue() ); 249 encryptionKeyLength = 1 + TLV.getNbBytes( keyTypeLength ) + keyTypeLength; 250 251 // Compute the keyValue 252 if ( keyValue == null ) 253 { 254 keyValueLength = 1 + 1; 255 } 256 else 257 { 258 keyValueLength = 1 + TLV.getNbBytes( keyValue.length ) + keyValue.length; 259 } 260 261 encryptionKeyLength += 1 + TLV.getNbBytes( keyValueLength ) + keyValueLength; 262 263 // Compute the whole sequence length 264 return 1 + BerValue.getNbBytes( encryptionKeyLength ) + encryptionKeyLength; 265 } 266 267 268 /** 269 * Encode the EncryptionKey message to a PDU. 270 * <pre> 271 * EncryptionKey : 272 * 273 * 0x30 LL 274 * 0xA0 LL 275 * 0x02 0x01 keyType 276 * 0xA1 LL 277 * 0x04 LL keyValue 278 * </pre> 279 * @param buffer The buffer where to put the PDU. It should have been allocated 280 * before, with the right size. 281 * @return The constructed PDU. 282 */ 283 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 284 { 285 if ( buffer == null ) 286 { 287 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 288 } 289 290 try 291 { 292 // The EncryptionKey SEQ Tag 293 buffer.put( UniversalTag.SEQUENCE.getValue() ); 294 buffer.put( TLV.getBytes( encryptionKeyLength ) ); 295 296 // The keyType, first the tag, then the value 297 buffer.put( ( byte ) KerberosConstants.ENCRYPTION_KEY_TYPE_TAG ); 298 buffer.put( TLV.getBytes( keyTypeLength ) ); 299 BerValue.encode( buffer, keyType.getValue() ); 300 301 // The keyValue, first the tag, then the value 302 buffer.put( ( byte ) KerberosConstants.ENCRYPTION_KEY_VALUE_TAG ); 303 buffer.put( TLV.getBytes( keyValueLength ) ); 304 BerValue.encode( buffer, keyValue ); 305 } 306 catch ( BufferOverflowException boe ) 307 { 308 log.error( I18n.err( I18n.ERR_142, 1 + TLV.getNbBytes( encryptionKeyLength ) 309 + encryptionKeyLength, buffer.capacity() ) ); 310 throw new EncoderException( I18n.err( I18n.ERR_138 ), boe ); 311 } 312 313 if ( IS_DEBUG ) 314 { 315 log.debug( "EncryptionKey encoding : {}", Strings.dumpBytes( buffer.array() ) ); 316 log.debug( "EncryptionKey initial value : {}", this ); 317 } 318 319 return buffer; 320 } 321 322 323 /** 324 * @see Object#toString() 325 */ 326 public String toString() 327 { 328 return keyType.toString() + " (" + keyType.getValue() + ")"; 329 } 330}