1 /*
  2  * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 /*
 24  * @test
 25  * @bug 6862679
 26  * @modules java.security.jgss/sun.security.krb5
 27  *          java.security.jgss/sun.security.krb5.internal.crypto
 28  *          java.security.jgss/sun.security.krb5.internal.crypto.dk:+open
 29  * @run main/othervm RFC396xTest
 30  * @summary ESC: AD Authentication with user with umlauts fails
 31  */
 32 
 33 import java.lang.reflect.Array;
 34 import java.lang.reflect.Method;
 35 import sun.security.krb5.EncryptedData;
 36 import sun.security.krb5.internal.crypto.Des;
 37 import sun.security.krb5.internal.crypto.EType;
 38 import sun.security.krb5.internal.crypto.crc32;
 39 import sun.security.krb5.internal.crypto.dk.AesDkCrypto;
 40 import sun.security.krb5.internal.crypto.dk.Des3DkCrypto;
 41 import sun.security.krb5.internal.crypto.dk.DkCrypto;
 42 import java.nio.*;
 43 import java.util.Hex;
 44 import javax.crypto.*;
 45 import javax.crypto.spec.*;
 46 
 47 public class RFC396xTest {
 48 
 49     static final String gclef = new String(Character.toChars(0x1d11e));
 50 
 51     /** Creates a new instance of NewClass */
 52     public static void main(String[] args) throws Exception {
 53         System.setProperty("sun.security.krb5.msinterop.des.s2kcharset",
 54                 "utf-8");
 55         test();
 56     }
 57 
 58     static void test() throws Exception {
 59         // RFC 3961
 60         // A.1
 61         Method nfold = DkCrypto.class.getDeclaredMethod("nfold", byte[].class, Integer.TYPE);
 62         nfold.setAccessible(true);
 63         assertStringEquals(hex((byte[])nfold.invoke(null, "012345".getBytes("UTF-8"), 64)), "be072631276b1955");
 64         assertStringEquals(hex((byte[])nfold.invoke(null, "password".getBytes("UTF-8"), 56)), "78a07b6caf85fa");
 65         assertStringEquals(hex((byte[])nfold.invoke(null, "Rough Consensus, and Running Code".getBytes("UTF-8"), 64)), "bb6ed30870b7f0e0");
 66         assertStringEquals(hex((byte[])nfold.invoke(null, "password".getBytes("UTF-8"), 168)), "59e4a8ca7c0385c3c37b3f6d2000247cb6e6bd5b3e");
 67         assertStringEquals(hex((byte[])nfold.invoke(null, "MASSACHVSETTS INSTITVTE OF TECHNOLOGY".getBytes("UTF-8"), 192)), "db3b0d8f0b061e603282b308a50841229ad798fab9540c1b");
 68         assertStringEquals(hex((byte[])nfold.invoke(null, "Q".getBytes("UTF-8"), 168)), "518a54a215a8452a518a54a215a8452a518a54a215");
 69         assertStringEquals(hex((byte[])nfold.invoke(null, "ba".getBytes("UTF-8"), 168)), "fb25d531ae8974499f52fd92ea9857c4ba24cf297e");
 70         assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 64)), "6b65726265726f73");
 71         assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 128)), "6b65726265726f737b9b5b2b93132b93");
 72         assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 168)), "8372c236344e5f1550cd0747e15d62ca7a5a3bcea4");
 73         assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 256)), "6b65726265726f737b9b5b2b93132b935c9bdcdad95c9899c4cae4dee6d6cae4");
 74 
 75         // A.2
 76         assertStringEquals(hex(Des.string_to_key_bytes("passwordATHENA.MIT.EDUraeburn".toCharArray())), "cbc22fae235298e3");
 77         assertStringEquals(hex(Des.string_to_key_bytes("potatoeWHITEHOUSE.GOVdanny".toCharArray())), "df3d32a74fd92a01");
 78         assertStringEquals(hex(Des.string_to_key_bytes((gclef+"EXAMPLE.COMpianist").toCharArray())), "4ffb26bab0cd9413");
 79         assertStringEquals(hex(Des.string_to_key_bytes("\u00dfATHENA.MIT.EDUJuri\u0161i\u0107".toCharArray())), "62c81a5232b5e69d");
 80         // Next 2 won't pass, since there's no real weak key here
 81         //assertStringEquals(hex(Des.string_to_key_bytes("11119999AAAAAAAA".toCharArray())), "984054d0f1a73e31");
 82         //assertStringEquals(hex(Des.string_to_key_bytes("NNNN6666FFFFAAAA".toCharArray())), "c4bf6b25adf7a4f8");
 83 
 84         // A.3
 85         Object o = Des3DkCrypto.class.getConstructor().newInstance();
 86         Method dr = DkCrypto.class.getDeclaredMethod("dr", byte[].class, byte[].class);
 87         Method randomToKey = DkCrypto.class.getDeclaredMethod("randomToKey", byte[].class);
 88         dr.setAccessible(true);
 89         randomToKey.setAccessible(true);
 90         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
 91                 xeh("dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92"),
 92                 xeh("0000000155")))),
 93                 "925179d04591a79b5d3192c4a7e9c289b049c71f6ee604cd");
 94         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
 95                 xeh("5e13d31c70ef765746578531cb51c15bf11ca82c97cee9f2"),
 96                 xeh("00000001aa")))),
 97                 "9e58e5a146d9942a101c469845d67a20e3c4259ed913f207");
 98         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
 99                 xeh("98e6fd8a04a4b6859b75a176540b9752bad3ecd610a252bc"),
100                 xeh("0000000155")))),
101                 "13fef80d763e94ec6d13fd2ca1d085070249dad39808eabf");
102         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
103                 xeh("622aec25a2fe2cad7094680b7c64940280084c1a7cec92b5"),
104                 xeh("00000001aa")))),
105                 "f8dfbf04b097e6d9dc0702686bcb3489d91fd9a4516b703e");
106         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
107                 xeh("d3f8298ccb166438dcb9b93ee5a7629286a491f838f802fb"),
108                 xeh("6b65726265726f73")))),
109                 "2370da575d2a3da864cebfdc5204d56df779a7df43d9da43");
110         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
111                 xeh("c1081649ada74362e6a1459d01dfd30d67c2234c940704da"),
112                 xeh("0000000155")))),
113                 "348057ec98fdc48016161c2a4c7a943e92ae492c989175f7");
114         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
115                 xeh("5d154af238f46713155719d55e2f1f790dd661f279a7917c"),
116                 xeh("00000001aa")))),
117                 "a8808ac267dada3dcbe9a7c84626fbc761c294b01315e5c1");
118         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
119                 xeh("798562e049852f57dc8c343ba17f2ca1d97394efc8adc443"),
120                 xeh("0000000155")))),
121                 "c813f88a3be3b334f75425ce9175fbe3c8493b89c8703b49");
122         assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
123                 xeh("26dce334b545292f2feab9a8701a89a4b99eb9942cecd016"),
124                 xeh("00000001aa")))),
125                 "f48ffd6e83f83e7354e694fd252cf83bfe58f7d5ba37ec5d");
126 
127         // A.4
128         assertStringEquals(hex(new Des3DkCrypto().stringToKey("passwordATHENA.MIT.EDUraeburn".toCharArray())), "850bb51358548cd05e86768c313e3bfef7511937dcf72c3e");
129         assertStringEquals(hex(new Des3DkCrypto().stringToKey("potatoeWHITEHOUSE.GOVdanny".toCharArray())), "dfcd233dd0a43204ea6dc437fb15e061b02979c1f74f377a");
130         assertStringEquals(hex(new Des3DkCrypto().stringToKey("pennyEXAMPLE.COMbuckaroo".toCharArray())), "6d2fcdf2d6fbbc3ddcadb5da5710a23489b0d3b69d5d9d4a");
131         assertStringEquals(hex(new Des3DkCrypto().stringToKey("\u00DFATHENA.MIT.EDUJuri\u0161i\u0107".toCharArray())), "16d5a40e1ce3bacb61b9dce00470324c831973a7b952feb0");
132         assertStringEquals(hex(new Des3DkCrypto().stringToKey((gclef+"EXAMPLE.COMpianist").toCharArray())), "85763726585dbc1cce6ec43e1f751f07f1c4cbb098f40b19");
133 
134         // A.5
135         assertStringEquals(hex(crc32.byte2crc32sum_bytes("foo".getBytes("UTF-8"))), "33bc3273");
136         assertStringEquals(hex(crc32.byte2crc32sum_bytes("test0123456789".getBytes("UTF-8"))), "d6883eb8");
137         assertStringEquals(hex(crc32.byte2crc32sum_bytes("MASSACHVSETTS INSTITVTE OF TECHNOLOGY".getBytes("UTF-8"))), "f78041e3");
138         assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {(byte)0x80, 0})), "4b98833b");
139         assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {0, 8})), "3288db0e");
140         assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {0, (byte)0x80})), "2083b8ed");
141         assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {(byte)0x80})), "2083b8ed");
142         assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {(byte)0x80, 0, 0, 0})), "3bb659ed");
143         assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {0, 0, 0, 1})), "96300777");
144 
145         // RFC 3962
146         AesDkCrypto a1 = new AesDkCrypto(128);
147         Method pbkdf2 = AesDkCrypto.class.getDeclaredMethod("PBKDF2", char[].class, byte[].class, Integer.TYPE, Integer.TYPE);
148         Method s2k = AesDkCrypto.class.getDeclaredMethod("stringToKey", char[].class, byte[].class, byte[].class);
149         pbkdf2.setAccessible(true);
150         s2k.setAccessible(true);
151         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1, 128)), "cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15");
152         assertStringEquals(hex(a1.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1))), "42 26 3c 6e 89 f4 fc 28 b8 df 68 ee 09 79 9f 15");
153         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1, 256)), "cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15  0a d1 f7 a0 4b b9 f3 a3 33 ec c0 e2 e1 f7 08 37");
154         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 2, 128)), "01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d");
155         assertStringEquals(hex(a1.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(2))), "c6 51 bf 29 e2 30 0a c2 7f a4 69 d6 93 bd da 13");
156         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 2, 256)), "01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d  a0 53 78 b9 32 44 ec 8f 48 a9 9e 61 ad 79 9d 86");
157         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1200, 128)), "5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b");
158         assertStringEquals(hex(a1.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1200))), "4c 01 cd 46 d6 32 d0 1e 6d be 23 0a 01 ed 64 2a");
159         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1200, 256)), "5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b  a7 e5 2d db c5 e5 14 2f 70 8a 31 e2 e6 2b 1e 13");
160         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), xeh("1234567878563412"), 5, 128)), "d1 da a7 86 15 f2 87 e6 a1 c8 b1 20 d7 06 2a 49");
161         assertStringEquals(hex((byte[])s2k.invoke(a1, "password".toCharArray(), xeh("1234567878563412"), i2b(5))), "e9 b2 3d 52 27 37 47 dd 5c 35 cb 55 be 61 9d 8e");
162         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), xeh("1234567878563412"), 5, 256)), "d1 da a7 86 15 f2 87 e6 a1 c8 b1 20 d7 06 2a 49  3f 98 d2 03 e6 be 49 a6 ad f4 fa 57 4b 6e 64 ee");
163         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size".getBytes("UTF-8"), 1200, 128)), "13 9c 30 c0 96 6b c3 2b a5 5f db f2 12 53 0a c9");
164         assertStringEquals(hex(a1.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size", i2b(1200))), "59 d1 bb 78 9a 82 8b 1a a5 4e f9 c2 88 3f 69 ed");
165         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size".getBytes("UTF-8"), 1200, 256)), "13 9c 30 c0 96 6b c3 2b a5 5f db f2 12 53 0a c9  c5 ec 59 f1 a4 52 f5 cc 9a d9 40 fe a0 59 8e d1");
166         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size".getBytes("UTF-8"), 1200, 128)), "9c ca d6 d4 68 77 0c d5 1b 10 e6 a6 87 21 be 61");
167         assertStringEquals(hex(a1.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size", i2b(1200))), "cb 80 05 dc 5f 90 17 9a 7f 02 10 4c 00 18 75 1d");
168         assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size".getBytes("UTF-8"), 1200, 256)), "9c ca d6 d4 68 77 0c d5 1b 10 e6 a6 87 21 be 61  1a 8b 4d 28 26 01 db 3b 36 be 92 46 91 5e c8 2a");
169         assertStringEquals(hex((byte[])pbkdf2.invoke(null, gclef.toCharArray(), "EXAMPLE.COMpianist".getBytes("UTF-8"), 50, 128)), "6b 9c f2 6d 45 45 5a 43 a5 b8 bb 27 6a 40 3b 39");
170         assertStringEquals(hex(a1.stringToKey(gclef.toCharArray(), "EXAMPLE.COMpianist", i2b(50))), "f1 49 c1 f2 e1 54 a7 34 52 d4 3e 7f e6 2a 56 e5");
171         assertStringEquals(hex((byte[])pbkdf2.invoke(null, gclef.toCharArray(), "EXAMPLE.COMpianist".getBytes("UTF-8"), 50, 256)), "6b 9c f2 6d 45 45 5a 43 a5 b8 bb 27 6a 40 3b 39  e7 fe 37 a0 c4 1e 02 c2 81 ff 30 69 e1 e9 4f 52");
172 
173         if (EType.isSupported(EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96)) {
174             AesDkCrypto a2 = new AesDkCrypto(256);
175             assertStringEquals(hex(a2.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1))), "fe 69 7b 52 bc 0d 3c e1 44 32 ba 03 6a 92 e6 5b  bb 52 28 09 90 a2 fa 27 88 39 98 d7 2a f3 01 61");
176             assertStringEquals(hex(a2.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(2))), "a2 e1 6d 16 b3 60 69 c1 35 d5 e9 d2 e2 5f 89 61  02 68 56 18 b9 59 14 b4 67 c6 76 22 22 58 24 ff");
177             assertStringEquals(hex(a2.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1200))), "55 a6 ac 74 0a d1 7b 48 46 94 10 51 e1 e8 b0 a7  54 8d 93 b0 ab 30 a8 bc 3f f1 62 80 38 2b 8c 2a");
178             assertStringEquals(hex((byte[])s2k.invoke(a2, "password".toCharArray(), xeh("1234567878563412"), i2b(5))), "97 a4 e7 86 be 20 d8 1a 38 2d 5e bc 96 d5 90 9c  ab cd ad c8 7c a4 8f 57 45 04 15 9f 16 c3 6e 31");
179             assertStringEquals(hex(a2.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size", i2b(1200))), "89 ad ee 36 08 db 8b c7 1f 1b fb fe 45 94 86 b0  56 18 b7 0c ba e2 20 92 53 4e 56 c5 53 ba 4b 34");
180             assertStringEquals(hex(a2.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size", i2b(1200))), "d7 8c 5c 9c b8 72 a8 c9 da d4 69 7f 0b b5 b2 d2 14 96 c8 2b eb 2c ae da 21 12 fc ee a0 57 40 1b");
181             assertStringEquals(hex(a2.stringToKey(gclef.toCharArray(), "EXAMPLE.COMpianist", i2b(50))), "4b 6d 98 39 f8 44 06 df 1f 09 cc 16 6d b4 b8 3c  57 18 48 b7 84 a3 d6 bd c3 46 58 9a 3e 39 3f 9e");
182         }
183 
184         Cipher cipher = Cipher.getInstance("AES/CTS/NoPadding");
185 
186         cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(
187                 xeh("63 68 69 63 6b 65 6e 20 74 65 72 69 79 61 6b 69"), "AES"),
188                 new IvParameterSpec(
189                 xeh("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"), 0, 16));
190         assertStringEquals(hex(cipher.doFinal(
191                 xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65 20"))),
192                 "c6 35 35 68 f2 bf 8c b4 d8 a5 80 36 2d a7 ff 7f  97");
193         assertStringEquals(hex(cipher.doFinal(
194                 xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20"))),
195                 "fc 00 78 3e 0e fd b2 c1 d4 45 d4 c8 ef f7 ed 22  97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5");
196         assertStringEquals(hex(cipher.doFinal(
197                 xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43"))),
198                 "39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5 a8  97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84");
199         assertStringEquals(hex(cipher.doFinal(
200                 xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43  68 69 63 6b 65 6e 2c 20 70 6c 65 61 73 65 2c"))),
201                 "97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84  b3 ff fd 94 0c 16 a1 8c 1b 55 49 d2 f8 38 02 9e  39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5");
202         assertStringEquals(hex(cipher.doFinal(
203                 xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43  68 69 63 6b 65 6e 2c 20 70 6c 65 61 73 65 2c 20"))),
204                 "97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84  9d ad 8b bb 96 c4 cd c0 3b c1 03 e1 a1 94 bb d8  39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5 a8");
205         assertStringEquals(hex(cipher.doFinal(
206                 xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43  68 69 63 6b 65 6e 2c 20 70 6c 65 61 73 65 2c 20  61 6e 64 20 77 6f 6e 74 6f 6e 20 73 6f 75 70 2e"))),
207                 "97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84  39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5 a8  48 07 ef e8 36 ee 89 a5 26 73 0d bc 2f 7b c8 40  9d ad 8b bb 96 c4 cd c0 3b c1 03 e1 a1 94 bb d8");
208     }
209 
210     static byte[] i2b(int i) {
211         ByteBuffer bb = ByteBuffer.allocate(4);
212         byte[] b = new byte[4];
213         bb.putInt(i);
214         bb.flip();
215         bb.get(b);
216         return b;
217     }
218 
219     static String hex(byte[] bs) {
220         return Hex.encoder("", "", "", false).encode(bs);
221     }
222 
223     static byte[] xeh(String in) {
224         in = in.replaceAll(" ", "");
225         return Hex.decoder().decode(in);
226     }
227 
228     static void assertStringEquals(String a, String b) {
229         a = a.replaceAll(" ", "");
230         b = b.replaceAll(" ", "");
231         if (!a.equals(b)) {
232             throw new RuntimeException("Not equal: " + a + " AND " + b);
233         }
234         System.err.print(".");
235     }
236 }