1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.directory.server.kerberos.shared.crypto.encryption;
22
23
24 import java.security.GeneralSecurityException;
25 import java.security.spec.AlgorithmParameterSpec;
26 import java.util.Arrays;
27 import java.util.zip.CRC32;
28
29 import javax.crypto.Cipher;
30 import javax.crypto.SecretKey;
31 import javax.crypto.spec.IvParameterSpec;
32 import javax.crypto.spec.SecretKeySpec;
33
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 public class DesCbcCrcEncryption extends EncryptionEngine
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 };
49
50
51 public EncryptionType getEncryptionType()
52 {
53 return EncryptionType.DES_CBC_CRC;
54 }
55
56
57 public int getConfounderLength()
58 {
59 return 8;
60 }
61
62
63 public int getChecksumLength()
64 {
65 return 4;
66 }
67
68
69 public byte[] calculateIntegrity( byte[] data, byte[] key, KeyUsage usage )
70 {
71 CRC32 crc32 = new CRC32();
72 crc32.update( data );
73
74 return int2octet( ( int ) crc32.getValue() );
75 }
76
77
78 private byte[] int2octet( int value )
79 {
80 byte[] bytes = new byte[4];
81 int i, shift;
82
83 for ( i = 0, shift = 24; i < 4; i++, shift -= 8 )
84 {
85 bytes[i] = ( byte ) ( 0xFF & ( value >> shift ) );
86 }
87
88 return bytes;
89 }
90
91
92 public byte[] getDecryptedData( EncryptionKey key, EncryptedData data, KeyUsage usage ) throws KerberosException
93 {
94
95 byte[] decryptedData = decrypt( data.getCipher(), key.getKeyValue() );
96
97
98 byte[] oldChecksum = new byte[getChecksumLength()];
99 System.arraycopy( decryptedData, getConfounderLength(), oldChecksum, 0, oldChecksum.length );
100
101
102 for ( int i = getConfounderLength(); i < getConfounderLength() + getChecksumLength(); i++ )
103 {
104 decryptedData[i] = 0;
105 }
106
107
108 byte[] newChecksum = calculateIntegrity( decryptedData, key.getKeyValue(), usage );
109
110
111 if ( !Arrays.equals( oldChecksum, newChecksum ) )
112 {
113 throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY );
114 }
115
116
117 return removeLeadingBytes( decryptedData, getConfounderLength(), getChecksumLength() );
118 }
119
120
121 public EncryptedData getEncryptedData( EncryptionKey key, byte[] plainText, KeyUsage usage )
122 {
123
124 byte[] conFounder = getRandomBytes( getConfounderLength() );
125 byte[] zeroedChecksum = new byte[getChecksumLength()];
126 byte[] dataBytes = concatenateBytes( conFounder, concatenateBytes( zeroedChecksum, plainText ) );
127 byte[] paddedDataBytes = padString( dataBytes );
128 byte[] checksumBytes = calculateIntegrity( paddedDataBytes, null, usage );
129
130
131 for ( int i = getConfounderLength(); i < getConfounderLength() + getChecksumLength(); i++ )
132 {
133 paddedDataBytes[i] = checksumBytes[i - getConfounderLength()];
134 }
135
136 byte[] encryptedData = encrypt( paddedDataBytes, key.getKeyValue() );
137
138 return new EncryptedData( getEncryptionType(), key.getKeyVersion(), encryptedData );
139 }
140
141
142 public byte[] encrypt( byte[] plainText, byte[] keyBytes )
143 {
144 return processCipher( true, plainText, keyBytes );
145 }
146
147
148 public byte[] decrypt( byte[] cipherText, byte[] keyBytes )
149 {
150 return processCipher( false, cipherText, keyBytes );
151 }
152
153
154 private byte[] processCipher( boolean isEncrypt, byte[] data, byte[] keyBytes )
155 {
156 try
157 {
158 Cipher cipher = Cipher.getInstance( "DES/CBC/NoPadding" );
159 SecretKey key = new SecretKeySpec( keyBytes, "DES" );
160
161 AlgorithmParameterSpec paramSpec = new IvParameterSpec( iv );
162
163 if ( isEncrypt )
164 {
165 cipher.init( Cipher.ENCRYPT_MODE, key, paramSpec );
166 }
167 else
168 {
169 cipher.init( Cipher.DECRYPT_MODE, key, paramSpec );
170 }
171
172 return cipher.doFinal( data );
173 }
174 catch ( GeneralSecurityException nsae )
175 {
176 nsae.printStackTrace();
177 return null;
178 }
179 }
180 }