1 /* 2 * Copyright 2020 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 @file:Suppress("deprecation") 18 19 package androidx.security.crypto 20 21 import android.content.Context 22 import androidx.test.core.app.ApplicationProvider 23 import androidx.test.ext.junit.runners.AndroidJUnit4 24 import androidx.test.filters.MediumTest 25 import java.io.File 26 import java.nio.charset.StandardCharsets 27 import java.security.KeyStore 28 import org.junit.Assert 29 import org.junit.Before 30 import org.junit.Test 31 import org.junit.runner.RunWith 32 33 private const val PREFS_FILE = "test_shared_prefs" 34 35 @MediumTest 36 @RunWith(AndroidJUnit4::class) 37 class KtxTests { 38 39 @Before 40 @Throws(Exception::class) setupnull41 fun setup() { 42 val context = ApplicationProvider.getApplicationContext<Context>() 43 // Delete all previous keys and shared preferences. 44 val parentDir = 45 context.filesDir?.parent ?: throw IllegalStateException("filesDir?.parent is null?") 46 var filePath = 47 (parentDir + "/shared_prefs/" + "__androidx_security__crypto_encrypted_prefs__") 48 var deletePrefFile = File(filePath) 49 deletePrefFile.delete() 50 val notEncryptedSharedPrefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE) 51 notEncryptedSharedPrefs.edit().clear().commit() 52 filePath = ("$parentDir/shared_prefs/$PREFS_FILE") 53 deletePrefFile = File(filePath) 54 deletePrefFile.delete() 55 val encryptedSharedPrefs = 56 context.getSharedPreferences("TinkTestPrefs", Context.MODE_PRIVATE) 57 encryptedSharedPrefs.edit().clear().commit() 58 filePath = ("$parentDir/shared_prefs/TinkTestPrefs") 59 deletePrefFile = File(filePath) 60 deletePrefFile.delete() 61 // Delete MasterKeys 62 val keyStore = KeyStore.getInstance("AndroidKeyStore") 63 keyStore.load(null) 64 keyStore.deleteEntry("_androidx_security_master_key_") 65 } 66 67 @Test testMasterKeyExtensionnull68 fun testMasterKeyExtension() { 69 val context = ApplicationProvider.getApplicationContext<Context>() 70 71 val ktxMasterKey = 72 MasterKey( 73 context = context, 74 authenticationRequired = false, 75 userAuthenticationValidityDurationSeconds = 123 76 ) 77 val jMasterKey = 78 MasterKey.Builder(context) 79 .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) 80 .setUserAuthenticationRequired(false, 123) 81 .build() 82 Assert.assertEquals(ktxMasterKey.keyAlias, jMasterKey.keyAlias) 83 Assert.assertEquals( 84 ktxMasterKey.isUserAuthenticationRequired, 85 jMasterKey.isUserAuthenticationRequired 86 ) 87 Assert.assertEquals( 88 ktxMasterKey.userAuthenticationValidityDurationSeconds, 89 jMasterKey.userAuthenticationValidityDurationSeconds 90 ) 91 } 92 93 @Test testEncryptedSharedPreferencesExtensionnull94 fun testEncryptedSharedPreferencesExtension() { 95 val context = ApplicationProvider.getApplicationContext<Context>() 96 val masterKey = MasterKey(context) 97 val filename = "test" 98 99 val ktxSharedPreferences = 100 EncryptedSharedPreferences( 101 context = context, 102 fileName = filename, 103 masterKey = masterKey 104 ) 105 ktxSharedPreferences.edit().putString("test_key", "KTX Write").commit() 106 107 val jSharedPreferences = 108 EncryptedSharedPreferences.create( 109 context, 110 filename, 111 masterKey, 112 EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, 113 EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM 114 ) 115 val readValue = jSharedPreferences.getString("test_key", "error") 116 Assert.assertEquals(readValue, "KTX Write") 117 } 118 119 @Test testEncryptedFileExtensionnull120 fun testEncryptedFileExtension() { 121 val context = ApplicationProvider.getApplicationContext<Context>() 122 val masterKey = MasterKey(context) 123 val file = File(context.cacheDir, "test.file") 124 val testContent = "This is a test" 125 126 if (file.exists()) { 127 file.delete() 128 } 129 130 val ktFile = EncryptedFile(context, file, masterKey) 131 ktFile.openFileOutput().use { 132 it.write("This is a test".toByteArray(StandardCharsets.UTF_8)) 133 } 134 135 val jFile = 136 EncryptedFile.Builder( 137 context, 138 file, 139 masterKey, 140 EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB 141 ) 142 .build() 143 144 val buffer = ByteArray(1024) 145 jFile.openFileInput().use { 146 val size = it.read(buffer) 147 Assert.assertEquals(size, testContent.length) 148 149 val contentBuffer = buffer.slice(IntRange(0, size - 1)).toByteArray() 150 val content = String(contentBuffer, StandardCharsets.UTF_8) 151 Assert.assertEquals(testContent, content) 152 } 153 154 if (!file.exists()) { 155 Assert.fail("File didn't exist?") 156 } 157 file.delete() 158 } 159 } 160