Revert "Add platform key generation ID to WrappedKey instances"

This reverts commit 9fa18c621e.

Reason for revert: broke the build, sorry

Change-Id: I6425160e9ac565664e25ee5c92ce1a5813dd4c28
This commit is contained in:
Robert Berry
2017-12-18 18:56:22 +00:00
parent 9fa18c621e
commit fd58c9bca2
5 changed files with 33 additions and 109 deletions

View File

@@ -1,62 +0,0 @@
/*
* 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 android.security.keystore.AndroidKeyStoreSecretKey;
/**
* Private key stored in AndroidKeyStore. Used to wrap recoverable keys before writing them to disk.
*
* <p>Identified by a generation ID, which increments whenever a new platform key is generated. A
* new key must be generated whenever the user disables their lock screen, as the decryption key is
* tied to lock-screen authentication.
*
* <p>One current platform key exists per profile on the device. (As each must be tied to a
* different user's lock screen.)
*
* @hide
*/
public class PlatformEncryptionKey {
private final int mGenerationId;
private final AndroidKeyStoreSecretKey mKey;
/**
* A new instance.
*
* @param generationId The generation ID of the key.
* @param key The secret key handle. Can be used to encrypt WITHOUT requiring screen unlock.
*/
public PlatformEncryptionKey(int generationId, AndroidKeyStoreSecretKey key) {
mGenerationId = generationId;
mKey = key;
}
/**
* Returns the generation ID of the key.
*/
public int getGenerationId() {
return mGenerationId;
}
/**
* Returns the actual key, which can only be used to encrypt.
*/
public AndroidKeyStoreSecretKey getKey() {
return mKey;
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server.locksettings.recoverablekeystore;
import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.util.Log;
@@ -55,7 +56,7 @@ public class RecoverableKeyGenerator {
* @hide
*/
public static RecoverableKeyGenerator newInstance(
PlatformEncryptionKey platformKey, RecoverableKeyStorage recoverableKeyStorage)
AndroidKeyStoreSecretKey platformKey, RecoverableKeyStorage recoverableKeyStorage)
throws NoSuchAlgorithmException {
// NB: This cannot use AndroidKeyStore as the provider, as we need access to the raw key
// material, so that it can be synced to disk in encrypted form.
@@ -65,11 +66,11 @@ public class RecoverableKeyGenerator {
private final KeyGenerator mKeyGenerator;
private final RecoverableKeyStorage mRecoverableKeyStorage;
private final PlatformEncryptionKey mPlatformKey;
private final AndroidKeyStoreSecretKey mPlatformKey;
private RecoverableKeyGenerator(
KeyGenerator keyGenerator,
PlatformEncryptionKey platformKey,
AndroidKeyStoreSecretKey platformKey,
RecoverableKeyStorage recoverableKeyStorage) {
mKeyGenerator = keyGenerator;
mRecoverableKeyStorage = recoverableKeyStorage;

View File

@@ -44,7 +44,6 @@ public class WrappedKey {
private static final String APPLICATION_KEY_ALGORITHM = "AES";
private static final int GCM_TAG_LENGTH_BITS = 128;
private final int mPlatformKeyGenerationId;
private final byte[] mNonce;
private final byte[] mKeyMaterial;
@@ -56,8 +55,8 @@ public class WrappedKey {
* {@link android.security.keystore.AndroidKeyStoreKey} for an example of a key that does
* not expose its key material.
*/
public static WrappedKey fromSecretKey(PlatformEncryptionKey wrappingKey, SecretKey key)
throws InvalidKeyException, KeyStoreException {
public static WrappedKey fromSecretKey(
SecretKey wrappingKey, SecretKey key) throws InvalidKeyException, KeyStoreException {
if (key.getEncoded() == null) {
throw new InvalidKeyException(
"key does not expose encoded material. It cannot be wrapped.");
@@ -71,7 +70,7 @@ public class WrappedKey {
"Android does not support AES/GCM/NoPadding. This should never happen.");
}
cipher.init(Cipher.WRAP_MODE, wrappingKey.getKey());
cipher.init(Cipher.WRAP_MODE, wrappingKey);
byte[] encryptedKeyMaterial;
try {
encryptedKeyMaterial = cipher.wrap(key);
@@ -91,10 +90,7 @@ public class WrappedKey {
}
}
return new WrappedKey(
/*nonce=*/ cipher.getIV(),
/*keyMaterial=*/ encryptedKeyMaterial,
/*platformKeyGenerationId=*/ wrappingKey.getGenerationId());
return new WrappedKey(/*mNonce=*/ cipher.getIV(), /*mKeyMaterial=*/ encryptedKeyMaterial);
}
/**
@@ -102,14 +98,12 @@ public class WrappedKey {
*
* @param nonce The nonce with which the key material was encrypted.
* @param keyMaterial The encrypted bytes of the key material.
* @param platformKeyGenerationId The generation ID of the key used to wrap this key.
*
* @hide
*/
public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) {
public WrappedKey(byte[] nonce, byte[] keyMaterial) {
mNonce = nonce;
mKeyMaterial = keyMaterial;
mPlatformKeyGenerationId = platformKeyGenerationId;
}
/**
@@ -130,13 +124,15 @@ public class WrappedKey {
return mKeyMaterial;
}
/**
* Returns the generation ID of the platform key, with which this key was wrapped.
*
* @hide
*/
public int getPlatformKeyGenerationId() {
return mPlatformKeyGenerationId;
// TODO(robertberry) Implement. See ag/3362855.
return 1;
}
/**

View File

@@ -48,24 +48,24 @@ import javax.crypto.SecretKey;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RecoverableKeyGeneratorTest {
private static final int TEST_GENERATION_ID = 3;
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;
@Mock
RecoverableKeyStorage mRecoverableKeyStorage;
@Captor ArgumentCaptor<KeyProtection> mKeyProtectionArgumentCaptor;
private PlatformEncryptionKey mPlatformKey;
private AndroidKeyStoreSecretKey mPlatformKey;
private SecretKey mKeyHandle;
private RecoverableKeyGenerator mRecoverableKeyGenerator;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mPlatformKey = new PlatformEncryptionKey(TEST_GENERATION_ID, generateAndroidKeyStoreKey());
mPlatformKey = generateAndroidKeyStoreKey();
mKeyHandle = generateKey();
mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(
mPlatformKey, mRecoverableKeyStorage);

View File

@@ -61,8 +61,7 @@ public class WrappedKeyTest {
@Test
public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped() throws Exception {
PlatformEncryptionKey wrappingKey = new PlatformEncryptionKey(
GENERATION_ID, generateAndroidKeyStoreKey());
SecretKey wrappingKey = generateAndroidKeyStoreKey();
SecretKey rawKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
@@ -70,36 +69,23 @@ public class WrappedKeyTest {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(
Cipher.UNWRAP_MODE,
wrappingKey.getKey(),
wrappingKey,
new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
SecretKey unwrappedKey = (SecretKey) cipher.unwrap(
wrappedKey.getKeyMaterial(), KEY_ALGORITHM, Cipher.SECRET_KEY);
assertEquals(rawKey, unwrappedKey);
}
@Test
public void fromSecretKey_returnsAKeyWithTheGenerationIdOfTheWrappingKey() throws Exception {
PlatformEncryptionKey wrappingKey = new PlatformEncryptionKey(
GENERATION_ID, generateAndroidKeyStoreKey());
SecretKey rawKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
assertEquals(GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
}
@Test
public void decryptWrappedKeys_decryptsWrappedKeys() throws Exception {
String alias = "karlin";
AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
PlatformDecryptionKey platformKey = generatePlatformDecryptionKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey);
WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey.getKey(), appKey);
HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
keysByAlias.put(alias, wrappedKey);
Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(
new PlatformDecryptionKey(GENERATION_ID, platformKey), keysByAlias);
Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(platformKey, keysByAlias);
assertEquals(1, unwrappedKeys.size());
assertTrue(unwrappedKeys.containsKey(alias));
@@ -109,31 +95,26 @@ public class WrappedKeyTest {
@Test
public void decryptWrappedKeys_doesNotDieIfSomeKeysAreUnwrappable() throws Exception {
String alias = "karlin";
AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
SecretKey appKey = generateKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey);
WrappedKey wrappedKey = WrappedKey.fromSecretKey(generateKey(), appKey);
HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
keysByAlias.put(alias, wrappedKey);
Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(
new PlatformDecryptionKey(GENERATION_ID, platformKey), keysByAlias);
generatePlatformDecryptionKey(), keysByAlias);
assertEquals(0, unwrappedKeys.size());
}
@Test
public void decryptWrappedKeys_throwsIfPlatformKeyGenerationIdDoesNotMatch() throws Exception {
AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
WrappedKey wrappedKey = WrappedKey.fromSecretKey(
new PlatformEncryptionKey(GENERATION_ID, platformKey), generateKey());
WrappedKey wrappedKey = WrappedKey.fromSecretKey(generateKey(), generateKey());
HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
keysByAlias.put("benji", wrappedKey);
try {
WrappedKey.unwrapKeys(
new PlatformDecryptionKey(/*generationId=*/ 2, platformKey),
keysByAlias);
generatePlatformDecryptionKey(/*generationId=*/ 2), keysByAlias);
fail("Should have thrown.");
} catch (BadPlatformKeyException e) {
assertEquals(
@@ -161,4 +142,12 @@ public class WrappedKeyTest {
.build());
return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
}
private PlatformDecryptionKey generatePlatformDecryptionKey() throws Exception {
return generatePlatformDecryptionKey(GENERATION_ID);
}
private PlatformDecryptionKey generatePlatformDecryptionKey(int generationId) throws Exception {
return new PlatformDecryptionKey(generationId, generateAndroidKeyStoreKey());
}
}