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