Move recoverablekeystore package under services

As these helpers will be used by the service, these properly belong there.

Test: Unit tests.
Change-Id: I4fb4fe2ed52581790421885680473a7b9638f332
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
new file mode 100644
index 0000000..298a988
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.security.KeyStore;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverableKeyGeneratorTest {
+    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String TEST_ALIAS = "karlin";
+    private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
+
+    @Mock
+    RecoverableKeyStorage mRecoverableKeyStorage;
+
+    @Captor ArgumentCaptor<KeyProtection> mKeyProtectionArgumentCaptor;
+
+    private AndroidKeyStoreSecretKey mPlatformKey;
+    private SecretKey mKeyHandle;
+    private RecoverableKeyGenerator mRecoverableKeyGenerator;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mPlatformKey = generateAndroidKeyStoreKey();
+        mKeyHandle = generateKey();
+        mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(
+                mPlatformKey, mRecoverableKeyStorage);
+
+        when(mRecoverableKeyStorage.loadFromAndroidKeyStore(any())).thenReturn(mKeyHandle);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+        keyStore.load(/*param=*/ null);
+        keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+    }
+
+    @Test
+    public void generateAndStoreKey_setsKeyInKeyStore() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        verify(mRecoverableKeyStorage, times(1))
+                .importIntoAndroidKeyStore(eq(TEST_ALIAS), any(), any());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesKeyEnabledForEncryptDecrypt() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        KeyProtection keyProtection = getKeyProtectionUsed();
+        assertEquals(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
+                keyProtection.getPurposes());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesKeyEnabledForGCM() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        KeyProtection keyProtection = getKeyProtectionUsed();
+        assertArrayEquals(new String[] { KeyProperties.BLOCK_MODE_GCM },
+                keyProtection.getBlockModes());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesKeyEnabledForNoPadding() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        KeyProtection keyProtection = getKeyProtectionUsed();
+        assertArrayEquals(new String[] { KeyProperties.ENCRYPTION_PADDING_NONE },
+                keyProtection.getEncryptionPaddings());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesWrappedKey() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        verify(mRecoverableKeyStorage, times(1)).persistToDisk(eq(TEST_ALIAS), any());
+    }
+
+    @Test
+    public void generateAndStoreKey_returnsKeyHandle() throws Exception {
+        SecretKey secretKey = mRecoverableKeyGenerator.generateAndStoreKey(TEST_ALIAS);
+
+        assertEquals(mKeyHandle, secretKey);
+    }
+
+    private KeyProtection getKeyProtectionUsed() throws Exception {
+        verify(mRecoverableKeyStorage, times(1)).importIntoAndroidKeyStore(
+                any(), any(), mKeyProtectionArgumentCaptor.capture());
+        return mKeyProtectionArgumentCaptor.getValue();
+    }
+
+    private SecretKey generateKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+        keyGenerator.init(/*keySize=*/ 256);
+        return keyGenerator.generateKey();
+    }
+
+    private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                KEY_ALGORITHM,
+                ANDROID_KEY_STORE_PROVIDER);
+        keyGenerator.init(new KeyGenParameterSpec.Builder(
+                WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .build());
+        return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
new file mode 100644
index 0000000..4cd5631
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore;
+
+import static org.junit.Assert.assertEquals;
+
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.security.KeyStore;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WrappedKeyTest {
+    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+    private static final String WRAPPING_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
+    private static final int GCM_TAG_LENGTH_BYTES = 16;
+    private static final int BITS_PER_BYTE = 8;
+    private static final int GCM_TAG_LENGTH_BITS = GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE;
+
+    @After
+    public void tearDown() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
+        keyStore.load(/*param=*/ null);
+        keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+    }
+
+    @Test
+    public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped() throws Exception {
+        SecretKey wrappingKey = generateAndroidKeyStoreKey();
+        SecretKey rawKey = generateKey();
+
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(
+                Cipher.UNWRAP_MODE,
+                wrappingKey,
+                new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
+        SecretKey unwrappedKey = (SecretKey) cipher.unwrap(
+                wrappedKey.getKeyMaterial(), KEY_ALGORITHM, Cipher.SECRET_KEY);
+        assertEquals(rawKey, unwrappedKey);
+    }
+
+    private SecretKey generateKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+        keyGenerator.init(/*keySize=*/ 256);
+        return keyGenerator.generateKey();
+    }
+
+    private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                KEY_ALGORITHM,
+                ANDROID_KEY_STORE_PROVIDER);
+        keyGenerator.init(new KeyGenParameterSpec.Builder(
+                WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                .build());
+        return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+    }
+}