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