blob: fd8b319b74ca4d677b82f28d8730b5d6d90564b4 [file] [log] [blame]
Robert Berryce50cd32017-12-07 14:33:54 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Robert Berry5397d4d2017-12-12 13:22:00 +000017package com.android.server.locksettings.recoverablekeystore;
Robert Berryce50cd32017-12-07 14:33:54 +000018
Robert Berrycfc990a2017-12-22 15:54:30 +000019import static junit.framework.Assert.assertNotNull;
Robert Berryce50cd32017-12-07 14:33:54 +000020
Robert Berrya244b2e2017-12-19 10:44:56 +000021import static org.junit.Assert.assertArrayEquals;
Robert Berrycfc990a2017-12-22 15:54:30 +000022import static org.junit.Assert.assertEquals;
Robert Berrya244b2e2017-12-19 10:44:56 +000023
24import android.content.Context;
Robert Berryce50cd32017-12-07 14:33:54 +000025import android.security.keystore.AndroidKeyStoreSecretKey;
26import android.security.keystore.KeyGenParameterSpec;
27import android.security.keystore.KeyProperties;
Robert Berrya244b2e2017-12-19 10:44:56 +000028import android.support.test.InstrumentationRegistry;
Robert Berryce50cd32017-12-07 14:33:54 +000029import android.support.test.filters.SmallTest;
30import android.support.test.runner.AndroidJUnit4;
31
Robert Berrya244b2e2017-12-19 10:44:56 +000032import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
33
Robert Berryce50cd32017-12-07 14:33:54 +000034import org.junit.After;
35import org.junit.Before;
36import org.junit.Test;
37import org.junit.runner.RunWith;
Robert Berryce50cd32017-12-07 14:33:54 +000038
Robert Berrya244b2e2017-12-19 10:44:56 +000039import java.io.File;
40import java.nio.charset.StandardCharsets;
Robert Berryce50cd32017-12-07 14:33:54 +000041import java.security.KeyStore;
Bo Zhu2c8e5382018-02-26 15:54:25 -080042import java.util.Random;
Robert Berryce50cd32017-12-07 14:33:54 +000043
Robert Berrya244b2e2017-12-19 10:44:56 +000044import javax.crypto.Cipher;
Robert Berryce50cd32017-12-07 14:33:54 +000045import javax.crypto.KeyGenerator;
Robert Berrya244b2e2017-12-19 10:44:56 +000046import javax.crypto.spec.GCMParameterSpec;
Robert Berryce50cd32017-12-07 14:33:54 +000047
48@SmallTest
49@RunWith(AndroidJUnit4.class)
50public class RecoverableKeyGeneratorTest {
Robert Berrya244b2e2017-12-19 10:44:56 +000051 private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
Robert Berry67b228c2017-12-18 19:26:22 +000052 private static final int TEST_GENERATION_ID = 3;
Robert Berryce50cd32017-12-07 14:33:54 +000053 private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
54 private static final String KEY_ALGORITHM = "AES";
Bo Zhu2c8e5382018-02-26 15:54:25 -080055 private static final int KEY_SIZE_BYTES = RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE;
Robert Berrycfc990a2017-12-22 15:54:30 +000056 private static final String KEY_WRAP_ALGORITHM = "AES/GCM/NoPadding";
Robert Berryce50cd32017-12-07 14:33:54 +000057 private static final String TEST_ALIAS = "karlin";
58 private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
Robert Berryb7c06ea2017-12-21 13:37:23 +000059 private static final int TEST_USER_ID = 1000;
Robert Berrya244b2e2017-12-19 10:44:56 +000060 private static final int KEYSTORE_UID_SELF = -1;
61 private static final int GCM_TAG_LENGTH_BITS = 128;
Robert Berryce50cd32017-12-07 14:33:54 +000062
Robert Berry67b228c2017-12-18 19:26:22 +000063 private PlatformEncryptionKey mPlatformKey;
Robert Berrya244b2e2017-12-19 10:44:56 +000064 private PlatformDecryptionKey mDecryptKey;
65 private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
66 private File mDatabaseFile;
Robert Berryce50cd32017-12-07 14:33:54 +000067 private RecoverableKeyGenerator mRecoverableKeyGenerator;
68
69 @Before
70 public void setUp() throws Exception {
Robert Berrya244b2e2017-12-19 10:44:56 +000071 Context context = InstrumentationRegistry.getTargetContext();
72 mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
73 mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
Robert Berryce50cd32017-12-07 14:33:54 +000074
Bo Zhu2c8e5382018-02-26 15:54:25 -080075 AndroidKeyStoreSecretKey platformKey = generatePlatformKey();
Robert Berrya244b2e2017-12-19 10:44:56 +000076 mPlatformKey = new PlatformEncryptionKey(TEST_GENERATION_ID, platformKey);
77 mDecryptKey = new PlatformDecryptionKey(TEST_GENERATION_ID, platformKey);
78 mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mRecoverableKeyStoreDb);
Robert Berryce50cd32017-12-07 14:33:54 +000079 }
80
81 @After
82 public void tearDown() throws Exception {
83 KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
84 keyStore.load(/*param=*/ null);
85 keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
Robert Berrya244b2e2017-12-19 10:44:56 +000086
87 mRecoverableKeyStoreDb.close();
88 mDatabaseFile.delete();
Robert Berryce50cd32017-12-07 14:33:54 +000089 }
90
91 @Test
Robert Berryce50cd32017-12-07 14:33:54 +000092 public void generateAndStoreKey_storesWrappedKey() throws Exception {
Robert Berryb7c06ea2017-12-21 13:37:23 +000093 mRecoverableKeyGenerator.generateAndStoreKey(
94 mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
Robert Berryce50cd32017-12-07 14:33:54 +000095
Robert Berrya244b2e2017-12-19 10:44:56 +000096 WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
Robert Berrycfc990a2017-12-22 15:54:30 +000097 assertNotNull(wrappedKey);
98 }
Robert Berryce50cd32017-12-07 14:33:54 +000099
Robert Berrycfc990a2017-12-22 15:54:30 +0000100 @Test
101 public void generateAndStoreKey_returnsRawMaterialOfCorrectLength() throws Exception {
102 byte[] rawKey = mRecoverableKeyGenerator.generateAndStoreKey(
103 mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
104
105 assertEquals(KEY_SIZE_BYTES, rawKey.length);
106 }
107
108 @Test
109 public void generateAndStoreKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
110 byte[] rawMaterial = mRecoverableKeyGenerator.generateAndStoreKey(
111 mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
112
113 WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
114 Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
115 cipher.init(Cipher.DECRYPT_MODE, mDecryptKey.getKey(),
116 new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
117 byte[] unwrappedMaterial = cipher.doFinal(wrappedKey.getKeyMaterial());
118 assertArrayEquals(rawMaterial, unwrappedMaterial);
Robert Berryce50cd32017-12-07 14:33:54 +0000119 }
120
Bo Zhu2c8e5382018-02-26 15:54:25 -0800121 @Test
122 public void importKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
123 byte[] rawMaterial = randomBytes(KEY_SIZE_BYTES);
124 mRecoverableKeyGenerator.importKey(
125 mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial);
126
127 WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
128 Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
129 cipher.init(Cipher.DECRYPT_MODE, mDecryptKey.getKey(),
130 new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
131 byte[] unwrappedMaterial = cipher.doFinal(wrappedKey.getKeyMaterial());
132 assertArrayEquals(rawMaterial, unwrappedMaterial);
133 }
134
135 private AndroidKeyStoreSecretKey generatePlatformKey() throws Exception {
Robert Berryce50cd32017-12-07 14:33:54 +0000136 KeyGenerator keyGenerator = KeyGenerator.getInstance(
137 KEY_ALGORITHM,
138 ANDROID_KEY_STORE_PROVIDER);
139 keyGenerator.init(new KeyGenParameterSpec.Builder(
140 WRAPPING_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
141 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
142 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
143 .build());
144 return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
145 }
Robert Berrya244b2e2017-12-19 10:44:56 +0000146
147 private static byte[] getUtf8Bytes(String s) {
148 return s.getBytes(StandardCharsets.UTF_8);
149 }
Bo Zhu2c8e5382018-02-26 15:54:25 -0800150
151 private static byte[] randomBytes(int n) {
152 byte[] bytes = new byte[n];
153 new Random().nextBytes(bytes);
154 return bytes;
155 }
Robert Berryce50cd32017-12-07 14:33:54 +0000156}