View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.kerberos.shared.messages.value;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.util.Arrays;
26  
27  import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
28  import org.apache.directory.shared.asn1.AbstractAsn1Object;
29  import org.apache.directory.shared.asn1.ber.tlv.TLV;
30  import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
31  import org.apache.directory.shared.asn1.ber.tlv.Value;
32  import org.apache.directory.shared.asn1.codec.EncoderException;
33  import org.apache.directory.shared.ldap.util.StringTools;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  
38  /**
39   * A Kerberos symmetric encryption key, which includes metadata support for
40   * the associated key type and key version number.
41   * 
42   * The ASN.1 description for this structure is :
43   * EncryptionKey   ::= SEQUENCE {
44   *       keytype         [0] Int32 -- actually encryption type --,
45   *       keyvalue        [1] OCTET STRING
46   * }
47   * 
48   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
49   * @version $Rev: 642496 $, $Date: 2008-03-29 04:09:22 +0100 (Sa, 29 Mär 2008) $
50   */
51  public class EncryptionKey extends AbstractAsn1Object
52  {
53      /** The logger */
54      private static final Logger log = LoggerFactory.getLogger( EncryptionKey.class );
55  
56      /** Speedup for logs */
57      private static final boolean IS_DEBUG = log.isDebugEnabled();
58  
59      // The encryption type
60      private EncryptionType keyType;
61  
62      // The encrypted value
63      private byte[] keyValue;
64      
65      // The key version
66      private int keyVersion;
67  
68      // Storage for computed lengths
69      private transient int keyTypeLength;
70      private transient int keyValueLength;
71      private transient int encryptionKeyLength;
72  
73  
74      /**
75       * Creates a new instance of EncryptionKey.
76       */
77      public EncryptionKey()
78      {
79      }
80      
81  
82      /**
83       * Creates a new instance of EncryptionKey.
84       *
85       * @param keyType The encryptionType 
86       * @param keyValue The value
87       */
88      public EncryptionKey( EncryptionType keyType, byte[] keyValue )
89      {
90          this.keyType = keyType;
91          this.keyValue = keyValue;
92      }
93  
94  
95      /**
96       * Creates a new instance of EncryptionKey.
97       *
98       * @param keyType The encryptionType 
99       * @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 }