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 */
020 package org.apache.directory.server.kerberos.shared.messages.value;
021
022
023 import java.nio.BufferOverflowException;
024 import java.nio.ByteBuffer;
025 import java.util.Arrays;
026
027 import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
028 import org.apache.directory.shared.asn1.AbstractAsn1Object;
029 import org.apache.directory.shared.asn1.ber.tlv.TLV;
030 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
031 import org.apache.directory.shared.asn1.ber.tlv.Value;
032 import org.apache.directory.shared.asn1.codec.EncoderException;
033 import org.apache.directory.shared.ldap.util.StringTools;
034 import org.slf4j.Logger;
035 import org.slf4j.LoggerFactory;
036
037
038 /**
039 * A Kerberos symmetric encryption key, which includes metadata support for
040 * the associated key type and key version number.
041 *
042 * The ASN.1 description for this structure is :
043 * EncryptionKey ::= SEQUENCE {
044 * keytype [0] Int32 -- actually encryption type --,
045 * keyvalue [1] OCTET STRING
046 * }
047 *
048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049 * @version $Rev: 642496 $, $Date: 2008-03-29 05:09:22 +0200 (Sat, 29 Mar 2008) $
050 */
051 public class EncryptionKey extends AbstractAsn1Object
052 {
053 /** The logger */
054 private static final Logger log = LoggerFactory.getLogger( EncryptionKey.class );
055
056 /** Speedup for logs */
057 private static final boolean IS_DEBUG = log.isDebugEnabled();
058
059 // The encryption type
060 private EncryptionType keyType;
061
062 // The encrypted value
063 private byte[] keyValue;
064
065 // The key version
066 private int keyVersion;
067
068 // Storage for computed lengths
069 private transient int keyTypeLength;
070 private transient int keyValueLength;
071 private transient int encryptionKeyLength;
072
073
074 /**
075 * Creates a new instance of EncryptionKey.
076 */
077 public EncryptionKey()
078 {
079 }
080
081
082 /**
083 * Creates a new instance of EncryptionKey.
084 *
085 * @param keyType The encryptionType
086 * @param keyValue The value
087 */
088 public EncryptionKey( EncryptionType keyType, byte[] keyValue )
089 {
090 this.keyType = keyType;
091 this.keyValue = keyValue;
092 }
093
094
095 /**
096 * Creates a new instance of EncryptionKey.
097 *
098 * @param keyType The encryptionType
099 * @param keyValue The value
100 * @param keyVersion ???
101 */
102 public EncryptionKey( EncryptionType keyType, byte[] keyValue, int keyVersion )
103 {
104 this.keyType = keyType;
105 this.keyValue = keyValue;
106 this.keyVersion = keyVersion;
107 }
108
109
110 /**
111 * Destroys this key by overwriting the symmetric key material with zeros.
112 */
113 public synchronized void destroy()
114 {
115 if ( keyValue != null )
116 {
117 Arrays.fill( keyValue, ( byte ) 0x00 );
118 }
119 }
120
121
122 /**
123 * Returns the key type.
124 *
125 * @return The key type.
126 */
127 public EncryptionType getKeyType()
128 {
129 return keyType;
130 }
131
132
133 /**
134 * Set the encryption type
135 * @param keyType The encryption type
136 */
137 public void setKeyType( EncryptionType keyType )
138 {
139 this.keyType = keyType;
140 }
141
142
143 /**
144 * Returns the key value.
145 *
146 * @return The key value.
147 */
148 public byte[] getKeyValue()
149 {
150 return keyValue;
151 }
152
153
154 /**
155 * Returns the key version.
156 *
157 * @return The key version.
158 */
159 public int getKeyVersion()
160 {
161 return keyVersion;
162 }
163
164
165 /**
166 * Set the key value
167 * @param keyVersion The key version
168 */
169 public void setKeyVersion( int keyVersion)
170 {
171 this.keyVersion = keyVersion;
172 }
173
174
175 /**
176 * Set the key value
177 * @param keyValue The key value
178 */
179 public void setKeyValue( byte[] keyValue )
180 {
181 this.keyValue = keyValue;
182 }
183
184
185 /**
186 * @see Object#equals(Object)
187 */
188 public boolean equals( Object o )
189 {
190 if ( this == o )
191 {
192 return true;
193 }
194
195 if ( ( o == null ) || !( o instanceof EncryptionKey ) )
196 {
197 return false;
198 }
199
200 EncryptionKey that = ( EncryptionKey ) o;
201 return ( this.keyType == that.keyType ) && ( Arrays.equals( this.keyValue, that.keyValue ) );
202 }
203
204
205 /**
206 * Compute the EncryptionKey length
207 *
208 * EncryptionKey :
209 *
210 * 0x30 L1 EncryptionKey
211 * |
212 * +--> 0xA0 L2 keyType tag
213 * | |
214 * | +--> 0x02 L2-1 keyType (int)
215 * |
216 * +--> 0xA1 L3 keyValue tag
217 * |
218 * +--> 0x04 L3-1 keyValue (OCTET STRING)
219 *
220 * where L1 = L2 + lenght(0xA0) + length(L2) +
221 * L3 + lenght(0xA1) + length(L3)
222 * and
223 * L2 = L2-1 + length(0x02) + length( L2-1)
224 * L3 = L3-1 + length(0x04) + length( L3-1)
225 */
226 public int computeLength()
227 {
228 // Compute the keyType. The Length will always be cobntained in 1 byte
229 keyTypeLength = 1 + 1 + Value.getNbBytes( keyType.getOrdinal() );
230 encryptionKeyLength = 1 + TLV.getNbBytes( keyTypeLength ) + keyTypeLength;
231
232 // Compute the keyValue
233 if ( keyValue == null )
234 {
235 keyValueLength = 1 + 1;
236 }
237 else
238 {
239 keyValueLength = 1 + TLV.getNbBytes( keyValue.length ) + keyValue.length;
240 }
241
242 encryptionKeyLength += 1 + TLV.getNbBytes( keyValueLength ) + keyValueLength;
243
244 // Compute the whole sequence length
245 int encryptionKeySeqLength = 1 + Value.getNbBytes( encryptionKeyLength ) + encryptionKeyLength;
246
247 return encryptionKeySeqLength;
248
249 }
250
251
252 /**
253 * Encode the EncryptionKey message to a PDU.
254 *
255 * EncryptionKey :
256 *
257 * 0x30 LL
258 * 0xA0 LL
259 * 0x02 0x01 keyType
260 * 0xA1 LL
261 * 0x04 LL keyValue
262 *
263 * @param buffer The buffer where to put the PDU. It should have been allocated
264 * before, with the right size.
265 * @return The constructed PDU.
266 */
267 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
268 {
269 if ( buffer == null )
270 {
271 throw new EncoderException( "Cannot put a PDU in a null buffer !" );
272 }
273
274 try
275 {
276 // The EncryptionKey SEQ Tag
277 buffer.put( UniversalTag.SEQUENCE_TAG );
278 buffer.put( TLV.getBytes( encryptionKeyLength ) );
279
280 // The keyType, first the tag, then the value
281 buffer.put( ( byte ) 0xA0 );
282 buffer.put( TLV.getBytes( keyTypeLength ) );
283 Value.encode( buffer, keyType.getOrdinal() );
284
285 // The keyValue, first the tag, then the value
286 buffer.put( ( byte ) 0xA1 );
287 buffer.put( TLV.getBytes( keyValueLength ) );
288 Value.encode( buffer, keyValue );
289 }
290 catch ( BufferOverflowException boe )
291 {
292 log.error(
293 "Cannot encode the EncryptionKey object, the PDU size is {} when only {} bytes has been allocated", 1
294 + TLV.getNbBytes( encryptionKeyLength ) + encryptionKeyLength, buffer.capacity() );
295 throw new EncoderException( "The PDU buffer size is too small !" );
296 }
297
298 if ( IS_DEBUG )
299 {
300 log.debug( "EncryptionKey encoding : {}", StringTools.dumpBytes( buffer.array() ) );
301 log.debug( "EncryptionKey initial value : {}", toString() );
302 }
303
304 return buffer;
305 }
306
307
308 /**
309 * @see Object#toString()
310 */
311 public String toString()
312 {
313 return keyType.toString() + " (" + keyType.getOrdinal() + ")";
314 }
315 }