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