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    
021    package org.apache.directory.server.kerberos.shared.crypto.encryption;
022    
023    
024    import java.io.IOException;
025    import java.util.Collections;
026    import java.util.HashMap;
027    import java.util.Map;
028    
029    import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
030    import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
031    import org.apache.directory.server.kerberos.shared.io.decoder.AuthenticatorDecoder;
032    import org.apache.directory.server.kerberos.shared.io.decoder.AuthorizationDataDecoder;
033    import org.apache.directory.server.kerberos.shared.io.decoder.Decoder;
034    import org.apache.directory.server.kerberos.shared.io.decoder.DecoderFactory;
035    import org.apache.directory.server.kerberos.shared.io.decoder.EncApRepPartDecoder;
036    import org.apache.directory.server.kerberos.shared.io.decoder.EncKdcRepPartDecoder;
037    import org.apache.directory.server.kerberos.shared.io.decoder.EncKrbPrivPartDecoder;
038    import org.apache.directory.server.kerberos.shared.io.decoder.EncTicketPartDecoder;
039    import org.apache.directory.server.kerberos.shared.io.decoder.EncryptedTimestampDecoder;
040    import org.apache.directory.server.kerberos.shared.io.encoder.AuthenticatorEncoder;
041    import org.apache.directory.server.kerberos.shared.io.encoder.EncApRepPartEncoder;
042    import org.apache.directory.server.kerberos.shared.io.encoder.EncAsRepPartEncoder;
043    import org.apache.directory.server.kerberos.shared.io.encoder.EncKrbPrivPartEncoder;
044    import org.apache.directory.server.kerberos.shared.io.encoder.EncTgsRepPartEncoder;
045    import org.apache.directory.server.kerberos.shared.io.encoder.EncTicketPartEncoder;
046    import org.apache.directory.server.kerberos.shared.io.encoder.Encoder;
047    import org.apache.directory.server.kerberos.shared.io.encoder.EncoderFactory;
048    import org.apache.directory.server.kerberos.shared.io.encoder.EncryptedTimestampEncoder;
049    import org.apache.directory.server.kerberos.shared.messages.AuthenticationReply;
050    import org.apache.directory.server.kerberos.shared.messages.Encodable;
051    import org.apache.directory.server.kerberos.shared.messages.TicketGrantReply;
052    import org.apache.directory.server.kerberos.shared.messages.components.Authenticator;
053    import org.apache.directory.server.kerberos.shared.messages.components.EncApRepPart;
054    import org.apache.directory.server.kerberos.shared.messages.components.EncKdcRepPart;
055    import org.apache.directory.server.kerberos.shared.messages.components.EncKrbPrivPart;
056    import org.apache.directory.server.kerberos.shared.messages.components.EncTicketPart;
057    import org.apache.directory.server.kerberos.shared.messages.value.AuthorizationData;
058    import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
059    import org.apache.directory.server.kerberos.shared.messages.value.EncryptedTimeStamp;
060    import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
061    
062    
063    /**
064     * A Hashed Adapter encapsulating ASN.1 encoders and decoders and cipher text engines to
065     * perform seal() and unseal() operations.  A seal() operation performs an encode and an
066     * encrypt, while an unseal() operation performs a decrypt and a decode.
067     * 
068     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
069     * @version $Rev: 548929 $, $Date: 2007-06-20 07:28:46 +0300 (Wed, 20 Jun 2007) $
070     */
071    public class CipherTextHandler
072    {
073        /** a map of the default encodable class names to the encoder class names */
074        private static final Map DEFAULT_ENCODERS;
075        /** a map of the default encodable class names to the decoder class names */
076        private static final Map DEFAULT_DECODERS;
077        /** a map of the default encryption types to the encryption engine class names */
078        private static final Map DEFAULT_CIPHERS;
079    
080        static
081        {
082            Map<Class, Class> map = new HashMap<Class, Class>();
083    
084            map.put( EncryptedTimeStamp.class, EncryptedTimestampEncoder.class );
085            map.put( EncTicketPart.class, EncTicketPartEncoder.class );
086            map.put( AuthenticationReply.class, EncAsRepPartEncoder.class );
087            map.put( TicketGrantReply.class, EncTgsRepPartEncoder.class );
088            map.put( EncKrbPrivPart.class, EncKrbPrivPartEncoder.class );
089            map.put( EncApRepPart.class, EncApRepPartEncoder.class );
090            map.put( Authenticator.class, AuthenticatorEncoder.class );
091    
092            DEFAULT_ENCODERS = Collections.unmodifiableMap( map );
093        }
094    
095        static
096        {
097            Map<Class, Class> map = new HashMap<Class, Class>();
098    
099            map.put( EncTicketPart.class, EncTicketPartDecoder.class );
100            map.put( Authenticator.class, AuthenticatorDecoder.class );
101            map.put( EncryptedTimeStamp.class, EncryptedTimestampDecoder.class );
102            map.put( AuthorizationData.class, AuthorizationDataDecoder.class );
103            map.put( EncKrbPrivPart.class, EncKrbPrivPartDecoder.class );
104            map.put( EncApRepPart.class, EncApRepPartDecoder.class );
105            map.put( EncKdcRepPart.class, EncKdcRepPartDecoder.class );
106    
107            DEFAULT_DECODERS = Collections.unmodifiableMap( map );
108        }
109    
110        static
111        {
112            Map<EncryptionType, Class> map = new HashMap<EncryptionType, Class>();
113    
114            map.put( EncryptionType.DES_CBC_MD5, DesCbcMd5Encryption.class );
115            map.put( EncryptionType.DES3_CBC_SHA1_KD, Des3CbcSha1KdEncryption.class );
116            map.put( EncryptionType.AES128_CTS_HMAC_SHA1_96, Aes128CtsSha1Encryption.class );
117            map.put( EncryptionType.AES256_CTS_HMAC_SHA1_96, Aes256CtsSha1Encryption.class );
118            map.put( EncryptionType.RC4_HMAC, ArcFourHmacMd5Encryption.class );
119    
120            DEFAULT_CIPHERS = Collections.unmodifiableMap( map );
121        }
122    
123    
124        /**
125         * Performs an encode and an encrypt.
126         *
127         * @param key The key to use for encrypting.
128         * @param encodable The Kerberos object to encode.
129         * @param usage The key usage.
130         * @return The Kerberos EncryptedData.
131         * @throws KerberosException
132         */
133        public EncryptedData seal( EncryptionKey key, Encodable encodable, KeyUsage usage ) throws KerberosException
134        {
135            try
136            {
137                return encrypt( key, encode( encodable ), usage );
138            }
139            catch ( IOException ioe )
140            {
141                throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, ioe );
142            }
143            catch ( ClassCastException cce )
144            {
145                throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, cce );
146            }
147        }
148    
149    
150        /**
151         * Perform a decrypt and a decode.
152         *
153         * @param hint The class the encrypted data is expected to contain.
154         * @param key The key to use for decryption.
155         * @param data The data to decrypt.
156         * @param usage The key usage.
157         * @return The Kerberos object resulting from a successful decrypt and decode.
158         * @throws KerberosException
159         */
160        public Encodable unseal( Class hint, EncryptionKey key, EncryptedData data, KeyUsage usage )
161            throws KerberosException
162        {
163            try
164            {
165                return decode( hint, decrypt( key, data, usage ) );
166            }
167            catch ( IOException ioe )
168            {
169                throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, ioe );
170            }
171            catch ( ClassCastException cce )
172            {
173                throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, cce );
174            }
175        }
176    
177    
178        private EncryptedData encrypt( EncryptionKey key, byte[] plainText, KeyUsage usage ) throws KerberosException
179        {
180            EncryptionEngine engine = getEngine( key );
181    
182            return engine.getEncryptedData( key, plainText, usage );
183        }
184    
185    
186        private byte[] decrypt( EncryptionKey key, EncryptedData data, KeyUsage usage ) throws KerberosException
187        {
188            EncryptionEngine engine = getEngine( key );
189    
190            return engine.getDecryptedData( key, data, usage );
191        }
192    
193    
194        private byte[] encode( Encodable encodable ) throws IOException
195        {
196            Class encodableClass = encodable.getClass();
197    
198            Class clazz = ( Class ) DEFAULT_ENCODERS.get( encodableClass );
199    
200            if ( clazz == null )
201            {
202                throw new IOException( "Encoder unavailable for " + encodableClass );
203            }
204    
205            EncoderFactory factory = null;
206    
207            try
208            {
209                factory = ( EncoderFactory ) clazz.newInstance();
210            }
211            catch ( IllegalAccessException iae )
212            {
213                throw new IOException( "Error accessing encoder for " + encodableClass );
214            }
215            catch ( InstantiationException ie )
216            {
217                throw new IOException( "Error instantiating encoder for " + encodableClass );
218            }
219    
220            Encoder encoder = factory.getEncoder();
221    
222            return encoder.encode( encodable );
223        }
224    
225    
226        private Encodable decode( Class encodable, byte[] plainText ) throws IOException
227        {
228            Class clazz = ( Class ) DEFAULT_DECODERS.get( encodable );
229    
230            if ( clazz == null )
231            {
232                throw new IOException( "Decoder unavailable for " + encodable );
233            }
234    
235            DecoderFactory factory = null;
236    
237            try
238            {
239                factory = ( DecoderFactory ) clazz.newInstance();
240            }
241            catch ( IllegalAccessException iae )
242            {
243                throw new IOException( "Error accessing decoder for " + encodable );
244            }
245            catch ( InstantiationException ie )
246            {
247                throw new IOException( "Error instantiating decoder for " + encodable );
248            }
249    
250            Decoder decoder = factory.getDecoder();
251    
252            return decoder.decode( plainText );
253        }
254    
255    
256        private EncryptionEngine getEngine( EncryptionKey key ) throws KerberosException
257        {
258            EncryptionType encryptionType = key.getKeyType();
259    
260            Class clazz = ( Class ) DEFAULT_CIPHERS.get( encryptionType );
261    
262            if ( clazz == null )
263            {
264                throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP );
265            }
266    
267            try
268            {
269                return ( EncryptionEngine ) clazz.newInstance();
270            }
271            catch ( IllegalAccessException iae )
272            {
273                throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP, iae );
274            }
275            catch ( InstantiationException ie )
276            {
277                throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP, ie );
278            }
279        }
280    }