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.shared.kerberos.components;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.security.MessageDigest;
26  import java.util.Arrays;
27  
28  import org.apache.directory.api.asn1.Asn1Object;
29  import org.apache.directory.api.asn1.EncoderException;
30  import org.apache.directory.api.asn1.ber.tlv.BerValue;
31  import org.apache.directory.api.asn1.ber.tlv.TLV;
32  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
33  import org.apache.directory.api.util.Strings;
34  import org.apache.directory.server.i18n.I18n;
35  import org.apache.directory.shared.kerberos.KerberosConstants;
36  import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  
41  /**
42   * A Kerberos symmetric encryption key, which includes metadata support for
43   * the associated key type and key version number.
44   * 
45   * The ASN.1 description for this structure is :
46   * <pre>
47   * EncryptionKey   ::= SEQUENCE {
48   *       keytype         [0] Int32 -- actually encryption type --,
49   *       keyvalue        [1] OCTET STRING
50   * }
51   * </pre>
52   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
53   */
54  public class EncryptionKey implements Asn1Object
55  {
56      /** The logger */
57      private static final Logger log = LoggerFactory.getLogger( EncryptionKey.class );
58  
59      /** Speedup for logs */
60      private static final boolean IS_DEBUG = log.isDebugEnabled();
61  
62      /** The encryption type */
63      private EncryptionType keyType;
64  
65      /** The encrypted value */
66      private byte[] keyValue;
67  
68      /** The key version */
69      private int keyVersion;
70  
71      // Storage for computed lengths
72      private int keyTypeLength;
73      private int keyValueLength;
74      private int encryptionKeyLength;
75  
76  
77      /**
78       * Creates a new instance of EncryptionKey.
79       */
80      public EncryptionKey()
81      {
82      }
83  
84  
85      /**
86       * Creates a new instance of EncryptionKey.
87       *
88       * @param keyType The encryptionType 
89       * @param keyValue The value
90       */
91      public EncryptionKey( EncryptionType keyType, byte[] keyValue )
92      {
93          this.keyType = keyType;
94          this.keyValue = keyValue;
95      }
96  
97  
98      /**
99       * 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../../../../org/apache/directory/shared/kerberos/components/EncryptionKey.html#EncryptionKey">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      *  +--&gt; 0xA0 L2 keyType tag
231      *  |     |
232      *  |     +--&gt; 0x02 L2-1 keyType (int)
233      *  |
234      *  +--&gt; 0xA1 L3 keyValue tag
235      *        |
236      *        +--&gt; 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 }