summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Robert Berry <robertberry@google.com> 2017-12-18 14:50:23 +0000
committer Robert Berry <robertberry@google.com> 2017-12-20 15:50:46 +0000
commitcbd4b2f46fda2cd2ea81b60e341ea64dab1d8b9d (patch)
treeeb2de090b88dc7f6569b33355004f0cf4b19331f
parent13eec4697c376a45531b4c0638f313281407f9b7 (diff)
Add tests for KeySyncUtils now that SecureBox is available
SecureBox is to be merged before this. Test: adb shell am instrument -w -e package com.android.server.locksettings.recoverablekeystore com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Change-Id: I40f783c165faa595c8913ff073915726ae71524d
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java213
2 files changed, 215 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index 37aeb3af051e..e2ba8aa4b1bc 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -112,7 +112,8 @@ public class KeySyncUtils {
* @throws NoSuchAlgorithmException if any SecureBox algorithm is unavailable.
* @throws InvalidKeyException if the hash cannot be used to encrypt for some reason.
*/
- private static byte[] locallyEncryptRecoveryKey(byte[] lockScreenHash, SecretKey recoveryKey)
+ @VisibleForTesting
+ static byte[] locallyEncryptRecoveryKey(byte[] lockScreenHash, SecretKey recoveryKey)
throws NoSuchAlgorithmException, InvalidKeyException {
return SecureBox.encrypt(
/*theirPublicKey=*/ null,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
index ac3abedba7f3..c328dda68389 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
@@ -16,6 +16,8 @@
package com.android.server.locksettings.recoverablekeystore;
+import static junit.framework.Assert.fail;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -23,13 +25,20 @@ import static org.junit.Assert.assertFalse;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.google.common.collect.ImmutableMap;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
import java.security.MessageDigest;
import java.util.Arrays;
+import java.util.Map;
+import java.util.Random;
+import javax.crypto.AEADBadTagException;
+import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@SmallTest
@@ -39,6 +48,13 @@ public class KeySyncUtilsTest {
private static final int THM_KF_HASH_SIZE = 256;
private static final int KEY_CLAIMANT_LENGTH_BYTES = 16;
private static final String SHA_256_ALGORITHM = "SHA-256";
+ private static final String APPLICATION_KEY_ALGORITHM = "AES";
+ private static final byte[] LOCK_SCREEN_HASH_1 =
+ utf8Bytes("g09TEvo6XqVdNaYdRggzn5w2C5rCeE1F");
+ private static final byte[] LOCK_SCREEN_HASH_2 =
+ utf8Bytes("snQzsbvclkSsG6PwasAp1oFLzbq3KtFe");
+ private static final byte[] RECOVERY_CLAIM_HEADER =
+ "V1 KF_claim".getBytes(StandardCharsets.UTF_8);
@Test
public void calculateThmKfHash_isShaOfLockScreenHashWithPrefix() throws Exception {
@@ -97,6 +113,197 @@ public class KeySyncUtilsTest {
utf8Bytes("!")));
}
+ @Test
+ public void decryptApplicationKey_decryptsAnApplicationKeyEncryptedWithSecureBox()
+ throws Exception {
+ String alias = "phoebe";
+ SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+ SecretKey applicationKey = generateApplicationKey();
+ Map<String, byte[]> encryptedKeys =
+ KeySyncUtils.encryptKeysWithRecoveryKey(
+ recoveryKey, ImmutableMap.of(alias, applicationKey));
+ byte[] encryptedKey = encryptedKeys.get(alias);
+
+ byte[] keyMaterial =
+ KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(), encryptedKey);
+
+ assertArrayEquals(applicationKey.getEncoded(), keyMaterial);
+ }
+
+ @Test
+ public void decryptApplicationKey_throwsIfUnableToDecrypt() throws Exception {
+ String alias = "casper";
+ Map<String, byte[]> encryptedKeys =
+ KeySyncUtils.encryptKeysWithRecoveryKey(
+ KeySyncUtils.generateRecoveryKey(),
+ ImmutableMap.of("casper", generateApplicationKey()));
+ byte[] encryptedKey = encryptedKeys.get(alias);
+
+ try {
+ KeySyncUtils.decryptApplicationKey(
+ KeySyncUtils.generateRecoveryKey().getEncoded(), encryptedKey);
+ fail("Did not throw decrypting with bad key.");
+ } catch (AEADBadTagException error) {
+ // expected
+ }
+ }
+
+ @Test
+ public void decryptRecoveryKey_decryptsALocallyEncryptedKey() throws Exception {
+ SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+ byte[] encrypted = KeySyncUtils.locallyEncryptRecoveryKey(
+ LOCK_SCREEN_HASH_1, recoveryKey);
+
+ byte[] keyMaterial = KeySyncUtils.decryptRecoveryKey(LOCK_SCREEN_HASH_1, encrypted);
+
+ assertArrayEquals(recoveryKey.getEncoded(), keyMaterial);
+ }
+
+ @Test
+ public void decryptRecoveryKey_throwsIfCannotDecrypt() throws Exception {
+ SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+ byte[] encrypted = KeySyncUtils.locallyEncryptRecoveryKey(LOCK_SCREEN_HASH_1, recoveryKey);
+
+ try {
+ KeySyncUtils.decryptRecoveryKey(LOCK_SCREEN_HASH_2, encrypted);
+ fail("Did not throw decrypting with bad key.");
+ } catch (AEADBadTagException error) {
+ // expected
+ }
+ }
+
+ @Test
+ public void encryptRecoveryClaim_encryptsLockScreenAndKeyClaimant() throws Exception {
+ KeyPair keyPair = SecureBox.genKeyPair();
+ byte[] keyClaimant = KeySyncUtils.generateKeyClaimant();
+ byte[] challenge = randomBytes(32);
+ byte[] vaultParams = randomBytes(100);
+
+ byte[] encryptedRecoveryClaim = KeySyncUtils.encryptRecoveryClaim(
+ keyPair.getPublic(),
+ vaultParams,
+ challenge,
+ LOCK_SCREEN_HASH_1,
+ keyClaimant);
+
+ byte[] decrypted = SecureBox.decrypt(
+ keyPair.getPrivate(),
+ /*sharedSecret=*/ null,
+ /*header=*/ KeySyncUtils.concat(RECOVERY_CLAIM_HEADER, vaultParams, challenge),
+ encryptedRecoveryClaim);
+ assertArrayEquals(KeySyncUtils.concat(LOCK_SCREEN_HASH_1, keyClaimant), decrypted);
+ }
+
+ @Test
+ public void encryptRecoveryClaim_cannotBeDecryptedWithoutChallenge() throws Exception {
+ KeyPair keyPair = SecureBox.genKeyPair();
+ byte[] keyClaimant = KeySyncUtils.generateKeyClaimant();
+ byte[] vaultParams = randomBytes(100);
+
+ byte[] encryptedRecoveryClaim = KeySyncUtils.encryptRecoveryClaim(
+ keyPair.getPublic(),
+ vaultParams,
+ /*challenge=*/ randomBytes(32),
+ LOCK_SCREEN_HASH_1,
+ keyClaimant);
+
+ try {
+ SecureBox.decrypt(
+ keyPair.getPrivate(),
+ /*sharedSecret=*/ null,
+ /*header=*/ KeySyncUtils.concat(
+ RECOVERY_CLAIM_HEADER, vaultParams, randomBytes(32)),
+ encryptedRecoveryClaim);
+ fail("Should throw if challenge is incorrect.");
+ } catch (AEADBadTagException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void encryptRecoveryClaim_cannotBeDecryptedWithoutCorrectSecretKey() throws Exception {
+ byte[] keyClaimant = KeySyncUtils.generateKeyClaimant();
+ byte[] challenge = randomBytes(32);
+ byte[] vaultParams = randomBytes(100);
+
+ byte[] encryptedRecoveryClaim = KeySyncUtils.encryptRecoveryClaim(
+ SecureBox.genKeyPair().getPublic(),
+ vaultParams,
+ challenge,
+ LOCK_SCREEN_HASH_1,
+ keyClaimant);
+
+ try {
+ SecureBox.decrypt(
+ SecureBox.genKeyPair().getPrivate(),
+ /*sharedSecret=*/ null,
+ /*header=*/ KeySyncUtils.concat(
+ RECOVERY_CLAIM_HEADER, vaultParams, challenge),
+ encryptedRecoveryClaim);
+ fail("Should throw if secret key is incorrect.");
+ } catch (AEADBadTagException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void encryptRecoveryClaim_cannotBeDecryptedWithoutCorrectVaultParams() throws Exception {
+ KeyPair keyPair = SecureBox.genKeyPair();
+ byte[] keyClaimant = KeySyncUtils.generateKeyClaimant();
+ byte[] challenge = randomBytes(32);
+
+ byte[] encryptedRecoveryClaim = KeySyncUtils.encryptRecoveryClaim(
+ keyPair.getPublic(),
+ /*vaultParams=*/ randomBytes(100),
+ challenge,
+ LOCK_SCREEN_HASH_1,
+ keyClaimant);
+
+ try {
+ SecureBox.decrypt(
+ keyPair.getPrivate(),
+ /*sharedSecret=*/ null,
+ /*header=*/ KeySyncUtils.concat(
+ RECOVERY_CLAIM_HEADER, randomBytes(100), challenge),
+ encryptedRecoveryClaim);
+ fail("Should throw if vault params is incorrect.");
+ } catch (AEADBadTagException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void encryptRecoveryClaim_cannotBeDecryptedWithoutCorrectHeader() throws Exception {
+ KeyPair keyPair = SecureBox.genKeyPair();
+ byte[] keyClaimant = KeySyncUtils.generateKeyClaimant();
+ byte[] challenge = randomBytes(32);
+ byte[] vaultParams = randomBytes(100);
+
+ byte[] encryptedRecoveryClaim = KeySyncUtils.encryptRecoveryClaim(
+ keyPair.getPublic(),
+ vaultParams,
+ challenge,
+ LOCK_SCREEN_HASH_1,
+ keyClaimant);
+
+ try {
+ SecureBox.decrypt(
+ keyPair.getPrivate(),
+ /*sharedSecret=*/ null,
+ /*header=*/ KeySyncUtils.concat(randomBytes(10), vaultParams, challenge),
+ encryptedRecoveryClaim);
+ fail("Should throw if header is incorrect.");
+ } catch (AEADBadTagException e) {
+ // expected
+ }
+ }
+
+ private static byte[] randomBytes(int n) {
+ byte[] bytes = new byte[n];
+ new Random().nextBytes(bytes);
+ return bytes;
+ }
+
private static byte[] utf8Bytes(String s) {
return s.getBytes(StandardCharsets.UTF_8);
}
@@ -106,4 +313,10 @@ public class KeySyncUtilsTest {
messageDigest.update(bytes);
return messageDigest.digest();
}
+
+ private static SecretKey generateApplicationKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(APPLICATION_KEY_ALGORITHM);
+ keyGenerator.init(/*keySize=*/ 256);
+ return keyGenerator.generateKey();
+ }
}