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
021package org.apache.directory.server.kerberos.shared.crypto.encryption;
022
023
024import java.nio.ByteBuffer;
025import java.util.Collections;
026import java.util.EnumMap;
027import java.util.Map;
028
029import org.apache.directory.api.asn1.Asn1Object;
030import org.apache.directory.api.asn1.EncoderException;
031import org.apache.directory.api.ldap.model.constants.Loggers;
032import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
033import org.apache.directory.shared.kerberos.components.EncryptedData;
034import org.apache.directory.shared.kerberos.components.EncryptionKey;
035import org.apache.directory.shared.kerberos.exceptions.ErrorType;
036import org.apache.directory.shared.kerberos.exceptions.KerberosException;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * A Hashed Adapter encapsulating ASN.1 cipher text engines to
043 * perform encrypt() and decrypt() operations.
044 *
045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
046 */
047public class CipherTextHandler
048{
049    /** The loggers for this class */
050    private static final Logger LOG_KRB = LoggerFactory.getLogger( Loggers.KERBEROS_LOG.getName() );
051
052    /** a map of the default encryption types to the encryption engine class names */
053    private static final Map<EncryptionType, Class<? extends EncryptionEngine>> DEFAULT_CIPHERS;
054
055    // Initialize the list of encyption mechanisms
056    static
057    {
058        EnumMap<EncryptionType, Class<? extends EncryptionEngine>> map = new EnumMap<>( EncryptionType.class );
059
060        map.put( EncryptionType.DES_CBC_MD5, DesCbcMd5Encryption.class );
061        map.put( EncryptionType.DES3_CBC_SHA1_KD, Des3CbcSha1KdEncryption.class );
062        map.put( EncryptionType.AES128_CTS_HMAC_SHA1_96, Aes128CtsSha1Encryption.class );
063        map.put( EncryptionType.AES256_CTS_HMAC_SHA1_96, Aes256CtsSha1Encryption.class );
064        map.put( EncryptionType.RC4_HMAC, ArcFourHmacMd5Encryption.class );
065
066        DEFAULT_CIPHERS = Collections.unmodifiableMap( map );
067    }
068
069
070    /**
071     * Performs an encode and an encrypt.
072     *
073     * @param key The key to use for encrypting.
074     * @param message The Kerberos object to encode.
075     * @param usage The key usage.
076     * @return The Kerberos EncryptedData.
077     * @throws KerberosException if the seal failed
078     */
079    public EncryptedData seal( EncryptionKey key, Asn1Object message, KeyUsage usage ) throws KerberosException
080    {
081        try
082        {
083            int bufferSize = message.computeLength();
084            ByteBuffer buffer = ByteBuffer.allocate( bufferSize );
085            byte[] encoded = message.encode( buffer ).array();
086            return encrypt( key, encoded, usage );
087        }
088        catch ( EncoderException ioe )
089        {
090            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, ioe );
091        }
092        catch ( ClassCastException cce )
093        {
094            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, cce );
095        }
096    }
097
098
099    public EncryptedData encrypt( EncryptionKey key, byte[] plainText, KeyUsage usage ) throws KerberosException
100    {
101        EncryptionEngine engine = getEngine( key );
102
103        return engine.getEncryptedData( key, plainText, usage );
104    }
105
106
107    /**
108     * Decrypt a block of data.
109     *
110     * @param key The key used to decrypt the data
111     * @param data The data to decrypt
112     * @param usage The key usage number
113     * @return The decrypted data as a byte[]
114     * @throws KerberosException If the decoding failed
115     */
116    public byte[] decrypt( EncryptionKey key, EncryptedData data, KeyUsage usage ) throws KerberosException
117    {
118        LOG_KRB.debug( "Decrypting data using key {} and usage {}", key.getKeyType(), usage );
119        EncryptionEngine engine = getEngine( key );
120
121        return engine.getDecryptedData( key, data, usage );
122    }
123
124
125    private EncryptionEngine getEngine( EncryptionKey key ) throws KerberosException
126    {
127        EncryptionType encryptionType = key.getKeyType();
128
129        Class<?> clazz = DEFAULT_CIPHERS.get( encryptionType );
130
131        if ( clazz == null )
132        {
133            throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP );
134        }
135
136        try
137        {
138            return ( EncryptionEngine ) clazz.newInstance();
139        }
140        catch ( IllegalAccessException iae )
141        {
142            throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP, iae );
143        }
144        catch ( InstantiationException ie )
145        {
146            throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP, ie );
147        }
148    }
149}