summaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/org/noreply/fancydress/crypto/CryptoPrimitivesTest.java212
-rw-r--r--src/tests/org/noreply/fancydress/crypto/RSAPublicKeyTest.java111
-rw-r--r--src/tests/org/noreply/fancydress/crypto/TestVectors134
-rw-r--r--src/tests/org/noreply/fancydress/directory/ServerDescriptorTest.java44
-rw-r--r--src/tests/org/noreply/fancydress/misc/UtilTest.java202
5 files changed, 703 insertions, 0 deletions
diff --git a/src/tests/org/noreply/fancydress/crypto/CryptoPrimitivesTest.java b/src/tests/org/noreply/fancydress/crypto/CryptoPrimitivesTest.java
new file mode 100644
index 0000000..4acc4db
--- /dev/null
+++ b/src/tests/org/noreply/fancydress/crypto/CryptoPrimitivesTest.java
@@ -0,0 +1,212 @@
+import java.io.*;
+import java.util.*;
+import junit.framework.*;
+import org.noreply.fancydress.crypto.CryptoPrimitives;
+import org.noreply.fancydress.misc.Util;
+
+public class CryptoPrimitivesTest extends TestCase {
+
+ public CryptoPrimitivesTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Test if xor returns an array of the same size as the input arrays.
+ */
+ public void testXorLengthMatchesInputs() {
+ byte[] a = new byte[30];
+ byte[] b = new byte[30];
+ byte[] r = CryptoPrimitives.xor(a,b);
+ assertEquals(30, r.length);
+ }
+
+ /**
+ * Test if rand returns n bytes
+ */
+ public void testRandLength() {
+ byte[] r;
+
+ r = CryptoPrimitives.rand(0);
+ assertEquals(0, r.length);
+ r = CryptoPrimitives.rand(30);
+ assertEquals(30, r.length);
+ r = CryptoPrimitives.rand(300);
+ assertEquals(300, r.length);
+ r = CryptoPrimitives.rand(30000);
+ assertEquals(30000, r.length);
+ }
+
+ /**
+ * Test if zero returns n bytes
+ */
+ public void testZeroLength() {
+ byte[] r;
+
+ r = CryptoPrimitives.zero(0);
+ assertEquals(0, r.length);
+ r = CryptoPrimitives.zero(30);
+ assertEquals(30, r.length);
+ r = CryptoPrimitives.zero(300);
+ assertEquals(300, r.length);
+ r = CryptoPrimitives.zero(30000);
+ assertEquals(30000, r.length);
+ }
+ /**
+ * Test if hash returns HASH_LEN bytes
+ */
+ public void testHashLength() {
+ byte[] r;
+ r = CryptoPrimitives.hash(new byte[0]);
+ assertEquals(CryptoPrimitives.HASH_LEN, r.length);
+
+ r = CryptoPrimitives.hash(new byte[2000]);
+ assertEquals(CryptoPrimitives.HASH_LEN, r.length);
+
+
+ r = CryptoPrimitives.hash(new byte[0], new byte[0]);
+ assertEquals(CryptoPrimitives.HASH_LEN, r.length);
+
+ r = CryptoPrimitives.hash(new byte[2000], new byte[2000]);
+ assertEquals(CryptoPrimitives.HASH_LEN, r.length);
+
+
+ r = CryptoPrimitives.hash(new byte[0], new byte[0], new byte[0]);
+ assertEquals(CryptoPrimitives.HASH_LEN, r.length);
+
+ r = CryptoPrimitives.hash(new byte[2000], new byte[2000], new byte[2000]);
+ assertEquals(CryptoPrimitives.HASH_LEN, r.length);
+ }
+
+ /**
+ * Test if hash is sane sha-1
+ */
+ public void testHash() {
+ String s1 = "";
+ byte[] b1 = Util.toOctets(s1);
+ byte[] h1 = Util.fromHex("da39a3ee5e6b4b0d3255bfef95601890afd80709");
+ String s2 = "I couldn't possibly fail to disagree with you less.";
+ byte[] b2 = Util.toOctets(s2);
+ byte[] h2 = Util.fromHex("90ecb7803dd428bd64ed296600d650a981268f1c");
+ String s3 = "Everyone writes on the walls except me. -Said to be graffiti seen in Pompeii";
+ byte[] b3 = Util.toOctets(s3);
+ byte[] h3 = Util.fromHex("fcdbe159e7c4c2d25f329a75c19c209fd27fc10d");
+ String s4 = "Freedom of the press is for those who happen to own one.";
+ byte[] b4 = Util.toOctets(s4);
+ byte[] h4 = Util.fromHex("12dbc37c1f71491a8fae55ae305ab888b852f70d");
+
+ /* Test hash with one arg. */
+ assertTrue(Util.equal(CryptoPrimitives.hash(b1) , h1));
+ assertTrue(Util.equal(CryptoPrimitives.hash(b2) , h2));
+ assertTrue(Util.equal(CryptoPrimitives.hash(b3) , h3));
+ assertTrue(Util.equal(CryptoPrimitives.hash(b4) , h4));
+
+ byte[] b;
+ /* Test hash with two args. */
+ b = Util.concat(b1,b2);
+ assertTrue(Util.equal( CryptoPrimitives.hash(b), CryptoPrimitives.hash(b1,b2)));
+
+ b = Util.concat(b2,b3);
+ assertTrue(Util.equal( CryptoPrimitives.hash(b), CryptoPrimitives.hash(b2,b3)));
+
+ b = Util.concat(b2,b3);
+ assertTrue(! Util.equal( CryptoPrimitives.hash(b), CryptoPrimitives.hash(b3,b2)));
+
+ /* Test hash with three args. */
+ b = Util.concat(b1,Util.concat(b2,b3));
+ assertTrue(Util.equal( CryptoPrimitives.hash(b), CryptoPrimitives.hash(b1,b2,b3)));
+
+ b = Util.concat(b4,Util.concat(b3,b2));
+ assertTrue(Util.equal( CryptoPrimitives.hash(b), CryptoPrimitives.hash(b4,b3,b2)));
+
+ b = Util.concat(b4,Util.concat(b3,b2));
+ assertTrue(! Util.equal( CryptoPrimitives.hash(b), CryptoPrimitives.hash(b2,b3,b4)));
+ }
+
+ /**
+ * Test the PRNG as defined in the mixminion spec.
+ */
+ public void testPRNG() {
+ byte[] key = Util.fromHex("02 13 24 35 46 57 68 79 8A 9B AC BD CE DF E0 F1");
+ byte[] keystream1 = Util.fromHex("CA F3 E8 F6 23 B9 87 20 D2 F7 A8 66 9C B6 DE 01 71" +
+ "31 CC 3E 74 20 80 99 62 2D 7D DF 98 59 D7 5B A6 77 78 FE 3C 22 C1 B5 AE 1F 8E" +
+ "79 78 72 3D 0F 51 B7 EA 19 F7 93 7F F6 DC 21 EC 2C 13 54 DD 98");
+ byte[] keystream2 = Util.fromHex("81 AE AE FB 58 E0 A2 FE 37 27 31 8E 5B C4 90 B9" +
+ "86 99 95 78 C0 F6 BC AC 9A A6 16 DF BA 0B 4E 6C 0A 10 C5 8F 7B 67 54 19 D7 EA" +
+ "8C 4A A7 0E C7 77 6B 25 51 68 88 1C 7C 4D EB 83 8C A0 3F 4A 85 32");
+
+ byte[] keystream0 = CryptoPrimitives.prng(key, 0x300);
+
+ assertTrue(Util.equal( Util.slice(keystream0, 0 , 0x40), keystream1));
+ assertTrue(Util.equal( Util.slice(keystream0, 0x2c0, 0x40), keystream2));
+ }
+
+ /**
+ * Test encrypt
+ */
+ public void testEncrypt() {
+ byte[] key = Util.fromHex("02 13 24 35 46 57 68 79 8A 9B AC BD CE DF E0 F1");
+ byte[] msg = Util.fromHex("48 65 6C 6C 6F 20 77 6F 72 6C 64 21");
+ byte[] ciphertext = Util.fromHex("82 96 84 9A 4C 99 F0 4F A0 9B CC 47");
+
+ assertTrue(Util.equal( CryptoPrimitives.encrypt(key, msg), ciphertext));
+ }
+
+ /**
+ * Test sprp_encrypt (LIONESS)
+ */
+ /* FIXME: test SPRPEncrypt with 3 args */
+ public void testSPRPEncrypt() {
+ byte[] key = Util.fromHex("AE BB 71 FA E1 F4 70 6C 0C 60 83 83 83 26 70 E3 60 63 37 EA");
+ byte[] msg = Util.fromHex("49 20 6E 65 76 65 72 20 62 65 6C 69 65 76 65 20 69 6E" +
+ "20 63 6F 64 65 20 75 6E 74 69 6C 20 69 74 27 73 20 72 75 6E 6E 69 6E 67 2C 20" +
+ "61 6E 64 20 49 20 6E 65 76 65 72 20 62 65 6C 69 65 76 65 20 69 6E 20 74 68 65" +
+ "20 6E 65 78 74 20 72 65 6C 65 61 73 65 20 75 6E 74 69 6C 20 69 74 27 73 20 6F" +
+ "75 74 2E");
+ byte[] ciphertext = Util.fromHex("1D 46 61 E1 CC 16 FA 17 5C B8 06 66 19 17 4C 09 44 B7" +
+ "BC BC 57 8B 2E EB 06 19 4C E1 F0 0F 67 1B 1B A2 76 E9 3E 77 BF 7C 00 3D A2 91" +
+ "3A 23 62 0A 4C DE 7A 52 E8 29 03 2A 93 B7 1F EC 5C A8 5C 84 7A 3F 45 A5 80 0A" +
+ "0B B6 B5 DF E1 25 B0 DE CC 10 4D 46 45 EF 11 F7 CF 44 01 66 9D EC 36 BF CE 46" +
+ "97 60 3D");
+
+ assertTrue(Util.equal( CryptoPrimitives.sprpEncrypt(key, msg), ciphertext));
+ }
+
+ /**
+ * Test sprp_decrypt (LIONESS)
+ */
+ /* FIXME: test SPRPDecrypt with 3 args */
+ public void testSPRPDecrypt() {
+ byte[] key = Util.fromHex("AE BB 71 FA E1 F4 70 6C 0C 60 83 83 83 26 70 E3 60 63 37 EA");
+ byte[] msg = Util.fromHex("49 20 6E 65 76 65 72 20 62 65 6C 69 65 76 65 20 69 6E" +
+ "20 63 6F 64 65 20 75 6E 74 69 6C 20 69 74 27 73 20 72 75 6E 6E 69 6E 67 2C 20" +
+ "61 6E 64 20 49 20 6E 65 76 65 72 20 62 65 6C 69 65 76 65 20 69 6E 20 74 68 65" +
+ "20 6E 65 78 74 20 72 65 6C 65 61 73 65 20 75 6E 74 69 6C 20 69 74 27 73 20 6F" +
+ "75 74 2E");
+ byte[] plaintext = Util.fromHex("F3 5E 91 70 2F 43 14 9F E0 A0 3B 18 8E A9 FC 17 0A 3A" +
+ "3F C0 EB A5 18 F6 03 4E E3 88 F7 B7 C3 2E 01 80 E1 D7 A1 86 B5 7D D8 38 B8 4D" +
+ "DD 3E 3D D2 D2 15 CA 31 71 DF F7 85 7C 1C 95 20 5A B6 19 22 16 54 F1 4E 09 8E" +
+ "BC 8E C1 02 F6 F5 CE EB 34 53 7F 52 A1 7B 3A 04 78 D8 4C 9C 18 34 FD 5D 63 DD" +
+ "F0 E4 FD");
+
+ assertTrue(Util.equal( CryptoPrimitives.sprpDecrypt(key, msg), plaintext));
+ }
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite();
+ // suite.addTest(new CryptoPrimitivesTest("testXorLengthThrows"));
+ suite.addTest(new CryptoPrimitivesTest("testXorLengthMatchesInputs"));
+ suite.addTest(new CryptoPrimitivesTest("testRandLength"));
+ suite.addTest(new CryptoPrimitivesTest("testZeroLength"));
+ suite.addTest(new CryptoPrimitivesTest("testHashLength"));
+ suite.addTest(new CryptoPrimitivesTest("testHash"));
+ suite.addTest(new CryptoPrimitivesTest("testPRNG"));
+ suite.addTest(new CryptoPrimitivesTest("testEncrypt"));
+ suite.addTest(new CryptoPrimitivesTest("testSPRPEncrypt"));
+ suite.addTest(new CryptoPrimitivesTest("testSPRPDecrypt"));
+ return suite;
+ }
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+}
diff --git a/src/tests/org/noreply/fancydress/crypto/RSAPublicKeyTest.java b/src/tests/org/noreply/fancydress/crypto/RSAPublicKeyTest.java
new file mode 100644
index 0000000..3a37de0
--- /dev/null
+++ b/src/tests/org/noreply/fancydress/crypto/RSAPublicKeyTest.java
@@ -0,0 +1,111 @@
+import java.io.*;
+import java.util.*;
+import junit.framework.*;
+import org.noreply.fancydress.crypto.CryptoPrimitives;
+import org.noreply.fancydress.crypto.RSAPublicKey;
+import org.noreply.fancydress.misc.Util;
+
+public class RSAPublicKeyTest extends TestCase {
+
+ public RSAPublicKeyTest(String name) {
+ super(name);
+ }
+
+ byte[] fpr, asn, modulus, pubE, privP, privQ, privD, padded, encrypted, seed;
+ /**
+ * Test RSAPublicKey
+ */
+ protected void setUp() {
+ fpr = Util.fromHex("4B1B3BA1FC035CAFAFBBFEF7E461DAF28AB9FAA8");
+ asn = Util.fromHex("30 82 01 0A 02 82 01 01 00 D1 A0 41 1E A0 32 7E 80 30 7B 2A" +
+ "B9 34 6A 33 1D EC D5 BA DD 76 94 61 DE 2A B7 E6 9D AC 7D 01 53 CC 7E E7 AA B2" +
+ "4A 9C 2A C8 CC 7B 74 73 36 10 EE 90 3D DE 6D 82 8F 2C A3 27 54 33 3E 9E 85 72" +
+ "1D 26 B0 9F 32 1C FB 5F B0 AB 52 C5 3F 94 C9 88 F9 0F 76 87 4A AB F4 8D 97 3D" +
+ "FA DE 49 25 B8 BC 21 A1 67 67 FF 5E A4 8E 5A 6B 9E F7 43 93 A6 71 B9 75 D3 B0" +
+ "01 AD 83 6D F9 A4 4B 45 B3 80 4B 38 B3 B1 8A 45 B6 A5 DB 76 4E 2A FB D6 9F 52" +
+ "63 4C C6 74 CF 26 E5 45 99 C3 8C F7 2A A6 05 7C F2 C8 A0 1B 0D FB 78 69 72 C8" +
+ "E3 3B 80 69 93 3A 4F DF 35 71 CB C5 4D DB E8 42 C6 36 DF A3 0D AC 3B A7 DA 0F" +
+ "6B BA AF C0 57 3C 1E D6 94 06 E6 C0 3F 19 A1 7E 9F F0 56 DA CB 4D 9A 8C 6D 26" +
+ "C6 09 44 F5 FD 18 42 BE BA 0C E3 44 40 FA 31 42 DF 02 D6 09 F7 28 02 10 D8 77" +
+ "70 D5 CC 69 41 FD E5 91 C7 81 CB 02 03 01 00 01");
+ pubE = Util.fromHex("01 00 01");
+ modulus = Util.fromHex("D1 A0 41 1E A0 32 7E 80 30 7B 2A B9 34 6A 33 1D EC D5 BA DD 76" +
+ "94 61 DE 2A B7 E6 9D AC 7D 01 53 CC 7E E7 AA B2 4A 9C 2A C8 CC 7B 74 73 36 10" +
+ "EE 90 3D DE 6D 82 8F 2C A3 27 54 33 3E 9E 85 72 1D 26 B0 9F 32 1C FB 5F B0 AB" +
+ "52 C5 3F 94 C9 88 F9 0F 76 87 4A AB F4 8D 97 3D FA DE 49 25 B8 BC 21 A1 67 67" +
+ "FF 5E A4 8E 5A 6B 9E F7 43 93 A6 71 B9 75 D3 B0 01 AD 83 6D F9 A4 4B 45 B3 80" +
+ "4B 38 B3 B1 8A 45 B6 A5 DB 76 4E 2A FB D6 9F 52 63 4C C6 74 CF 26 E5 45 99 C3" +
+ "8C F7 2A A6 05 7C F2 C8 A0 1B 0D FB 78 69 72 C8 E3 3B 80 69 93 3A 4F DF 35 71" +
+ "CB C5 4D DB E8 42 C6 36 DF A3 0D AC 3B A7 DA 0F 6B BA AF C0 57 3C 1E D6 94 06" +
+ "E6 C0 3F 19 A1 7E 9F F0 56 DA CB 4D 9A 8C 6D 26 C6 09 44 F5 FD 18 42 BE BA 0C" +
+ "E3 44 40 FA 31 42 DF 02 D6 09 F7 28 02 10 D8 77 70 D5 CC 69 41 FD E5 91 C7 81" +
+ "CB");
+ privP = Util.fromHex("F1 8C 45 B7 41 AB AA 5B 2D 2D 71 32 B4 0A 64 91 36 64 18" +
+ "37 F7 0F 54 EB CF 2B 36 57 6F AE 50 4C 6D 61 CA 05 AD 9C 48 18 B9 3C FB B0 4F" +
+ "1C 68 B1 26 32 C1 BC CA 8C 2C D6 81 30 C5 C7 FF D1 DF 4B 21 CD DD 01 D7 5A E9" +
+ "0F A8 D8 66 C2 69 C7 89 3D 34 8B 44 2C 36 C7 70 B0 62 44 C5 71 F4 1E CC 60 64" +
+ "22 83 90 B6 D8 93 39 B3 7A D7 D7 3E 86 8F E3 74 39 7D E5 52 CE 19 81 AD 9D DE" +
+ "A7 09 53 24 31");
+ privQ = Util.fromHex("DE 2B 0A B4 B8 88 4B 21 AE 6A 8E 1B 31 3F EC DE C4 1C 82" +
+ "A7 0B 02 BA 4D 88 F5 28 E4 44 A9 E6 A6 D7 7E 50 22 1F 6C 13 0B 56 4D 87 BC 14" +
+ "B6 7D 00 9B C4 DD 1B 52 67 28 55 1D C0 71 0B A6 24 4F F7 20 90 8F 66 C5 4B FF" +
+ "39 8E 4E 91 08 49 97 74 01 A9 63 30 7A 96 BA AD 62 11 4D 7B 92 F3 A6 12 C6 B4" +
+ "02 EC B9 53 AA E8 8E CB 41 B5 17 63 7D 35 F5 F9 1A C1 F8 85 BE 76 19 56 8B C2" +
+ "DC 32 82 B2 BB");
+ privD = Util.fromHex("44 D1 52 6F 86 71 ED 3B 92 2E ED 20 AE 07 6B 4E 98 B0 B5" +
+ "CE FC 9D CB DF 4E B0 DE E1 C6 7D A7 50 E6 62 87 15 6F C0 B4 B2 0B 07 AE 43 D5" +
+ "8A DB 56 26 3E 59 66 24 25 72 A7 01 43 50 2B 6F 89 29 A4 4E 4E 4F 84 F9 24 C1" +
+ "0E 53 C0 31 87 25 06 60 94 3B 32 53 49 FD 57 A4 A0 11 35 E9 81 A4 03 98 A7 85" +
+ "C0 57 D0 EB 36 24 91 A4 A1 24 55 A8 04 4D 73 70 2E 15 AB 07 56 8D 65 16 3D AB" +
+ "DD 38 F1 F8 E3 D4 DA 17 B2 F2 D5 63 A1 D3 69 58 87 9F C4 42 C6 EA 12 1D 3F F5" +
+ "2D 78 D2 B6 F4 7D B6 C2 C7 93 A9 65 0A DC DC 44 ED 5F A8 11 FB 81 1A 20 F2 18" +
+ "4B D6 0E 54 AD F5 09 9D 73 52 0B 70 B6 3F D6 D0 B7 2D 17 00 2A B4 99 AF 7C 03" +
+ "01 9F A3 3A CA DC 26 B8 D0 6B 65 A9 86 EC 36 C6 CA 1E 01 20 49 57 B5 DB 85 C3" +
+ "79 5C 1E 2B C6 F9 E8 9F CE 11 4B 16 17 98 70 75 99 C1 4D F9 89 3F C2 16 9A 25" +
+ "D2 D7 A1");
+ seed = Util.fromHex("00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13");
+ padded = Util.fromHex("00 19 B0 7B B0 24 3D 14 F6 17 06 CE E6 81 26 83" +
+ "FA 7D D3 9B 38 92 0C 33 64 A9 34 8C 3D 87 9E 4D 61 CA F2 50 24 96 19 83 6B 99" +
+ "F3 72 63 A5 74 17 1D 60 78 80 91 7A EF CF 64 22 94 B0 8B 98 27 11 C0 FA 68 F6" +
+ "48 5F 62 C7 30 54 AB 50 A0 C7 56 69 5E 2A 53 BD 58 5A 81 94 85 27 EC F0 15 61" +
+ "4F 8B BE 3E 96 FE AA 86 89 4F D5 43 FB 37 CA 4C A3 58 CA 98 88 07 83 DD 07 A5" +
+ "6F DB E4 BE 7D D4 4F 45 C5 CB 11 F4 7F 60 53 64 5A 2D 45 B3 3A 0F B0 CB 4E EF" +
+ "E0 3A 23 20 8A BA 39 17 A4 5F 1C BE 4B 72 BA BB E8 6F 85 9F FC 5F C1 00 04 22" +
+ "FB E2 1F 3A AD BD 73 FE 45 D0 37 61 EE 30 CC 33 10 26 1C 71 70 F4 EB 0C F4 EA" +
+ "DE B4 4F CE 38 5C 8F F4 34 02 97 1D 43 0D C7 BD 31 18 2E EE 6D E1 CE 62 D8 D7" +
+ "61 0C D7 4A 5A 92 FA 88 AD 95 CB C8 40 F0 B8 5C 81 9E 70 CF 4D C6 DB 9D 1A 7A" +
+ "20 9C 71 FD 97 CB");
+ encrypted = Util.fromHex("A5 7A 58 F6 3A 15 1B 9F 30 C3 56 EA 5A F3 C8 4D 3E 25 36" +
+ "37 59 2D 1C A3 BF 1B A0 40 99 80 50 7E 06 48 73 41 A0 58 AF 40 8F DF 71 9C D9" +
+ "3F 3E CB 7D B6 7F F7 E8 46 81 16 10 CB B1 0A E0 5B 4A 68 68 98 1A EE 8A 68 FC" +
+ "63 B9 14 6D 2A 48 FD A3 28 1A 1C E2 19 2A 41 1B 04 C7 74 3F EA 43 50 C9 23 80" +
+ "0D 5F 0F EC 7B 74 AD 6B 4F E0 A6 95 6B BF 93 1A B1 7C 08 1F 0C 25 1D E1 5B 7F" +
+ "58 EC 60 C2 71 9D BB AF BD 7E BC DB 71 47 A8 B1 25 E6 1A 15 61 D0 59 09 75 A4" +
+ "69 71 4F 80 52 99 2D D9 59 F0 06 45 53 88 EA FA E0 32 D9 9C E3 C9 6C 36 BF 52" +
+ "6F 60 54 B5 B2 DA 55 1C F9 90 5D 14 DC EA 79 C3 CE 10 E5 E7 11 16 92 B0 1C C7" +
+ "9A 17 52 7E D3 6C 04 20 14 C8 9E 23 02 6B 23 27 A3 97 89 18 B1 6C 6F C5 11 DA" +
+ "D9 21 A5 1B 2C 13 80 01 1E DF 37 87 FC 37 C1 36 0A 2E AA 9C 85 75 1A D2 B5 2D" +
+ "27 1A A6");
+ }
+
+ public void testRSAPublicKey() {
+ RSAPublicKey key = new RSAPublicKey(asn);
+
+ assertTrue(CryptoPrimitives.equal(key.encode(), asn));
+ assertTrue(CryptoPrimitives.equal(key.getFingerprint(), fpr));
+
+ /* FIXME
+ * we cannot check if encryptiong works because BC does not allow to set the MGF seed
+ */
+ };
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite();
+ suite.addTest(new RSAPublicKeyTest("testRSAPublicKey"));
+ return suite;
+ }
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+}
diff --git a/src/tests/org/noreply/fancydress/crypto/TestVectors b/src/tests/org/noreply/fancydress/crypto/TestVectors
new file mode 100644
index 0000000..78ae9cd
--- /dev/null
+++ b/src/tests/org/noreply/fancydress/crypto/TestVectors
@@ -0,0 +1,134 @@
+Here's my first pass at test vectors. Once we both generate these, I'll
+feel better about my crypto, and publish them for real.
+
+======================================== RSA Example
+2048-bit Key K
+
+ exponent = [01 00 01]
+
+ modulus = [D1 A0 41 1E A0 32 7E 80 30 7B 2A B9 34 6A 33 1D EC D5 BA DD 76
+94 61 DE 2A B7 E6 9D AC 7D 01 53 CC 7E E7 AA B2 4A 9C 2A C8 CC 7B 74 73 36 10
+EE 90 3D DE 6D 82 8F 2C A3 27 54 33 3E 9E 85 72 1D 26 B0 9F 32 1C FB 5F B0 AB
+52 C5 3F 94 C9 88 F9 0F 76 87 4A AB F4 8D 97 3D FA DE 49 25 B8 BC 21 A1 67 67
+FF 5E A4 8E 5A 6B 9E F7 43 93 A6 71 B9 75 D3 B0 01 AD 83 6D F9 A4 4B 45 B3 80
+4B 38 B3 B1 8A 45 B6 A5 DB 76 4E 2A FB D6 9F 52 63 4C C6 74 CF 26 E5 45 99 C3
+8C F7 2A A6 05 7C F2 C8 A0 1B 0D FB 78 69 72 C8 E3 3B 80 69 93 3A 4F DF 35 71
+CB C5 4D DB E8 42 C6 36 DF A3 0D AC 3B A7 DA 0F 6B BA AF C0 57 3C 1E D6 94 06
+E6 C0 3F 19 A1 7E 9F F0 56 DA CB 4D 9A 8C 6D 26 C6 09 44 F5 FD 18 42 BE BA 0C
+E3 44 40 FA 31 42 DF 02 D6 09 F7 28 02 10 D8 77 70 D5 CC 69 41 FD E5 91 C7 81
+CB]
+
+ Private key (P)= [F1 8C 45 B7 41 AB AA 5B 2D 2D 71 32 B4 0A 64 91 36 64 18
+37 F7 0F 54 EB CF 2B 36 57 6F AE 50 4C 6D 61 CA 05 AD 9C 48 18 B9 3C FB B0 4F
+1C 68 B1 26 32 C1 BC CA 8C 2C D6 81 30 C5 C7 FF D1 DF 4B 21 CD DD 01 D7 5A E9
+0F A8 D8 66 C2 69 C7 89 3D 34 8B 44 2C 36 C7 70 B0 62 44 C5 71 F4 1E CC 60 64
+22 83 90 B6 D8 93 39 B3 7A D7 D7 3E 86 8F E3 74 39 7D E5 52 CE 19 81 AD 9D DE
+A7 09 53 24 31]
+
+ Private key (Q)= [DE 2B 0A B4 B8 88 4B 21 AE 6A 8E 1B 31 3F EC DE C4 1C 82
+A7 0B 02 BA 4D 88 F5 28 E4 44 A9 E6 A6 D7 7E 50 22 1F 6C 13 0B 56 4D 87 BC 14
+B6 7D 00 9B C4 DD 1B 52 67 28 55 1D C0 71 0B A6 24 4F F7 20 90 8F 66 C5 4B FF
+39 8E 4E 91 08 49 97 74 01 A9 63 30 7A 96 BA AD 62 11 4D 7B 92 F3 A6 12 C6 B4
+02 EC B9 53 AA E8 8E CB 41 B5 17 63 7D 35 F5 F9 1A C1 F8 85 BE 76 19 56 8B C2
+DC 32 82 B2 BB]
+
+ Private key (D)= [44 D1 52 6F 86 71 ED 3B 92 2E ED 20 AE 07 6B 4E 98 B0 B5
+CE FC 9D CB DF 4E B0 DE E1 C6 7D A7 50 E6 62 87 15 6F C0 B4 B2 0B 07 AE 43 D5
+8A DB 56 26 3E 59 66 24 25 72 A7 01 43 50 2B 6F 89 29 A4 4E 4E 4F 84 F9 24 C1
+0E 53 C0 31 87 25 06 60 94 3B 32 53 49 FD 57 A4 A0 11 35 E9 81 A4 03 98 A7 85
+C0 57 D0 EB 36 24 91 A4 A1 24 55 A8 04 4D 73 70 2E 15 AB 07 56 8D 65 16 3D AB
+DD 38 F1 F8 E3 D4 DA 17 B2 F2 D5 63 A1 D3 69 58 87 9F C4 42 C6 EA 12 1D 3F F5
+2D 78 D2 B6 F4 7D B6 C2 C7 93 A9 65 0A DC DC 44 ED 5F A8 11 FB 81 1A 20 F2 18
+4B D6 0E 54 AD F5 09 9D 73 52 0B 70 B6 3F D6 D0 B7 2D 17 00 2A B4 99 AF 7C 03
+01 9F A3 3A CA DC 26 B8 D0 6B 65 A9 86 EC 36 C6 CA 1E 01 20 49 57 B5 DB 85 C3
+79 5C 1E 2B C6 F9 E8 9F CE 11 4B 16 17 98 70 75 99 C1 4D F9 89 3F C2 16 9A 25
+D2 D7 A1]
+
+ PK_Encode(K) = [30 82 01 0A 02 82 01 01 00 D1 A0 41 1E A0 32 7E 80 30 7B 2A
+B9 34 6A 33 1D EC D5 BA DD 76 94 61 DE 2A B7 E6 9D AC 7D 01 53 CC 7E E7 AA B2
+4A 9C 2A C8 CC 7B 74 73 36 10 EE 90 3D DE 6D 82 8F 2C A3 27 54 33 3E 9E 85 72
+1D 26 B0 9F 32 1C FB 5F B0 AB 52 C5 3F 94 C9 88 F9 0F 76 87 4A AB F4 8D 97 3D
+FA DE 49 25 B8 BC 21 A1 67 67 FF 5E A4 8E 5A 6B 9E F7 43 93 A6 71 B9 75 D3 B0
+01 AD 83 6D F9 A4 4B 45 B3 80 4B 38 B3 B1 8A 45 B6 A5 DB 76 4E 2A FB D6 9F 52
+63 4C C6 74 CF 26 E5 45 99 C3 8C F7 2A A6 05 7C F2 C8 A0 1B 0D FB 78 69 72 C8
+E3 3B 80 69 93 3A 4F DF 35 71 CB C5 4D DB E8 42 C6 36 DF A3 0D AC 3B A7 DA 0F
+6B BA AF C0 57 3C 1E D6 94 06 E6 C0 3F 19 A1 7E 9F F0 56 DA CB 4D 9A 8C 6D 26
+C6 09 44 F5 FD 18 42 BE BA 0C E3 44 40 FA 31 42 DF 02 D6 09 F7 28 02 10 D8 77
+70 D5 CC 69 41 FD E5 91 C7 81 CB 02 03 01 00 01]
+
+ Fingerprint = 4B1B3BA1FC035CAFAFBBFEF7E461DAF28AB9FAA8
+
+OAEP Padding/PKCS encoding example: (Using MGF SEED [00 01 02 03 04 05 06 07
+08 09 0A 0B 0C 0D 0E 0F 10 11 12 13])
+
+ original string M: [48 65 6C 6C 6F 20 77 6F 72 6C 64]
+
+ Padded string (2048 bits): [00 19 B0 7B B0 24 3D 14 F6 17 06 CE E6 81 26 83
+FA 7D D3 9B 38 92 0C 33 64 A9 34 8C 3D 87 9E 4D 61 CA F2 50 24 96 19 83 6B 99
+F3 72 63 A5 74 17 1D 60 78 80 91 7A EF CF 64 22 94 B0 8B 98 27 11 C0 FA 68 F6
+48 5F 62 C7 30 54 AB 50 A0 C7 56 69 5E 2A 53 BD 58 5A 81 94 85 27 EC F0 15 61
+4F 8B BE 3E 96 FE AA 86 89 4F D5 43 FB 37 CA 4C A3 58 CA 98 88 07 83 DD 07 A5
+6F DB E4 BE 7D D4 4F 45 C5 CB 11 F4 7F 60 53 64 5A 2D 45 B3 3A 0F B0 CB 4E EF
+E0 3A 23 20 8A BA 39 17 A4 5F 1C BE 4B 72 BA BB E8 6F 85 9F FC 5F C1 00 04 22
+FB E2 1F 3A AD BD 73 FE 45 D0 37 61 EE 30 CC 33 10 26 1C 71 70 F4 EB 0C F4 EA
+DE B4 4F CE 38 5C 8F F4 34 02 97 1D 43 0D C7 BD 31 18 2E EE 6D E1 CE 62 D8 D7
+61 0C D7 4A 5A 92 FA 88 AD 95 CB C8 40 F0 B8 5C 81 9E 70 CF 4D C6 DB 9D 1A 7A
+20 9C 71 FD 97 CB]
+
+ PK_Encrypt(K,M): [A5 7A 58 F6 3A 15 1B 9F 30 C3 56 EA 5A F3 C8 4D 3E 25 36
+37 59 2D 1C A3 BF 1B A0 40 99 80 50 7E 06 48 73 41 A0 58 AF 40 8F DF 71 9C D9
+3F 3E CB 7D B6 7F F7 E8 46 81 16 10 CB B1 0A E0 5B 4A 68 68 98 1A EE 8A 68 FC
+63 B9 14 6D 2A 48 FD A3 28 1A 1C E2 19 2A 41 1B 04 C7 74 3F EA 43 50 C9 23 80
+0D 5F 0F EC 7B 74 AD 6B 4F E0 A6 95 6B BF 93 1A B1 7C 08 1F 0C 25 1D E1 5B 7F
+58 EC 60 C2 71 9D BB AF BD 7E BC DB 71 47 A8 B1 25 E6 1A 15 61 D0 59 09 75 A4
+69 71 4F 80 52 99 2D D9 59 F0 06 45 53 88 EA FA E0 32 D9 9C E3 C9 6C 36 BF 52
+6F 60 54 B5 B2 DA 55 1C F9 90 5D 14 DC EA 79 C3 CE 10 E5 E7 11 16 92 B0 1C C7
+9A 17 52 7E D3 6C 04 20 14 C8 9E 23 02 6B 23 27 A3 97 89 18 B1 6C 6F C5 11 DA
+D9 21 A5 1B 2C 13 80 01 1E DF 37 87 FC 37 C1 36 0A 2E AA 9C 85 75 1A D2 B5 2D
+27 1A A6]
+
+======================================== AES Single block encryption
+ Key: [00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF]
+ Plaintext block: [4D 69 78 6D 69 6E 69 6F 6E 54 79 70 65 49 49 49]
+ Encrypted block: [11 86 E8 6C 9D 55 16 33 6E 13 E1 71 69 A4 86 94]
+ Decrypted block: [7F 49 AA 5E 62 4A 12 B6 99 47 D7 52 47 11 27 6E]
+
+Counter mode encryption:
+ Key: [02 13 24 35 46 57 68 79 8A 9B AC BD CE DF E0 F1]
+
+ Keystream[0x0...0x3F]: [CA F3 E8 F6 23 B9 87 20 D2 F7 A8 66 9C B6 DE 01 71
+31 CC 3E 74 20 80 99 62 2D 7D DF 98 59 D7 5B A6 77 78 FE 3C 22 C1 B5 AE 1F 8E
+79 78 72 3D 0F 51 B7 EA 19 F7 93 7F F6 DC 21 EC 2C 13 54 DD 98]
+
+ Keystream[0x2C0...0x2FF]: [81 AE AE FB 58 E0 A2 FE 37 27 31 8E 5B C4 90 B9
+86 99 95 78 C0 F6 BC AC 9A A6 16 DF BA 0B 4E 6C 0A 10 C5 8F 7B 67 54 19 D7 EA
+8C 4A A7 0E C7 77 6B 25 51 68 88 1C 7C 4D EB 83 8C A0 3F 4A 85 32]
+
+ Example text M: [48 65 6C 6C 6F 20 77 6F 72 6C 64 21]
+
+ Encrypt(K,M): [82 96 84 9A 4C 99 F0 4F A0 9B CC 47]
+
+======================================== LIONESS SPRP_Encrypt:
+ Base key K: [AE BB 71 FA E1 F4 70 6C 0C 60 83 83 83 26 70 E3 60 63 37 EA]
+ K2: [AE BB 71 FA E1 F4 70 6C 0C 60 83 83 83 26 70 E3 60 63 37 EB]
+ K3: [AE BB 71 FA E1 F4 70 6C 0C 60 83 83 83 26 70 E3 60 63 37 E8]
+ K4: [AE BB 71 FA E1 F4 70 6C 0C 60 83 83 83 26 70 E3 60 63 37 E9]
+
+ Example text M: [49 20 6E 65 76 65 72 20 62 65 6C 69 65 76 65 20 69 6E
+20 63 6F 64 65 20 75 6E 74 69 6C 20 69 74 27 73 20 72 75 6E 6E 69 6E 67 2C 20
+61 6E 64 20 49 20 6E 65 76 65 72 20 62 65 6C 69 65 76 65 20 69 6E 20 74 68 65
+20 6E 65 78 74 20 72 65 6C 65 61 73 65 20 75 6E 74 69 6C 20 69 74 27 73 20 6F
+75 74 2E]
+
+ SPRP_Encrypt(K,M): [1D 46 61 E1 CC 16 FA 17 5C B8 06 66 19 17 4C 09 44 B7
+BC BC 57 8B 2E EB 06 19 4C E1 F0 0F 67 1B 1B A2 76 E9 3E 77 BF 7C 00 3D A2 91
+3A 23 62 0A 4C DE 7A 52 E8 29 03 2A 93 B7 1F EC 5C A8 5C 84 7A 3F 45 A5 80 0A
+0B B6 B5 DF E1 25 B0 DE CC 10 4D 46 45 EF 11 F7 CF 44 01 66 9D EC 36 BF CE 46
+97 60 3D]
+
+ SPRP_Decrypt(K,M): [F3 5E 91 70 2F 43 14 9F E0 A0 3B 18 8E A9 FC 17 0A 3A
+3F C0 EB A5 18 F6 03 4E E3 88 F7 B7 C3 2E 01 80 E1 D7 A1 86 B5 7D D8 38 B8 4D
+DD 3E 3D D2 D2 15 CA 31 71 DF F7 85 7C 1C 95 20 5A B6 19 22 16 54 F1 4E 09 8E
+BC 8E C1 02 F6 F5 CE EB 34 53 7F 52 A1 7B 3A 04 78 D8 4C 9C 18 34 FD 5D 63 DD
+F0 E4 FD]
+
diff --git a/src/tests/org/noreply/fancydress/directory/ServerDescriptorTest.java b/src/tests/org/noreply/fancydress/directory/ServerDescriptorTest.java
new file mode 100644
index 0000000..adbe46e
--- /dev/null
+++ b/src/tests/org/noreply/fancydress/directory/ServerDescriptorTest.java
@@ -0,0 +1,44 @@
+import java.io.*;
+import java.util.*;
+import junit.framework.*;
+import org.noreply.fancydress.misc.Util;
+import org.noreply.fancydress.directory.ServerDescriptor;
+
+public class ServerDescriptorTest extends TestCase {
+
+ public ServerDescriptorTest(String name) {
+ super(name);
+ }
+
+ private boolean equals(String[] s1, String[] s2) {
+ boolean equals = s1.length == s2.length;
+ if (equals)
+ for (int i=0; i<s1.length; i++) {
+ equals = equals && s1[i].equals(s2[i]);
+ }
+ return equals;
+ }
+
+ public void testParsePacketVersions() {
+ String versions = "0.1 , 0.3, 0.6";
+ String[] expected = {"0.1", "0.3", "0.6"};
+ String[] parsed = ServerDescriptor.parsePacketVersions(versions, false);
+ String[] expected2 = {"0.3"};
+ String[] parsed2 = ServerDescriptor.parsePacketVersions(versions);
+ String[] parsed2_1 = ServerDescriptor.parsePacketVersions("0.3");
+
+ assertTrue(equals(expected, parsed));
+ assertTrue(equals(expected2, parsed2));
+ assertTrue(equals(expected2, parsed2_1));
+ };
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite();
+ suite.addTest(new ServerDescriptorTest("testParsePacketVersions"));
+ return suite;
+ }
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+}
diff --git a/src/tests/org/noreply/fancydress/misc/UtilTest.java b/src/tests/org/noreply/fancydress/misc/UtilTest.java
new file mode 100644
index 0000000..d967b99
--- /dev/null
+++ b/src/tests/org/noreply/fancydress/misc/UtilTest.java
@@ -0,0 +1,202 @@
+import java.io.*;
+import java.util.*;
+import junit.framework.*;
+import org.noreply.fancydress.misc.Util;
+
+public class UtilTest extends TestCase {
+
+ public UtilTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Test if equal returns an array of the same size as the input arrays.
+ */
+ public void testEqual() {
+ byte[] a0 = new byte[30];
+ byte[] a1 = { };
+ byte[] a2 = { (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 };
+ byte[] a3 = { (byte)0x10, (byte)0x20, (byte)0xf0, (byte)0xF0, (byte)0xab };
+ assertTrue(Util.equal(a0,a0));
+ assertTrue(Util.equal(a1,a1));
+ assertTrue(Util.equal(a2,a2));
+ assertTrue(Util.equal(a3,a3));
+
+ assertTrue(!Util.equal(a0,a1));
+ assertTrue(!Util.equal(a0,a2));
+ assertTrue(!Util.equal(a0,a3));
+ assertTrue(!Util.equal(a1,a0));
+ assertTrue(!Util.equal(a1,a2));
+ assertTrue(!Util.equal(a1,a3));
+ assertTrue(!Util.equal(a2,a0));
+ assertTrue(!Util.equal(a2,a1));
+ assertTrue(!Util.equal(a2,a3));
+ assertTrue(!Util.equal(a3,a0));
+ assertTrue(!Util.equal(a3,a1));
+ assertTrue(!Util.equal(a3,a2));
+ }
+
+ /**
+ * Test if concat returns n+m bytes
+ */
+ public void testConcatLength() {
+ byte[] a;
+ byte[] b;
+ byte[] r;
+
+ a = new byte[0];
+ b = new byte[30];
+ r = Util.concat(a,b);
+ assertEquals(a.length + b.length, r.length);
+ a = new byte[30];
+ b = new byte[0];
+ r = Util.concat(a,b);
+ assertEquals(a.length + b.length, r.length);
+ a = new byte[30];
+ b = new byte[30];
+ r = Util.concat(a,b);
+ assertEquals(a.length + b.length, r.length);
+ }
+
+ /**
+ * Test that slice returns the correct length
+ */
+ public void testSliceLength() {
+ byte[] b = new byte[300];
+ byte[] r;
+
+ r = Util.slice(b, 0, 0);
+ assertEquals(0, r.length);
+ r = Util.slice(b, 30, 0);
+ assertEquals(0, r.length);
+ r = Util.slice(b, 0, 30);
+ assertEquals(30, r.length);
+ r = Util.slice(b, 30, 30);
+ assertEquals(30, r.length);
+ }
+
+ /**
+ * Test that slice returns the correct length
+ */
+ public void testSlice() {
+ byte[] b0 = Util.fromHex("00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF");
+ byte[] b1 = Util.fromHex("00 11 22 33 44 55 66 77 ");
+ byte[] b2 = Util.fromHex(" 55 66 77 88 99 ");
+ byte[] b3 = Util.fromHex(" DD EE FF");
+ byte[] b4 = Util.fromHex(" ");
+
+ assertTrue(Util.equal(Util.slice(b0, 0, b0.length), b0));
+ assertTrue(Util.equal(Util.slice(b0, 0, 8), b1));
+ assertTrue(Util.equal(Util.slice(b0, 5, 5), b2));
+ assertTrue(Util.equal(Util.slice(b0, 13, 3), b3));
+
+ assertTrue(Util.equal(Util.slice(b0, 0, 0), b4));
+ assertTrue(Util.equal(Util.slice(b0, 5, 0), b4));
+ assertTrue(Util.equal(Util.slice(b0, 15, 0), b4));
+ }
+
+ /**
+ * Test if fromHex returns the right amount if bytes.
+ */
+ public void testFromHexLength() {
+ String s;
+ byte[] r;
+
+ s = "";
+ r = Util.fromHex(s);
+ assertEquals(0, r.length);
+
+ s = " ";
+ r = Util.fromHex(s);
+ assertEquals(0, r.length);
+
+ s = "00 01 02 03 04";
+ r = Util.fromHex(s);
+ assertEquals(5, r.length);
+
+ s = "00 01 02 0 3 0 4";
+ r = Util.fromHex(s);
+ assertEquals(5, r.length);
+ }
+
+ /**
+ * Test if fromHex is sane.
+ */
+ public void testFromHexSaneness() {
+ String s1 = "";
+ String s2 = "00 01 02 03 04";
+ String s2_2 = "00 01 02 0 3 04";
+ String s3 = "10 20 f0 F0 Ab";
+ byte[] a1 = { };
+ byte[] a2 = { (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 };
+ byte[] a3 = { (byte)0x10, (byte)0x20, (byte)0xf0, (byte)0xF0, (byte)0xab };
+ byte[] r;
+
+ r = Util.fromHex(s1);
+ assertTrue(Util.equal(a1, r));
+
+ r = Util.fromHex(s2);
+ assertTrue(Util.equal(a2, r));
+
+ r = Util.fromHex(s2_2);
+ assertTrue(Util.equal(a2, r));
+
+ r = Util.fromHex(s3);
+ assertTrue(Util.equal(a3, r));
+ }
+
+ /**
+ * Test if fromHex(asHex()) is sane.
+ */
+ public void testAsHexFromHex() {
+ String s = "CA F3 E8 F6 23 B9 87 20 D2 F7 A8 66 9C B6 DE 01 71" +
+ "31 CC 3E 74 20 80 99 62 2D 7D DF 98 59 D7 5B A6 77 78 FE 3C 22 C1 B5 AE 1F 8E" +
+ "79 78 72 3D 0F 51 B7 EA 19 F7 93 7F F6 DC 21 EC 2C 13 54 DD 98";
+ byte[] r, r1;
+ String s1;
+
+ r = Util.fromHex(s);
+ s1 = Util.asHex(r);
+ r1 = Util.fromHex(s1);
+
+ assertTrue(Util.equal(r, r1));
+ }
+
+ /**
+ * Test if toOctets() works.
+ */
+ public void testToOctets() {
+ String s0 = "Don't you wish you had more energy... or less ambition?";
+ byte[] o0 = Util.fromHex("44 6f 6e 27 74 20 79 6f 75 20 77 69 73 68 20 79" +
+ "6f 75 20 68 61 64 20 6d 6f 72 65 20 65 6e 65 72" +
+ "67 79 2e 2e 2e 20 6f 72 20 6c 65 73 73 20 61 6d" +
+ "62 69 74 69 6f 6e 3f" );
+ String s1 = "";
+ byte[] o1 = {};
+ byte[] r;
+
+ r = Util.toOctets(s0);
+ assertTrue(Util.equal(r, o0));
+
+ r = Util.toOctets(s1);
+ assertTrue(Util.equal(r, o1));
+ }
+
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite();
+ suite.addTest(new UtilTest("testEqual"));
+ suite.addTest(new UtilTest("testConcatLength"));
+ suite.addTest(new UtilTest("testSlice"));
+ suite.addTest(new UtilTest("testSliceLength"));
+ suite.addTest(new UtilTest("testFromHexLength"));
+ suite.addTest(new UtilTest("testFromHexSaneness"));
+ suite.addTest(new UtilTest("testAsHexFromHex"));
+ suite.addTest(new UtilTest("testToOctets"));
+ return suite;
+ }
+
+ public static void main(String args[]) {
+ junit.textui.TestRunner.run(suite());
+ }
+}