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