1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.kerberos.shared.crypto.encryption;
21  
22  
23  import java.text.ParseException;
24  import java.text.SimpleDateFormat;
25  import java.util.Date;
26  import java.util.TimeZone;
27  
28  import javax.security.auth.kerberos.KerberosKey;
29  import javax.security.auth.kerberos.KerberosPrincipal;
30  
31  import junit.framework.TestCase;
32  
33  import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
34  import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
35  import org.apache.directory.server.kerberos.shared.messages.value.EncryptedTimeStamp;
36  import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
37  import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
38  
39  
40  /**
41   * Test case for sealing and unsealing Kerberos CipherText.
42   * 
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   * @version $Rev$, $Date$
45   */
46  public class CipherTextHandlerTest extends TestCase
47  {
48      private byte[] desEncryptedTimeStamp =
49          { ( byte ) 0x97, ( byte ) 0x21, ( byte ) 0x58, ( byte ) 0x5f, ( byte ) 0x81, ( byte ) 0x46, ( byte ) 0x17,
50              ( byte ) 0xa6, ( byte ) 0x4e, ( byte ) 0x8a, ( byte ) 0x5d, ( byte ) 0xe2, ( byte ) 0xf3, ( byte ) 0xd1,
51              ( byte ) 0x40, ( byte ) 0x30, ( byte ) 0x38, ( byte ) 0x5e, ( byte ) 0xb8, ( byte ) 0xf6, ( byte ) 0xad,
52              ( byte ) 0xd8, ( byte ) 0x7c, ( byte ) 0x30, ( byte ) 0xb0, ( byte ) 0x0d, ( byte ) 0x69, ( byte ) 0x71,
53              ( byte ) 0x08, ( byte ) 0xd5, ( byte ) 0x6a, ( byte ) 0x61, ( byte ) 0x1f, ( byte ) 0xee, ( byte ) 0x38,
54              ( byte ) 0xad, ( byte ) 0x43, ( byte ) 0x99, ( byte ) 0xae, ( byte ) 0xc2, ( byte ) 0xd2, ( byte ) 0xf5,
55              ( byte ) 0xb2, ( byte ) 0xb7, ( byte ) 0x95, ( byte ) 0x22, ( byte ) 0x93, ( byte ) 0x12, ( byte ) 0x63,
56              ( byte ) 0xd5, ( byte ) 0xf4, ( byte ) 0x39, ( byte ) 0xfa, ( byte ) 0x27, ( byte ) 0x6e, ( byte ) 0x8e };
57  
58      private byte[] tripleDesEncryptedTimeStamp =
59          { ( byte ) 0x96, ( byte ) 0xcb, ( byte ) 0x38, ( byte ) 0xb3, ( byte ) 0xc9, ( byte ) 0xb5, ( byte ) 0x78,
60              ( byte ) 0x17, ( byte ) 0xba, ( byte ) 0x0a, ( byte ) 0x64, ( byte ) 0x49, ( byte ) 0x18, ( byte ) 0x39,
61              ( byte ) 0x57, ( byte ) 0x1e, ( byte ) 0xcf, ( byte ) 0xfc, ( byte ) 0x6e, ( byte ) 0x0f, ( byte ) 0x53,
62              ( byte ) 0xe2, ( byte ) 0x9c, ( byte ) 0x96, ( byte ) 0xfd, ( byte ) 0xbc, ( byte ) 0xc6, ( byte ) 0x1e,
63              ( byte ) 0x10, ( byte ) 0x35, ( byte ) 0xe0, ( byte ) 0x8f, ( byte ) 0xc1, ( byte ) 0x7f, ( byte ) 0xbd,
64              ( byte ) 0x86, ( byte ) 0x55, ( byte ) 0xf2, ( byte ) 0x22, ( byte ) 0x48, ( byte ) 0x86, ( byte ) 0xfb,
65              ( byte ) 0x92, ( byte ) 0x22, ( byte ) 0xe7, ( byte ) 0xbe, ( byte ) 0xd1, ( byte ) 0xec, ( byte ) 0x2e,
66              ( byte ) 0x37, ( byte ) 0xd8, ( byte ) 0x47, ( byte ) 0x1e, ( byte ) 0xa0, ( byte ) 0x16, ( byte ) 0x70,
67              ( byte ) 0x5f, ( byte ) 0x6b, ( byte ) 0x18, ( byte ) 0xf3 };
68  
69      private byte[] aes128EncryptedTimeStamp =
70          { ( byte ) 0x4f, ( byte ) 0x1e, ( byte ) 0x52, ( byte ) 0xf5, ( byte ) 0xe0, ( byte ) 0xee, ( byte ) 0xe5,
71              ( byte ) 0xe2, ( byte ) 0x2c, ( byte ) 0x9b, ( byte ) 0xf4, ( byte ) 0xdc, ( byte ) 0x58, ( byte ) 0x5f,
72              ( byte ) 0x00, ( byte ) 0x96, ( byte ) 0x31, ( byte ) 0xfe, ( byte ) 0xc7, ( byte ) 0xf7, ( byte ) 0x89,
73              ( byte ) 0x38, ( byte ) 0x88, ( byte ) 0xf5, ( byte ) 0x25, ( byte ) 0xaf, ( byte ) 0x09, ( byte ) 0x9f,
74              ( byte ) 0xfd, ( byte ) 0x78, ( byte ) 0x68, ( byte ) 0x3b, ( byte ) 0xb4, ( byte ) 0x1e, ( byte ) 0xc2,
75              ( byte ) 0xfc, ( byte ) 0x2d, ( byte ) 0xf3, ( byte ) 0x41, ( byte ) 0x88, ( byte ) 0x92, ( byte ) 0x7e,
76              ( byte ) 0xd7, ( byte ) 0xed, ( byte ) 0xe1, ( byte ) 0xe0, ( byte ) 0x0c, ( byte ) 0xad, ( byte ) 0xe5,
77              ( byte ) 0x06, ( byte ) 0xbf, ( byte ) 0x30, ( byte ) 0x1e, ( byte ) 0xbf, ( byte ) 0xf2, ( byte ) 0xec };
78  
79      private byte[] aes256EncryptedTimeStamp =
80          { ( byte ) 0xa8, ( byte ) 0x40, ( byte ) 0x73, ( byte ) 0xfc, ( byte ) 0xe5, ( byte ) 0x45, ( byte ) 0x66,
81              ( byte ) 0xd6, ( byte ) 0x83, ( byte ) 0xb4, ( byte ) 0xed, ( byte ) 0xb6, ( byte ) 0x18, ( byte ) 0x5a,
82              ( byte ) 0xd2, ( byte ) 0x24, ( byte ) 0xd6, ( byte ) 0xef, ( byte ) 0x38, ( byte ) 0xac, ( byte ) 0xdf,
83              ( byte ) 0xcd, ( byte ) 0xed, ( byte ) 0x6d, ( byte ) 0x32, ( byte ) 0xf6, ( byte ) 0x00, ( byte ) 0xd1,
84              ( byte ) 0xc0, ( byte ) 0xb0, ( byte ) 0x1e, ( byte ) 0x70, ( byte ) 0x13, ( byte ) 0x48, ( byte ) 0x0a,
85              ( byte ) 0x5a, ( byte ) 0xbb, ( byte ) 0xd2, ( byte ) 0x2a, ( byte ) 0x6b, ( byte ) 0x16, ( byte ) 0x29,
86              ( byte ) 0x63, ( byte ) 0xba, ( byte ) 0xea, ( byte ) 0xb7, ( byte ) 0x1a, ( byte ) 0x90, ( byte ) 0x7b,
87              ( byte ) 0xf4, ( byte ) 0x89, ( byte ) 0x94, ( byte ) 0x7a, ( byte ) 0x2d, ( byte ) 0x6a, ( byte ) 0xf1 };
88  
89      private byte[] arcfourEncryptedTimeStamp =
90          { ( byte ) 0xa2, ( byte ) 0x4f, ( byte ) 0x04, ( byte ) 0x6d, ( byte ) 0x93, ( byte ) 0x31, ( byte ) 0x19,
91              ( byte ) 0x77, ( byte ) 0x3f, ( byte ) 0x9d, ( byte ) 0xf9, ( byte ) 0x6f, ( byte ) 0x7e, ( byte ) 0x86,
92              ( byte ) 0x2c, ( byte ) 0x99, ( byte ) 0x63, ( byte ) 0xc5, ( byte ) 0xcf, ( byte ) 0xe2, ( byte ) 0xf1,
93              ( byte ) 0x54, ( byte ) 0x05, ( byte ) 0x6a, ( byte ) 0xea, ( byte ) 0x20, ( byte ) 0x37, ( byte ) 0x31,
94              ( byte ) 0xa2, ( byte ) 0xdc, ( byte ) 0xe8, ( byte ) 0x79, ( byte ) 0xaa, ( byte ) 0xae, ( byte ) 0x1c,
95              ( byte ) 0xfa, ( byte ) 0x93, ( byte ) 0x02, ( byte ) 0xbe, ( byte ) 0x11, ( byte ) 0x14, ( byte ) 0x22,
96              ( byte ) 0x65, ( byte ) 0x92, ( byte ) 0xbd, ( byte ) 0xf5, ( byte ) 0x52, ( byte ) 0x9f, ( byte ) 0x94,
97              ( byte ) 0x67, ( byte ) 0x10, ( byte ) 0xd2 };
98  
99      private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
100 
101     private static final SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyyMMddHHmmss'Z'" );
102 
103     static
104     {
105         dateFormat.setTimeZone( UTC_TIME_ZONE );
106     }
107 
108 
109     /**
110      * Tests the lengths of the test vectors for encrypted timestamps for each
111      * of the supported encryption types.  The length of the Kerberos Cipher Text
112      * is relevant to the structure of the underlying plaintext.
113      */
114     public void testTestVectorLengths()
115     {
116         assertEquals( "DES length", 56, desEncryptedTimeStamp.length );
117         assertEquals( "DES3 length", 60, tripleDesEncryptedTimeStamp.length );
118         assertEquals( "AES128 length", 56, aes128EncryptedTimeStamp.length );
119         assertEquals( "AES256 length", 56, aes256EncryptedTimeStamp.length );
120         assertEquals( "RC4-HMAC length", 52, arcfourEncryptedTimeStamp.length );
121     }
122 
123 
124     /**
125      * Tests the unsealing of Kerberos CipherText with a good password.  After decryption and
126      * an integrity check, an attempt is made to decode the bytes as an EncryptedTimestamp.  The
127      * result is timestamp data.
128      */
129     public void testDesGoodPasswordDecrypt()
130     {
131         CipherTextHandler lockBox = new CipherTextHandler();
132         Class hint = EncryptedTimeStamp.class;
133         KerberosPrincipal principal = new KerberosPrincipal( "erodriguez@EXAMPLE.COM" );
134         KerberosKey kerberosKey = new KerberosKey( principal, "kerby".toCharArray(), "DES" );
135         EncryptionKey key = new EncryptionKey( EncryptionType.DES_CBC_MD5, kerberosKey.getEncoded() );
136         EncryptedData data = new EncryptedData( EncryptionType.DES_CBC_MD5, 0, desEncryptedTimeStamp );
137 
138         try
139         {
140             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, data, KeyUsage.NUMBER1 );
141             assertEquals( "TimeStamp", "20070322233107Z", object.getTimeStamp().toString() );
142             assertEquals( "MicroSeconds", 291067, object.getMicroSeconds() );
143         }
144         catch ( KerberosException ke )
145         {
146             fail( "Should not have caught exception." );
147         }
148     }
149 
150 
151     /**
152      * Tests the unsealing of Kerberos CipherText with a bad password.  After decryption, the
153      * checksum is tested and should fail on comparison, resulting in an integrity check error.
154      */
155     public void testDesBadPasswordDecrypt()
156     {
157         CipherTextHandler lockBox = new CipherTextHandler();
158         Class hint = EncryptedTimeStamp.class;
159         KerberosPrincipal principal = new KerberosPrincipal( "erodriguez@EXAMPLE.COM" );
160         KerberosKey kerberosKey = new KerberosKey( principal, "badpassword".toCharArray(), "DES" );
161         EncryptionKey key = new EncryptionKey( EncryptionType.DES_CBC_MD5, kerberosKey.getEncoded() );
162         EncryptedData data = new EncryptedData( EncryptionType.DES_CBC_MD5, 0, desEncryptedTimeStamp );
163 
164         try
165         {
166             lockBox.unseal( hint, key, data, KeyUsage.NUMBER1 );
167             fail( "Should have thrown exception." );
168         }
169         catch ( KerberosException ke )
170         {
171             assertEquals( "ErrorCode", 31, ke.getErrorCode() );
172         }
173     }
174 
175 
176     /**
177      * Tests the unsealing of Kerberos CipherText with a good password.  After decryption and
178      * an integrity check, an attempt is made to decode the bytes as an EncryptedTimestamp.  The
179      * result is timestamp data.
180      */
181     public void testTripleDesGoodPasswordDecrypt()
182     {
183         CipherTextHandler lockBox = new CipherTextHandler();
184         Class hint = EncryptedTimeStamp.class;
185         KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
186         String algorithm = VendorHelper.getTripleDesAlgorithm();
187         KerberosKey kerberosKey = new KerberosKey( principal, "secret".toCharArray(), algorithm );
188         EncryptionKey key = new EncryptionKey( EncryptionType.DES3_CBC_SHA1_KD, kerberosKey.getEncoded() );
189         EncryptedData data = new EncryptedData( EncryptionType.DES3_CBC_SHA1_KD, 0, tripleDesEncryptedTimeStamp );
190 
191         try
192         {
193             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, data, KeyUsage.NUMBER1 );
194             assertEquals( "TimeStamp", "20070410190400Z", object.getTimeStamp().toString() );
195             assertEquals( "MicroSeconds", 460450, object.getMicroSeconds() );
196         }
197         catch ( KerberosException ke )
198         {
199             fail( "Should not have caught exception." );
200         }
201     }
202 
203 
204     /**
205      * Tests the encryption and subsequent unsealing of an ASN.1 encoded timestamp with a
206      * good password.  After encryption, an attempt is made to unseal the encrypted bytes
207      * as an EncryptedTimestamp.  The result is timestamp data.
208      * 
209      * @throws ParseException 
210      */
211     public void testTripleDesGoodPasswordEncrypt() throws ParseException
212     {
213         CipherTextHandler lockBox = new CipherTextHandler();
214         KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
215         String algorithm = VendorHelper.getTripleDesAlgorithm();
216         KerberosKey kerberosKey = new KerberosKey( principal, "secret".toCharArray(), algorithm );
217         EncryptionKey key = new EncryptionKey( EncryptionType.DES3_CBC_SHA1_KD, kerberosKey.getEncoded() );
218 
219         String zuluTime = "20070410190400Z";
220         int microSeconds = 460450;
221         EncryptedTimeStamp encryptedTimeStamp = getEncryptedTimeStamp( zuluTime, microSeconds );
222 
223         EncryptedData encryptedData = null;
224 
225         try
226         {
227             encryptedData = lockBox.seal( key, encryptedTimeStamp, KeyUsage.NUMBER1 );
228         }
229         catch ( KerberosException ke )
230         {
231             fail( "Should not have caught exception." );
232         }
233 
234         Class hint = EncryptedTimeStamp.class;
235 
236         try
237         {
238             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, encryptedData,
239                 KeyUsage.NUMBER1 );
240             assertEquals( "TimeStamp", zuluTime, object.getTimeStamp().toString() );
241             assertEquals( "MicroSeconds", microSeconds, object.getMicroSeconds() );
242         }
243         catch ( KerberosException ke )
244         {
245             fail( "Should not have caught exception." );
246         }
247     }
248 
249 
250     /**
251      * Tests the unsealing of Kerberos CipherText with a good password.  After decryption and
252      * an integrity check, an attempt is made to decode the bytes as an EncryptedTimestamp.  The
253      * result is timestamp data.
254      */
255     public void testAes128GoodPasswordDecrypt()
256     {
257         if ( !VendorHelper.isCtsSupported() )
258         {
259             return;
260         }
261 
262         CipherTextHandler lockBox = new CipherTextHandler();
263         Class hint = EncryptedTimeStamp.class;
264         KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
265         KerberosKey kerberosKey = new KerberosKey( principal, "secret".toCharArray(), "AES128" );
266         EncryptionKey key = new EncryptionKey( EncryptionType.AES128_CTS_HMAC_SHA1_96, kerberosKey.getEncoded() );
267         EncryptedData data = new EncryptedData( EncryptionType.AES128_CTS_HMAC_SHA1_96, 0, aes128EncryptedTimeStamp );
268 
269         try
270         {
271             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, data, KeyUsage.NUMBER1 );
272             assertEquals( "TimeStamp", "20070410212557Z", object.getTimeStamp().toString() );
273             assertEquals( "MicroSeconds", 379386, object.getMicroSeconds() );
274         }
275         catch ( KerberosException ke )
276         {
277             fail( "Should not have caught exception." );
278         }
279     }
280 
281 
282     /**
283      * Tests the encryption and subsequent unsealing of an ASN.1 encoded timestamp with a
284      * good password.  After encryption, an attempt is made to unseal the encrypted bytes
285      * as an EncryptedTimestamp.  The result is timestamp data.
286      * 
287      * @throws ParseException 
288      */
289     public void testAes128GoodPasswordEncrypt() throws ParseException
290     {
291         if ( !VendorHelper.isCtsSupported() )
292         {
293             return;
294         }
295 
296         CipherTextHandler lockBox = new CipherTextHandler();
297         KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
298         KerberosKey kerberosKey = new KerberosKey( principal, "secret".toCharArray(), "AES128" );
299         EncryptionKey key = new EncryptionKey( EncryptionType.AES128_CTS_HMAC_SHA1_96, kerberosKey.getEncoded() );
300 
301         String zuluTime = "20070410190400Z";
302         int microSeconds = 460450;
303         EncryptedTimeStamp encryptedTimeStamp = getEncryptedTimeStamp( zuluTime, microSeconds );
304 
305         EncryptedData encryptedData = null;
306 
307         try
308         {
309             encryptedData = lockBox.seal( key, encryptedTimeStamp, KeyUsage.NUMBER1 );
310         }
311         catch ( KerberosException ke )
312         {
313             fail( "Should not have caught exception." );
314         }
315 
316         Class hint = EncryptedTimeStamp.class;
317 
318         try
319         {
320             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, encryptedData,
321                 KeyUsage.NUMBER1 );
322             assertEquals( "TimeStamp", "20070410190400Z", object.getTimeStamp().toString() );
323             assertEquals( "MicroSeconds", 460450, object.getMicroSeconds() );
324         }
325         catch ( KerberosException ke )
326         {
327             fail( "Should not have caught exception." );
328         }
329     }
330 
331 
332     /**
333      * Tests the unsealing of Kerberos CipherText with a good password.  After decryption and
334      * an integrity check, an attempt is made to decode the bytes as an EncryptedTimestamp.  The
335      * result is timestamp data.
336      */
337     public void testAes256GoodPasswordDecrypt()
338     {
339         if ( !VendorHelper.isCtsSupported() )
340         {
341             return;
342         }
343 
344         CipherTextHandler lockBox = new CipherTextHandler();
345         Class hint = EncryptedTimeStamp.class;
346 
347         KerberosKey kerberosKey;
348 
349         try
350         {
351             KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
352             kerberosKey = new KerberosKey( principal, "secret".toCharArray(), "AES256" );
353         }
354         catch ( IllegalArgumentException iae )
355         {
356             // Algorithm AES256 not enabled
357             return;
358         }
359 
360         EncryptionKey key = new EncryptionKey( EncryptionType.AES256_CTS_HMAC_SHA1_96, kerberosKey.getEncoded() );
361         EncryptedData data = new EncryptedData( EncryptionType.AES256_CTS_HMAC_SHA1_96, 0, aes256EncryptedTimeStamp );
362 
363         try
364         {
365             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, data, KeyUsage.NUMBER1 );
366             assertEquals( "TimeStamp", "20070410212809Z", object.getTimeStamp().toString() );
367             assertEquals( "MicroSeconds", 298294, object.getMicroSeconds() );
368         }
369         catch ( KerberosException ke )
370         {
371             fail( "Should not have caught exception." );
372         }
373     }
374 
375 
376     /**
377      * Tests the encryption and subsequent unsealing of an ASN.1 encoded timestamp with a
378      * good password.  After encryption, an attempt is made to unseal the encrypted bytes
379      * as an EncryptedTimestamp.  The result is timestamp data.
380      * 
381      * @throws ParseException 
382      */
383     public void testAes256GoodPasswordEncrypt() throws ParseException
384     {
385         if ( !VendorHelper.isCtsSupported() )
386         {
387             return;
388         }
389 
390         CipherTextHandler lockBox = new CipherTextHandler();
391 
392         KerberosKey kerberosKey;
393 
394         try
395         {
396             KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
397             kerberosKey = new KerberosKey( principal, "secret".toCharArray(), "AES256" );
398         }
399         catch ( IllegalArgumentException iae )
400         {
401             // Algorithm AES256 not enabled
402             return;
403         }
404 
405         EncryptionKey key = new EncryptionKey( EncryptionType.AES256_CTS_HMAC_SHA1_96, kerberosKey.getEncoded() );
406 
407         String zuluTime = "20070410190400Z";
408         int microSeconds = 460450;
409         EncryptedTimeStamp encryptedTimeStamp = getEncryptedTimeStamp( zuluTime, microSeconds );
410 
411         EncryptedData encryptedData = null;
412 
413         try
414         {
415             encryptedData = lockBox.seal( key, encryptedTimeStamp, KeyUsage.NUMBER1 );
416         }
417         catch ( KerberosException ke )
418         {
419             fail( "Should not have caught exception." );
420         }
421 
422         Class hint = EncryptedTimeStamp.class;
423 
424         try
425         {
426             EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, encryptedData,
427                 KeyUsage.NUMBER1 );
428             assertEquals( "TimeStamp", "20070410190400Z", object.getTimeStamp().toString() );
429             assertEquals( "MicroSeconds", 460450, object.getMicroSeconds() );
430         }
431         catch ( KerberosException ke )
432         {
433             fail( "Should not have caught exception." );
434         }
435     }
436 
437 
438     protected EncryptedTimeStamp getEncryptedTimeStamp( String zuluTime, int microSeconds ) throws ParseException
439     {
440         Date date = null;
441         synchronized ( dateFormat )
442         {
443             date = dateFormat.parse( zuluTime );
444         }
445 
446         KerberosTime timeStamp = new KerberosTime( date );
447 
448         return new EncryptedTimeStamp( timeStamp, microSeconds );
449     }
450 
451     /*
452      public void testArcFourGoodPassword()
453      {
454      LockBox lockBox = new LockBox();
455      Class hint = EncryptedTimeStamp.class;
456      KerberosPrincipal principal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
457      KerberosKey kerberosKey = new KerberosKey( principal, "secret".toCharArray(), "ArcFourHmac" );
458      EncryptionKey key = new EncryptionKey( EncryptionType.RC4_HMAC, kerberosKey.getEncoded() );
459      EncryptedData data = new EncryptedData( EncryptionType.RC4_HMAC, 0, arcfourEncryptedTimeStamp );
460 
461      try
462      {
463      EncryptedTimeStamp object = ( EncryptedTimeStamp ) lockBox.unseal( hint, key, data );
464      assertEquals( "TimeStamp", "20070322233107Z", object.getTimeStamp().toString() );
465      assertEquals( "MicroSeconds", 291067, object.getMicroSeconds() );
466      }
467      catch ( KerberosException ke )
468      {
469      fail( "Should not have caught exception." );
470      }
471      }*/
472 }