1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.kerberos.shared.crypto.encryption;
21
22
23 import java.security.GeneralSecurityException;
24 import java.security.spec.AlgorithmParameterSpec;
25 import java.util.Arrays;
26
27 import javax.crypto.Cipher;
28 import javax.crypto.Mac;
29 import javax.crypto.SecretKey;
30 import javax.crypto.spec.IvParameterSpec;
31 import javax.crypto.spec.SecretKeySpec;
32
33 import org.apache.directory.server.kerberos.shared.crypto.checksum.ChecksumEngine;
34 import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
35 import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
36 import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
37 import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
38
39
40
41
42
43
44 abstract class AesCtsSha1Encryption extends EncryptionEngine implements ChecksumEngine
45 {
46 private static final byte[] iv = new byte[]
47 { ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
48 ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
49 ( byte ) 0x00, ( byte ) 0x00 };
50
51
52 public int getConfounderLength()
53 {
54 return 16;
55 }
56
57
58 public int getChecksumLength()
59 {
60 return 12;
61 }
62
63
64 protected abstract int getKeyLength();
65
66
67 public byte[] calculateChecksum( byte[] data, byte[] key, KeyUsage usage )
68 {
69 byte[] Kc = deriveKey( key, getUsageKc( usage ), 128, getKeyLength() );
70 byte[] checksum = processChecksum( data, Kc );
71
72 return removeTrailingBytes( checksum, 0, checksum.length - getChecksumLength() );
73 }
74
75
76 public byte[] calculateIntegrity( byte[] data, byte[] key, KeyUsage usage )
77 {
78 byte[] Ki = deriveKey( key, getUsageKi( usage ), 128, getKeyLength() );
79 byte[] checksum = processChecksum( data, Ki );
80
81 return removeTrailingBytes( checksum, 0, checksum.length - getChecksumLength() );
82 }
83
84
85 public byte[] getDecryptedData( EncryptionKey key, EncryptedData data, KeyUsage usage ) throws KerberosException
86 {
87 byte[] Ke = deriveKey( key.getKeyValue(), getUsageKe( usage ), 128, getKeyLength() );
88
89 byte[] encryptedData = data.getCipher();
90
91
92 byte[] oldChecksum = new byte[getChecksumLength()];
93 System
94 .arraycopy( encryptedData, encryptedData.length - getChecksumLength(), oldChecksum, 0, oldChecksum.length );
95
96
97 encryptedData = removeTrailingBytes( encryptedData, 0, getChecksumLength() );
98
99
100 byte[] decryptedData = decrypt( encryptedData, Ke );
101
102
103 byte[] withoutConfounder = removeLeadingBytes( decryptedData, getConfounderLength(), 0 );
104
105
106 byte[] newChecksum = calculateIntegrity( decryptedData, key.getKeyValue(), usage );
107
108
109 if ( !Arrays.equals( oldChecksum, newChecksum ) )
110 {
111 throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY );
112 }
113
114 return withoutConfounder;
115 }
116
117
118 public EncryptedData getEncryptedData( EncryptionKey key, byte[] plainText, KeyUsage usage )
119 {
120 byte[] Ke = deriveKey( key.getKeyValue(), getUsageKe( usage ), 128, getKeyLength() );
121
122
123 byte[] conFounder = getRandomBytes( getConfounderLength() );
124 byte[] dataBytes = concatenateBytes( conFounder, plainText );
125
126 byte[] checksumBytes = calculateIntegrity( dataBytes, key.getKeyValue(), usage );
127
128 byte[] encryptedData = encrypt( dataBytes, Ke );
129 byte[] cipherText = concatenateBytes( encryptedData, checksumBytes );
130
131 return new EncryptedData( getEncryptionType(), key.getKeyVersion(), cipherText );
132 }
133
134
135 public byte[] encrypt( byte[] plainText, byte[] keyBytes )
136 {
137 return processCipher( true, plainText, keyBytes );
138 }
139
140
141 public byte[] decrypt( byte[] cipherText, byte[] keyBytes )
142 {
143 return processCipher( false, cipherText, keyBytes );
144 }
145
146
147 protected byte[] deriveKey( byte[] baseKey, byte[] usage, int n, int k )
148 {
149 return deriveRandom( baseKey, usage, n, k );
150 }
151
152
153 private byte[] processChecksum( byte[] data, byte[] key )
154 {
155 try
156 {
157 SecretKey sk = new SecretKeySpec( key, "AES" );
158
159 Mac mac = Mac.getInstance( "HmacSHA1" );
160 mac.init( sk );
161
162 return mac.doFinal( data );
163 }
164 catch ( GeneralSecurityException nsae )
165 {
166 nsae.printStackTrace();
167 return null;
168 }
169 }
170
171
172 private byte[] processCipher( boolean isEncrypt, byte[] data, byte[] keyBytes )
173 {
174 try
175 {
176 Cipher cipher = Cipher.getInstance( "AES/CTS/NoPadding" );
177 SecretKey key = new SecretKeySpec( keyBytes, "AES" );
178
179 AlgorithmParameterSpec paramSpec = new IvParameterSpec( iv );
180
181 if ( isEncrypt )
182 {
183 cipher.init( Cipher.ENCRYPT_MODE, key, paramSpec );
184 }
185 else
186 {
187 cipher.init( Cipher.DECRYPT_MODE, key, paramSpec );
188 }
189
190 return cipher.doFinal( data );
191 }
192 catch ( GeneralSecurityException nsae )
193 {
194 nsae.printStackTrace();
195 return null;
196 }
197 }
198 }