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 15:38:06 +0100 (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    }