package de.pinyto.ctSESAM; import android.test.ActivityInstrumentationTestCase2; import org.json.JSONException; import org.json.JSONObject; import java.util.Arrays; import java.util.Iterator; import javax.crypto.NoSuchPaddingException; /** * Testing the management of password settings. */ public class PasswordSettingsManagerTest extends ActivityInstrumentationTestCase2<MainActivity> { private PasswordSettingsManager settingsManager; private KgkManager kgkManager; public PasswordSettingsManagerTest() { super(MainActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); settingsManager = new PasswordSettingsManager(getActivity().getBaseContext()); kgkManager = new KgkManager(getActivity().getBaseContext()); } public void testSetSetting() { PasswordSetting setting = new PasswordSetting("unit.test"); setting.setTemplate("nnnn"); settingsManager.setSetting(setting); PasswordSetting checkSetting = settingsManager.getSetting("unit.test"); assertEquals(4, checkSetting.getLength()); assertEquals(4096, checkSetting.getIterations()); settingsManager.deleteSetting(checkSetting.getDomain()); boolean found = false; for (String domain : settingsManager.getDomainList()) { if (domain.equals("unit.test")) { found = true; } } assertFalse(found); } public void testSaveUnsupportedSettings() { PasswordSetting setting = new PasswordSetting("unit.test"); setting.setExtraCharacterSet("ABCKWXkwx345/$#"); setting.setTemplate("ooooooo"); setting.setLegacyPassword("Insecure"); setting.setUsername("hugo"); setting.setSalt("hmpf".getBytes()); setting.setNotes("12 is more than 5."); settingsManager.setSetting(setting); PasswordSetting checkSetting = settingsManager.getSetting("unit.test"); assertEquals("ABCKWXkwx345/$#", checkSetting.getCharacterSetAsString()); assertEquals("Insecure", checkSetting.getLegacyPassword()); assertEquals("hugo", checkSetting.getUsername()); assertEquals("hmpf".getBytes().length, checkSetting.getSalt().length); for (int i = 0; i < checkSetting.getSalt().length; i++) { assertEquals("hmpf".getBytes()[i], checkSetting.getSalt()[i]); } assertEquals("12 is more than 5.", checkSetting.getNotes()); settingsManager.deleteSetting(checkSetting.getDomain()); } private Crypter getSettingsCrypter(KgkManager kgkManager) { byte[] salt2 = kgkManager.getSalt2(); byte[] iv2 = kgkManager.getIv2(); byte[] kgk = kgkManager.getKgk(); byte[] settingsKey = Crypter.createKey(kgk, salt2); byte[] settingsKeyIv = new byte[48]; for (int i = 0; i < settingsKey.length; i++) { settingsKeyIv[i] = settingsKey[i]; settingsKey[i] = 0x00; } System.arraycopy(iv2, 0, settingsKeyIv, settingsKey.length, iv2.length); return new Crypter(settingsKeyIv); } public void testGetBlob() { PasswordSetting setting = new PasswordSetting("unit.test"); setting.setTemplate("nnnn"); settingsManager.setSetting(setting); byte[] password = "some secret".getBytes(); kgkManager.decryptKgk(password, kgkManager.getKgkCrypterSalt(), kgkManager.gelLocalKgkBlock()); byte[] blob = settingsManager.getExportData(kgkManager); assertEquals(0x01, blob[0]); byte[] encryptedSettings = Arrays.copyOfRange(blob, 145, blob.length); for (int i = 0; i < blob.length; i++) { blob[i] = 0x00; } Crypter settingsCrypter = this.getSettingsCrypter(kgkManager); byte[] decrypted = settingsCrypter.decrypt(encryptedSettings); try { JSONObject data = new JSONObject(Packer.decompress(decrypted)); boolean found = false; Iterator<String> keysIterator = data.keys(); while (keysIterator.hasNext()) { JSONObject dataset = data.getJSONObject(keysIterator.next()); if (dataset.getString("domain").equals("unit.test")) { found = true; assertTrue(dataset.has("extras")); assertEquals("#!\"~|@^°$%&/()[]{}=-_+*<>;:.", dataset.getString("extras")); assertTrue(dataset.has("passwordTemplate")); assertEquals("nnnn", dataset.getString("passwordTemplate")); assertTrue(dataset.has("iterations")); assertEquals(4096, dataset.getInt("iterations")); } } assertTrue(found); } catch (JSONException e) { e.printStackTrace(); assertTrue(false); } } public void testUpdateBlob() { PasswordSetting setting = new PasswordSetting("unit.test"); setting.setTemplate("nnnn"); setting.setCreationDate("2001-01-01T02:14:12"); setting.setModificationDate("2001-01-01T02:14:13"); settingsManager.setSetting(setting); byte[] password = "some secret".getBytes(); try { kgkManager.decryptKgk(password, kgkManager.getKgkCrypterSalt(), kgkManager.gelLocalKgkBlock()); byte[] blob = settingsManager.getExportData(kgkManager); byte[] encryptedSettings = Arrays.copyOfRange(blob, 145, blob.length); for (int i = 0; i < blob.length; i++) { blob[i] = 0x00; } Crypter settingsCrypter = this.getSettingsCrypter(kgkManager); byte[] decrypted = settingsCrypter.decrypt(encryptedSettings); JSONObject data = new JSONObject(Packer.decompress(decrypted)); JSONObject remoteDataset = new JSONObject(); remoteDataset.put("domain", "unit.test"); remoteDataset.put("length", 12); remoteDataset.put("iterations", 4097); remoteDataset.put("usedCharacters", "0123456789"); remoteDataset.put("mDate", "2012-04-13T11:45:10"); Iterator<String> keysIterator = data.keys(); while (keysIterator.hasNext()) { String domain = keysIterator.next(); if (remoteDataset.getString("domain").equals( data.getJSONObject(domain).getString("domain"))) { data.put(domain, remoteDataset); } } byte[] encryptedData = settingsCrypter.encrypt(Packer.compress(data.toString())); byte[] salt = kgkManager.getKgkCrypterSalt(); byte[] kgkBlock = kgkManager.getEncryptedKgk(); byte[] remoteBlob = new byte[1 + salt.length + kgkBlock.length + encryptedData.length]; remoteBlob[0] = 0x01; System.arraycopy(salt, 0, remoteBlob, 1, salt.length); for (int i = 0; i < kgkBlock.length; i++) { remoteBlob[1 + salt.length + i] = kgkBlock[i]; } for (int i = 0; i < encryptedData.length; i++) { remoteBlob[1 + salt.length + kgkBlock.length + i] = encryptedData[i]; } settingsManager.updateFromExportData(kgkManager, remoteBlob); PasswordSetting updated = settingsManager.getSetting("unit.test"); assertEquals("2012-04-13T11:45:10", updated.getModificationDate()); assertEquals("2001-01-01T02:14:12", updated.getCreationDate()); assertEquals(4097, updated.getIterations()); assertEquals(12, updated.getLength()); } catch (JSONException e) { e.printStackTrace(); assertTrue(false); } settingsManager.deleteSetting("unit.test"); } public void testSetAllSettingsToSynced() { PasswordSetting setting = new PasswordSetting("unit.test"); setting.setTemplate("nnnn"); setting.setCreationDate("2001-01-01T02:14:12"); setting.setModificationDate("2001-01-01T02:14:13"); settingsManager.setSetting(setting); assertFalse(setting.isSynced()); String[] domainList = settingsManager.getDomainList(); PasswordSetting[] allSettings = new PasswordSetting[domainList.length]; for (int i = 0; i < domainList.length; i++) { allSettings[i] = settingsManager.getSetting(domainList[i]); } settingsManager.setAllSettingsToSynced(); assertTrue(settingsManager.getSetting("unit.test").isSynced()); for (String domain : domainList) { assertTrue(settingsManager.getSetting(domain).isSynced()); } // restoring for (PasswordSetting s : allSettings) { settingsManager.setSetting(s); } settingsManager.deleteSetting("unit.test"); } public void testSaveAndLoadLocally() { PasswordSetting setting = new PasswordSetting("unit.test"); setting.setTemplate("nnnn"); setting.setCreationDate("2001-01-01T02:14:12"); setting.setModificationDate("2001-01-01T02:14:13"); settingsManager.setSetting(setting); byte[] password = "some secret".getBytes(); kgkManager.decryptKgk(password, kgkManager.getKgkCrypterSalt(), kgkManager.gelLocalKgkBlock()); settingsManager.storeLocalSettings(kgkManager); PasswordSettingsManager settingsManager2 = new PasswordSettingsManager( getActivity().getBaseContext()); try { settingsManager2.loadLocalSettings(kgkManager); } catch (WrongPasswordException ex) { ex.printStackTrace(); assertTrue(false); } PasswordSetting setting2 = settingsManager2.getSetting("unit.test"); assertEquals(setting.getLength(), setting2.getLength()); assertEquals("2001-01-01T02:14:12", setting2.getCreationDate()); assertEquals("2001-01-01T02:14:13", setting2.getModificationDate()); } }