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 */
020package org.apache.directory.server.kerberos.shared.crypto.checksum;
021
022
023import java.util.Collections;
024import java.util.EnumMap;
025import java.util.Map;
026
027import org.apache.directory.server.kerberos.shared.crypto.encryption.Aes128CtsSha1Encryption;
028import org.apache.directory.server.kerberos.shared.crypto.encryption.Aes256CtsSha1Encryption;
029import org.apache.directory.server.kerberos.shared.crypto.encryption.Des3CbcSha1KdEncryption;
030import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
031import org.apache.directory.shared.kerberos.components.Checksum;
032import org.apache.directory.shared.kerberos.crypto.checksum.ChecksumType;
033import org.apache.directory.shared.kerberos.exceptions.ErrorType;
034import org.apache.directory.shared.kerberos.exceptions.KerberosException;
035
036
037/**
038 * A Hashed Adapter encapsulating checksum engines for performing integrity checks.
039 *
040 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
041 */
042public class ChecksumHandler
043{
044    /** A map of the default encodable class names to the encoder class names. */
045    private static final Map<ChecksumType, Class<?>> DEFAULT_CHECKSUMS;
046
047    static
048    {
049        EnumMap<ChecksumType, Class<?>> map = new EnumMap<>( ChecksumType.class );
050
051        map.put( ChecksumType.HMAC_MD5, HmacMd5Checksum.class );
052        map.put( ChecksumType.HMAC_SHA1_96_AES128, Aes128CtsSha1Encryption.class );
053        map.put( ChecksumType.HMAC_SHA1_96_AES256, Aes256CtsSha1Encryption.class );
054        map.put( ChecksumType.HMAC_SHA1_DES3_KD, Des3CbcSha1KdEncryption.class );
055        map.put( ChecksumType.RSA_MD5, RsaMd5Checksum.class );
056
057        DEFAULT_CHECKSUMS = Collections.unmodifiableMap( map );
058    }
059
060
061    /**
062     * Calculate a checksum based on raw bytes and an (optional) key for keyed checksums.
063     *
064     * @param checksumType The type of checksum to use
065     * @param bytes The data
066     * @param key The key
067     * @param usage The key usage 
068     * @return The computed {@link Checksum}.
069     * @throws KerberosException If the checksum can't be cmputed
070     */
071    public Checksum calculateChecksum( ChecksumType checksumType, byte[] bytes, byte[] key, KeyUsage usage )
072        throws KerberosException
073    {
074        if ( !DEFAULT_CHECKSUMS.containsKey( checksumType ) )
075        {
076            throw new KerberosException( ErrorType.KDC_ERR_SUMTYPE_NOSUPP );
077        }
078
079        ChecksumEngine digester = getEngine( checksumType );
080        return new Checksum( checksumType, digester.calculateChecksum( bytes, key, usage ) );
081    }
082
083
084    /**
085     * Verify a checksum by providing the raw bytes and an (optional) key for keyed checksums.
086     *
087     * @param checksum The checksum to verify
088     * @param bytes The data
089     * @param key The key
090     * @param usage The key usage 
091     * @throws KerberosException If the verification failed
092     */
093    public void verifyChecksum( Checksum checksum, byte[] bytes, byte[] key, KeyUsage usage ) throws KerberosException
094    {
095        if ( checksum == null )
096        {
097            throw new KerberosException( ErrorType.KRB_AP_ERR_INAPP_CKSUM );
098        }
099
100        if ( !DEFAULT_CHECKSUMS.containsKey( checksum.getChecksumType() ) )
101        {
102            throw new KerberosException( ErrorType.KDC_ERR_SUMTYPE_NOSUPP );
103        }
104
105        ChecksumType checksumType = checksum.getChecksumType();
106        ChecksumEngine digester = getEngine( checksumType );
107        Checksum newChecksum = new Checksum( checksumType, digester.calculateChecksum( bytes, key, usage ) );
108
109        if ( !newChecksum.equals( checksum ) )
110        {
111            throw new KerberosException( ErrorType.KRB_AP_ERR_MODIFIED );
112        }
113    }
114
115
116    private ChecksumEngine getEngine( ChecksumType checksumType ) throws KerberosException
117    {
118        Class<?> clazz = DEFAULT_CHECKSUMS.get( checksumType );
119
120        if ( clazz == null )
121        {
122            throw new KerberosException( ErrorType.KDC_ERR_SUMTYPE_NOSUPP );
123        }
124
125        try
126        {
127            return ( ChecksumEngine ) clazz.newInstance();
128        }
129        catch ( IllegalAccessException iae )
130        {
131            throw new KerberosException( ErrorType.KDC_ERR_SUMTYPE_NOSUPP, iae );
132        }
133        catch ( InstantiationException ie )
134        {
135            throw new KerberosException( ErrorType.KDC_ERR_SUMTYPE_NOSUPP, ie );
136        }
137    }
138}