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