1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 package org.mozilla.android.sync.test; 5 6 import org.json.simple.JSONArray; 7 import org.junit.Test; 8 import org.junit.runner.RunWith; 9 import org.mozilla.apache.commons.codec.binary.Base64; 10 import org.mozilla.gecko.background.testhelpers.TestRunner; 11 import org.mozilla.gecko.sync.CollectionKeys; 12 import org.mozilla.gecko.sync.CryptoRecord; 13 import org.mozilla.gecko.sync.NoCollectionKeysSetException; 14 import org.mozilla.gecko.sync.NonObjectJSONException; 15 import org.mozilla.gecko.sync.crypto.CryptoException; 16 import org.mozilla.gecko.sync.crypto.KeyBundle; 17 18 import java.io.IOException; 19 import java.util.Arrays; 20 import java.util.Set; 21 22 import static org.junit.Assert.assertArrayEquals; 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertFalse; 25 import static org.junit.Assert.assertNotNull; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 @RunWith(TestRunner.class) 30 public class TestCollectionKeys { 31 32 @Test testDefaultKeys()33 public void testDefaultKeys() throws CryptoException, NoCollectionKeysSetException { 34 CollectionKeys ck = new CollectionKeys(); 35 try { 36 ck.defaultKeyBundle(); 37 fail("defaultKeys should throw."); 38 } catch (NoCollectionKeysSetException ex) { 39 // Good. 40 } 41 KeyBundle testKeys = KeyBundle.withRandomKeys(); 42 ck.setDefaultKeyBundle(testKeys); 43 assertEquals(testKeys, ck.defaultKeyBundle()); 44 } 45 46 @Test testKeyForCollection()47 public void testKeyForCollection() throws CryptoException, NoCollectionKeysSetException { 48 CollectionKeys ck = new CollectionKeys(); 49 try { 50 ck.keyBundleForCollection("test"); 51 fail("keyForCollection should throw."); 52 } catch (NoCollectionKeysSetException ex) { 53 // Good. 54 } 55 KeyBundle testKeys = KeyBundle.withRandomKeys(); 56 KeyBundle otherKeys = KeyBundle.withRandomKeys(); 57 58 ck.setDefaultKeyBundle(testKeys); 59 assertEquals(testKeys, ck.defaultKeyBundle()); 60 assertEquals(testKeys, ck.keyBundleForCollection("test")); // Returns default. 61 62 ck.setKeyBundleForCollection("test", otherKeys); 63 assertEquals(otherKeys, ck.keyBundleForCollection("test")); // Returns default. 64 65 } 66 assertSame(byte[] arrayOne, byte[] arrayTwo)67 public static void assertSame(byte[] arrayOne, byte[] arrayTwo) { 68 assertTrue(Arrays.equals(arrayOne, arrayTwo)); 69 } 70 71 72 @Test testSetKeysFromWBO()73 public void testSetKeysFromWBO() throws IOException, NonObjectJSONException, CryptoException, NoCollectionKeysSetException { 74 String json = "{\"default\":[\"3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=\",\"/AMaoCX4hzic28WY94XtokNi7N4T0nv+moS1y5wlbug=\"],\"collections\":{},\"collection\":\"crypto\",\"id\":\"keys\"}"; 75 CryptoRecord rec = new CryptoRecord(json); 76 77 KeyBundle syncKeyBundle = new KeyBundle("slyjcrjednxd6rf4cr63vqilmkus6zbe", "6m8mv8ex2brqnrmsb9fjuvfg7y"); 78 rec.keyBundle = syncKeyBundle; 79 80 rec.encrypt(); 81 CollectionKeys ck = new CollectionKeys(); 82 ck.setKeyPairsFromWBO(rec, syncKeyBundle); 83 byte[] input = "3fI6k1exImMgAKjilmMaAWxGqEIzFX/9K5EjEgH99vc=".getBytes("UTF-8"); 84 byte[] expected = Base64.decodeBase64(input); 85 assertSame(expected, ck.defaultKeyBundle().getEncryptionKey()); 86 } 87 88 @Test testCryptoRecordFromCollectionKeys()89 public void testCryptoRecordFromCollectionKeys() throws CryptoException, NoCollectionKeysSetException, IOException, NonObjectJSONException { 90 CollectionKeys ck1 = CollectionKeys.generateCollectionKeys(); 91 assertNotNull(ck1.defaultKeyBundle()); 92 assertEquals(ck1.keyBundleForCollection("foobar"), ck1.defaultKeyBundle()); 93 CryptoRecord rec = ck1.asCryptoRecord(); 94 assertEquals(rec.collection, "crypto"); 95 assertEquals(rec.guid, "keys"); 96 JSONArray defaultKey = (JSONArray) rec.payload.get("default"); 97 98 assertSame(Base64.decodeBase64((String) (defaultKey.get(0))), ck1.defaultKeyBundle().getEncryptionKey()); 99 CollectionKeys ck2 = new CollectionKeys(); 100 ck2.setKeyPairsFromWBO(rec, null); 101 assertSame(ck1.defaultKeyBundle().getEncryptionKey(), ck2.defaultKeyBundle().getEncryptionKey()); 102 } 103 104 @Test testCreateKeysBundle()105 public void testCreateKeysBundle() throws CryptoException, NonObjectJSONException, IOException, NoCollectionKeysSetException { 106 String username = "b6evr62dptbxz7fvebek7btljyu322wp"; 107 String friendlyBase32SyncKey = "basuxv2426eqj7frhvpcwkavdi"; 108 109 KeyBundle syncKeyBundle = new KeyBundle(username, friendlyBase32SyncKey); 110 111 CollectionKeys ck = CollectionKeys.generateCollectionKeys(); 112 CryptoRecord unencrypted = ck.asCryptoRecord(); 113 unencrypted.keyBundle = syncKeyBundle; 114 CryptoRecord encrypted = unencrypted.encrypt(); 115 116 CollectionKeys ckDecrypted = new CollectionKeys(); 117 ckDecrypted.setKeyPairsFromWBO(encrypted, syncKeyBundle); 118 119 // Compare decrypted keys to the keys that were set upon creation 120 assertArrayEquals(ck.defaultKeyBundle().getEncryptionKey(), ckDecrypted.defaultKeyBundle().getEncryptionKey()); 121 assertArrayEquals(ck.defaultKeyBundle().getHMACKey(), ckDecrypted.defaultKeyBundle().getHMACKey()); 122 } 123 124 @Test testDifferences()125 public void testDifferences() throws Exception { 126 KeyBundle kb1 = KeyBundle.withRandomKeys(); 127 KeyBundle kb2 = KeyBundle.withRandomKeys(); 128 KeyBundle kb3 = KeyBundle.withRandomKeys(); 129 CollectionKeys a = CollectionKeys.generateCollectionKeys(); 130 CollectionKeys b = CollectionKeys.generateCollectionKeys(); 131 Set<String> diffs; 132 133 a.setKeyBundleForCollection("1", kb1); 134 b.setKeyBundleForCollection("1", kb1); 135 diffs = CollectionKeys.differences(a, b); 136 assertTrue(diffs.isEmpty()); 137 138 a.setKeyBundleForCollection("2", kb2); 139 diffs = CollectionKeys.differences(a, b); 140 assertArrayEquals(new String[] { "2" }, diffs.toArray(new String[diffs.size()])); 141 142 b.setKeyBundleForCollection("3", kb3); 143 diffs = CollectionKeys.differences(a, b); 144 assertEquals(2, diffs.size()); 145 assertTrue(diffs.contains("2")); 146 assertTrue(diffs.contains("3")); 147 148 b.setKeyBundleForCollection("1", KeyBundle.withRandomKeys()); 149 diffs = CollectionKeys.differences(a, b); 150 assertEquals(3, diffs.size()); 151 152 // This tests that explicitly setting a default key works. 153 a = CollectionKeys.generateCollectionKeys(); 154 b = CollectionKeys.generateCollectionKeys(); 155 b.setDefaultKeyBundle(a.defaultKeyBundle()); 156 a.setKeyBundleForCollection("a", a.defaultKeyBundle()); 157 b.setKeyBundleForCollection("b", b.defaultKeyBundle()); 158 assertTrue(CollectionKeys.differences(a, b).isEmpty()); 159 assertTrue(CollectionKeys.differences(b, a).isEmpty()); 160 } 161 162 @Test testEquals()163 public void testEquals() throws Exception { 164 KeyBundle kb1 = KeyBundle.withRandomKeys(); 165 KeyBundle kb2 = KeyBundle.withRandomKeys(); 166 CollectionKeys a = CollectionKeys.generateCollectionKeys(); 167 CollectionKeys b = CollectionKeys.generateCollectionKeys(); 168 169 // Random keys are different. 170 assertFalse(a.equals(b)); 171 assertFalse(b.equals(a)); 172 173 // keys with unset default key bundles are different. 174 b.setDefaultKeyBundle(null); 175 assertFalse(a.equals(b)); 176 177 // keys with equal default key bundles and no other collections are the same. 178 b.setDefaultKeyBundle(a.defaultKeyBundle()); 179 assertTrue(a.equals(b)); 180 181 // keys with equal defaults and equal collections are the same. 182 a.setKeyBundleForCollection("1", kb1); 183 b.setKeyBundleForCollection("1", kb1); 184 assertTrue(a.equals(b)); 185 186 // keys with equal defaults but some collection missing are different. 187 a.setKeyBundleForCollection("2", kb2); 188 assertFalse(a.equals(b)); 189 assertFalse(b.equals(a)); 190 191 // keys with equal defaults and some collection set to the default are the same. 192 a.setKeyBundleForCollection("2", a.defaultKeyBundle()); 193 b.setKeyBundleForCollection("3", b.defaultKeyBundle()); 194 assertTrue(a.equals(b)); 195 assertTrue(b.equals(a)); 196 } 197 } 198