17
17
package com.duckduckgo.autofill.impl.securestorage.encryption
18
18
19
19
import android.security.keystore.KeyProperties
20
+ import com.duckduckgo.autofill.api.AutofillFeature
20
21
import com.duckduckgo.autofill.impl.securestorage.SecureStorageException
21
22
import com.duckduckgo.autofill.impl.securestorage.SecureStorageException.InternalSecureStorageException
22
23
import com.duckduckgo.autofill.impl.securestorage.encryption.EncryptionHelper.EncryptedBytes
24
+ import com.duckduckgo.common.utils.DispatcherProvider
23
25
import com.duckduckgo.di.scopes.AppScope
24
26
import com.squareup.anvil.annotations.ContributesBinding
25
27
import java.lang.Exception
26
28
import java.security.Key
27
29
import javax.crypto.Cipher
28
30
import javax.crypto.spec.GCMParameterSpec
29
31
import javax.inject.Inject
32
+ import kotlinx.coroutines.sync.Mutex
33
+ import kotlinx.coroutines.sync.withLock
34
+ import kotlinx.coroutines.withContext
30
35
31
36
interface EncryptionHelper {
32
37
@Throws(SecureStorageException ::class )
33
- fun encrypt (
38
+ suspend fun encrypt (
34
39
raw : ByteArray ,
35
40
key : Key ,
36
41
): EncryptedBytes
37
42
38
43
@Throws(SecureStorageException ::class )
39
- fun decrypt (
44
+ suspend fun decrypt (
40
45
toDecrypt : EncryptedBytes ,
41
46
key : Key ,
42
47
): ByteArray
@@ -53,12 +58,45 @@ interface EncryptionHelper {
53
58
}
54
59
55
60
@ContributesBinding(AppScope ::class )
56
- class RealEncryptionHelper @Inject constructor() : EncryptionHelper {
61
+ class RealEncryptionHelper @Inject constructor(
62
+ private val autofillFeature : AutofillFeature ,
63
+ private val dispatcherProvider : DispatcherProvider ,
64
+ ) : EncryptionHelper {
57
65
private val encryptionCipher = Cipher .getInstance(TRANSFORMATION )
58
66
private val decryptionCipher = Cipher .getInstance(TRANSFORMATION )
59
67
68
+ private val encryptMutex = Mutex ()
69
+ private val decryptMutex = Mutex ()
70
+
71
+ override suspend fun encrypt (
72
+ raw : ByteArray ,
73
+ key : Key ,
74
+ ): EncryptedBytes = withContext(dispatcherProvider.io()) {
75
+ return @withContext if (autofillFeature.createAsyncPreferences().isEnabled()) {
76
+ encryptAsync(raw, key)
77
+ } else {
78
+ encryptSync(raw, key)
79
+ }
80
+ }
81
+
60
82
@Synchronized
61
- override fun encrypt (
83
+ private fun encryptSync (
84
+ raw : ByteArray ,
85
+ key : Key ,
86
+ ): EncryptedBytes {
87
+ return innerEncrypt(raw, key)
88
+ }
89
+
90
+ private suspend fun encryptAsync (
91
+ raw : ByteArray ,
92
+ key : Key ,
93
+ ): EncryptedBytes {
94
+ encryptMutex.withLock {
95
+ return innerEncrypt(raw, key)
96
+ }
97
+ }
98
+
99
+ private fun innerEncrypt (
62
100
raw : ByteArray ,
63
101
key : Key ,
64
102
): EncryptedBytes {
@@ -73,8 +111,35 @@ class RealEncryptionHelper @Inject constructor() : EncryptionHelper {
73
111
return EncryptedBytes (encrypted, iv)
74
112
}
75
113
114
+ override suspend fun decrypt (
115
+ toDecrypt : EncryptedBytes ,
116
+ key : Key ,
117
+ ): ByteArray = withContext(dispatcherProvider.io()) {
118
+ return @withContext if (autofillFeature.createAsyncPreferences().isEnabled()) {
119
+ decryptAsync(toDecrypt, key)
120
+ } else {
121
+ decryptSync(toDecrypt, key)
122
+ }
123
+ }
124
+
76
125
@Synchronized
77
- override fun decrypt (
126
+ private fun decryptSync (
127
+ toDecrypt : EncryptedBytes ,
128
+ key : Key ,
129
+ ): ByteArray {
130
+ return innerDecrypt(toDecrypt, key)
131
+ }
132
+
133
+ private suspend fun decryptAsync (
134
+ toDecrypt : EncryptedBytes ,
135
+ key : Key ,
136
+ ): ByteArray {
137
+ decryptMutex.withLock {
138
+ return innerDecrypt(toDecrypt, key)
139
+ }
140
+ }
141
+
142
+ private fun innerDecrypt (
78
143
toDecrypt : EncryptedBytes ,
79
144
key : Key ,
80
145
): ByteArray {
0 commit comments