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