1 /* 2 * Copyright (C) 2019 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 17 package com.android.server.locksettings; 18 19 import static org.hamcrest.CoreMatchers.is; 20 import static org.junit.Assert.assertThat; 21 22 import android.platform.test.annotations.Presubmit; 23 24 import androidx.test.filters.SmallTest; 25 import androidx.test.runner.AndroidJUnit4; 26 27 import org.junit.Before; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 31 import java.io.ByteArrayOutputStream; 32 import java.io.DataOutputStream; 33 34 import javax.crypto.SecretKey; 35 import javax.crypto.spec.SecretKeySpec; 36 37 /** 38 * atest FrameworksServicesTests:RebootEscrowDataTest 39 */ 40 @SmallTest 41 @Presubmit 42 @RunWith(AndroidJUnit4.class) 43 public class RebootEscrowDataTest { 44 private RebootEscrowKey mKey; 45 private SecretKey mKeyStoreEncryptionKey; 46 47 // Hex encoding of a randomly generated AES key for test. 48 private static final byte[] TEST_AES_KEY = new byte[] { 49 0x44, 0x74, 0x61, 0x54, 0x29, 0x74, 0x37, 0x61, 50 0x48, 0x19, 0x12, 0x54, 0x13, 0x13, 0x52, 0x31, 51 0x70, 0x70, 0x75, 0x25, 0x27, 0x31, 0x49, 0x09, 52 0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23, 53 }; 54 55 @Before generateKey()56 public void generateKey() throws Exception { 57 mKey = RebootEscrowKey.generate(); 58 mKeyStoreEncryptionKey = new SecretKeySpec(TEST_AES_KEY, "AES"); 59 } 60 getTestSp()61 private static byte[] getTestSp() { 62 byte[] testSp = new byte[10]; 63 for (int i = 0; i < testSp.length; i++) { 64 testSp[i] = (byte) i; 65 } 66 return testSp; 67 } 68 69 @Test(expected = NullPointerException.class) fromEntries_failsOnNull()70 public void fromEntries_failsOnNull() throws Exception { 71 RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, null, mKeyStoreEncryptionKey); 72 } 73 74 @Test(expected = NullPointerException.class) fromEncryptedData_failsOnNullData()75 public void fromEncryptedData_failsOnNullData() throws Exception { 76 byte[] testSp = getTestSp(); 77 RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, testSp, 78 mKeyStoreEncryptionKey); 79 RebootEscrowKey key = RebootEscrowKey.fromKeyBytes(expected.getKey().getKeyBytes()); 80 RebootEscrowData.fromEncryptedData(key, null, mKeyStoreEncryptionKey); 81 } 82 83 @Test(expected = NullPointerException.class) fromEncryptedData_failsOnNullKey()84 public void fromEncryptedData_failsOnNullKey() throws Exception { 85 byte[] testSp = getTestSp(); 86 RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, testSp, 87 mKeyStoreEncryptionKey); 88 RebootEscrowData.fromEncryptedData(null, expected.getBlob(), mKeyStoreEncryptionKey); 89 } 90 91 @Test fromEntries_loopback_success()92 public void fromEntries_loopback_success() throws Exception { 93 byte[] testSp = getTestSp(); 94 RebootEscrowData expected = RebootEscrowData.fromSyntheticPassword(mKey, (byte) 2, testSp, 95 mKeyStoreEncryptionKey); 96 97 RebootEscrowKey key = RebootEscrowKey.fromKeyBytes(expected.getKey().getKeyBytes()); 98 RebootEscrowData actual = RebootEscrowData.fromEncryptedData(key, expected.getBlob(), 99 mKeyStoreEncryptionKey); 100 101 assertThat(actual.getSpVersion(), is(expected.getSpVersion())); 102 assertThat(actual.getKey().getKeyBytes(), is(expected.getKey().getKeyBytes())); 103 assertThat(actual.getBlob(), is(expected.getBlob())); 104 assertThat(actual.getSyntheticPassword(), is(expected.getSyntheticPassword())); 105 } 106 107 @Test aesEncryptedBlob_loopback_success()108 public void aesEncryptedBlob_loopback_success() throws Exception { 109 byte[] testSp = getTestSp(); 110 byte [] encrypted = AesEncryptionUtil.encrypt(mKeyStoreEncryptionKey, testSp); 111 byte [] decrypted = AesEncryptionUtil.decrypt(mKeyStoreEncryptionKey, encrypted); 112 113 assertThat(decrypted, is(testSp)); 114 } 115 116 @Test fromEncryptedData_legacyVersion_success()117 public void fromEncryptedData_legacyVersion_success() throws Exception { 118 byte[] testSp = getTestSp(); 119 byte[] ksEncryptedBlob = AesEncryptionUtil.encrypt(mKey.getKey(), testSp); 120 121 // Write a legacy blob encrypted only by k_s. 122 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 123 DataOutputStream dos = new DataOutputStream(bos); 124 dos.writeInt(1); 125 dos.writeByte(3); 126 dos.write(ksEncryptedBlob); 127 byte[] legacyBlob = bos.toByteArray(); 128 129 RebootEscrowData actual = RebootEscrowData.fromEncryptedData(mKey, legacyBlob, null); 130 131 assertThat(actual.getSpVersion(), is((byte) 3)); 132 assertThat(actual.getKey().getKeyBytes(), is(mKey.getKeyBytes())); 133 assertThat(actual.getSyntheticPassword(), is(testSp)); 134 } 135 } 136