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.encryption;
021
022
023import java.security.SecureRandom;
024
025import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
026import org.apache.directory.shared.kerberos.components.EncryptedData;
027import org.apache.directory.shared.kerberos.components.EncryptionKey;
028import org.apache.directory.shared.kerberos.exceptions.KerberosException;
029
030
031/**
032 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
033 */
034public abstract class EncryptionEngine
035{
036    private static final SecureRandom random = new SecureRandom();
037
038
039    protected abstract byte[] getDecryptedData( EncryptionKey key, EncryptedData data, KeyUsage usage )
040        throws KerberosException;
041
042
043    protected abstract EncryptedData getEncryptedData( EncryptionKey key, byte[] plainText, KeyUsage usage );
044
045
046    protected abstract EncryptionType getEncryptionType();
047
048
049    protected abstract int getConfounderLength();
050
051
052    protected abstract int getChecksumLength();
053
054
055    protected abstract byte[] encrypt( byte[] plainText, byte[] key );
056
057
058    protected abstract byte[] decrypt( byte[] cipherText, byte[] key );
059
060
061    protected abstract byte[] calculateIntegrity( byte[] plainText, byte[] key, KeyUsage usage );
062
063
064    protected byte[] deriveRandom( byte[] key, byte[] usage, int n, int k )
065    {
066        byte[] nFoldedUsage = NFold.nFold( n, usage );
067
068        int kBytes = k / 8;
069        byte[] result = new byte[kBytes];
070
071        byte[] fillingKey = encrypt( nFoldedUsage, key );
072
073        int pos = 0;
074
075        for ( int i = 0; i < kBytes; i++ )
076        {
077            if ( pos < fillingKey.length )
078            {
079                result[i] = fillingKey[pos];
080                pos++;
081            }
082            else
083            {
084                fillingKey = encrypt( fillingKey, key );
085                pos = 0;
086                result[i] = fillingKey[pos];
087                pos++;
088            }
089        }
090
091        return result;
092    }
093
094
095    // Encryption
096    protected byte[] getRandomBytes( int size )
097    {
098        byte[] bytes = new byte[size];
099
100        // SecureRandom.nextBytes is already synchronized
101        random.nextBytes( bytes );
102
103        return bytes;
104    }
105
106
107    // Encryption
108    protected byte[] padString( byte encodedString[] )
109    {
110        int x;
111        if ( encodedString.length < 8 )
112        {
113            x = encodedString.length;
114        }
115        else
116        {
117            x = encodedString.length % 8;
118        }
119
120        if ( x == 0 )
121        {
122            return encodedString;
123        }
124
125        byte paddedByteArray[] = new byte[( 8 - x ) + encodedString.length];
126
127        for ( int y = paddedByteArray.length - 1; y > encodedString.length - 1; y-- )
128        {
129            paddedByteArray[y] = 0;
130        }
131
132        System.arraycopy( encodedString, 0, paddedByteArray, 0, encodedString.length );
133
134        return paddedByteArray;
135    }
136
137
138    // Encryption
139    protected byte[] concatenateBytes( byte[] array1, byte[] array2 )
140    {
141        int l1 = array1.length;
142        int l2 = array2.length;
143        byte concatenatedBytes[] = new byte[l1 + l2];
144
145        System.arraycopy( array1, 0, concatenatedBytes, 0, l1 );
146        System.arraycopy( array2, 0, concatenatedBytes, l1, l2 );
147
148        return concatenatedBytes;
149    }
150
151
152    // Decryption
153    protected byte[] removeLeadingBytes( byte[] array, int confounder, int checksum )
154    {
155        byte lessBytes[] = new byte[array.length - confounder - checksum];
156
157        int j = 0;
158        for ( int i = confounder + checksum; i < array.length; i++ )
159        {
160            lessBytes[j] = array[i];
161            j++;
162        }
163
164        return lessBytes;
165    }
166
167
168    protected byte[] removeTrailingBytes( byte[] array, int confounder, int checksum )
169    {
170        byte lessBytes[] = new byte[array.length - confounder - checksum];
171
172        int j = 0;
173        for ( int i = 0; i < array.length - confounder - checksum; i++ )
174        {
175            lessBytes[j] = array[i];
176            j++;
177        }
178
179        return lessBytes;
180    }
181
182
183    protected int getBit( byte[] data, int pos )
184    {
185        int posByte = pos / 8;
186        int posBit = pos % 8;
187
188        byte valByte = data[posByte];
189        
190        return valByte >> ( 8 - ( posBit + 1 ) ) & 0x0001;
191    }
192
193
194    protected void setBit( byte[] data, int pos, int val )
195    {
196        int posByte = pos / 8;
197        int posBit = pos % 8;
198        byte oldByte = data[posByte];
199        oldByte = ( byte ) ( ( ( 0xFF7F >> posBit ) & oldByte ) & 0x00FF );
200        byte newByte = ( byte ) ( ( val << ( 8 - ( posBit + 1 ) ) ) | oldByte );
201        data[posByte] = newByte;
202    }
203
204
205    /**
206     * The "well-known constant" used for the DK function is the key
207     * usage number, expressed as four octets in big-endian order,
208     * followed by one octet indicated below.
209     * 
210     *  Kc = DK(base-key, usage | 0x99);
211     *  
212     *  @param usage The key usage
213     *  @return the computed usage Kc
214     */
215    protected byte[] getUsageKc( KeyUsage usage )
216    {
217        return getUsage( usage.getOrdinal(), ( byte ) 0x99 );
218    }
219
220
221    /**
222     * The "well-known constant" used for the DK function is the key
223     * usage number, expressed as four octets in big-endian order,
224     * followed by one octet indicated below.
225     * 
226     *  Ke = DK(base-key, usage | 0xAA);
227     *  
228     *  @param usage The key usage
229     *  @return the computed usage Ke
230     */
231    protected byte[] getUsageKe( KeyUsage usage )
232    {
233        return getUsage( usage.getOrdinal(), ( byte ) 0xAA );
234    }
235
236
237    /**
238     * The "well-known constant" used for the DK function is the key
239     * usage number, expressed as four octets in big-endian order,
240     * followed by one octet indicated below.
241     * 
242     *  Ki = DK(base-key, usage | 0x55);
243     *  
244     *  @param usage The key usage
245     *  @return the computed usage Ki
246     */
247    protected byte[] getUsageKi( KeyUsage usage )
248    {
249        return getUsage( usage.getOrdinal(), ( byte ) 0x55 );
250    }
251
252
253    private byte[] getUsage( int usage, byte constant )
254    {
255        byte[] bytes = new byte[5];
256        bytes[0] = ( byte ) ( ( usage >>> 24 ) & 0x000000FF );
257        bytes[1] = ( byte ) ( ( usage >> 16 ) & 0x000000FF );
258        bytes[2] = ( byte ) ( ( usage >> 8 ) & 0x000000FF );
259        bytes[3] = ( byte ) ( usage & 0x00FF );
260        bytes[4] = constant;
261
262        return bytes;
263    }
264}