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.NoSuchAlgorithmException;
26 import java.security.spec.AlgorithmParameterSpec;
27 import java.util.Arrays;
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 import org.apache.directory.shared.ldap.constants.LdapSecurityConstants;
39
40
41
42
43
44
45 class DesCbcMd5Encryption extends EncryptionEngine
46 {
47 private static final byte[] iv = new byte[]
48 { ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
49 ( byte ) 0x00 };
50
51
52 public EncryptionType getEncryptionType()
53 {
54 return EncryptionType.DES_CBC_MD5;
55 }
56
57
58 public int getConfounderLength()
59 {
60 return 8;
61 }
62
63
64 public int getChecksumLength()
65 {
66 return 16;
67 }
68
69
70 public byte[] calculateIntegrity( byte[] data, byte[] key, KeyUsage usage )
71 {
72 try
73 {
74 MessageDigest digester = MessageDigest.getInstance( LdapSecurityConstants.HASH_METHOD_MD5.getName() );
75 return digester.digest( data );
76 }
77 catch ( NoSuchAlgorithmException nsae )
78 {
79 return null;
80 }
81 }
82
83
84 public byte[] getDecryptedData( EncryptionKey key, EncryptedData data, KeyUsage usage ) throws KerberosException
85 {
86
87 byte[] decryptedData = decrypt( data.getCipher(), key.getKeyValue() );
88
89
90 byte[] oldChecksum = new byte[getChecksumLength()];
91 System.arraycopy( decryptedData, getConfounderLength(), oldChecksum, 0, oldChecksum.length );
92
93
94 for ( int i = getConfounderLength(); i < getConfounderLength() + getChecksumLength(); i++ )
95 {
96 decryptedData[i] = 0;
97 }
98
99
100 byte[] newChecksum = calculateIntegrity( decryptedData, key.getKeyValue(), usage );
101
102
103 if ( !Arrays.equals( oldChecksum, newChecksum ) )
104 {
105 throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY );
106 }
107
108
109 return removeLeadingBytes( decryptedData, getConfounderLength(), getChecksumLength() );
110 }
111
112
113 public EncryptedData getEncryptedData( EncryptionKey key, byte[] plainText, KeyUsage usage )
114 {
115
116 byte[] conFounder = getRandomBytes( getConfounderLength() );
117 byte[] zeroedChecksum = new byte[getChecksumLength()];
118 byte[] dataBytes = concatenateBytes( conFounder, concatenateBytes( zeroedChecksum, plainText ) );
119 byte[] paddedDataBytes = padString( dataBytes );
120 byte[] checksumBytes = calculateIntegrity( paddedDataBytes, null, usage );
121
122
123 for ( int i = getConfounderLength(); i < getConfounderLength() + getChecksumLength(); i++ )
124 {
125 paddedDataBytes[i] = checksumBytes[i - getConfounderLength()];
126 }
127
128 byte[] encryptedData = encrypt( paddedDataBytes, key.getKeyValue() );
129
130 return new EncryptedData( getEncryptionType(), key.getKeyVersion(), encryptedData );
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 private byte[] processCipher( boolean isEncrypt, byte[] data, byte[] keyBytes )
147 {
148 try
149 {
150 Cipher cipher = Cipher.getInstance( "DES/CBC/NoPadding" );
151 SecretKey key = new SecretKeySpec( keyBytes, "DES" );
152
153 AlgorithmParameterSpec paramSpec = new IvParameterSpec( iv );
154
155 if ( isEncrypt )
156 {
157 cipher.init( Cipher.ENCRYPT_MODE, key, paramSpec );
158 }
159 else
160 {
161 cipher.init( Cipher.DECRYPT_MODE, key, paramSpec );
162 }
163
164 return cipher.doFinal( data );
165 }
166 catch ( GeneralSecurityException nsae )
167 {
168 nsae.printStackTrace();
169 return null;
170 }
171 }
172 }