KeyStoreCrypto fallback if Android KeyStore is not properly working.
This commit is contained in:
parent
6136a429f7
commit
ae9280d50b
42
CHANGELOG.md
42
CHANGELOG.md
|
@ -1,3 +1,45 @@
|
|||
## Crypto Version [1.15.2]
|
||||
|
||||
Sep 20, 2021
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Auth 1.15.2.
|
||||
- Account 1.15.2.
|
||||
- Crypto 1.15.2.
|
||||
- Human-Verification 1.15.2.
|
||||
- Key 1.15.2.
|
||||
- Network 1.15.2.
|
||||
- Util Kotlin 1.15.2.
|
||||
- User 1.15.2.
|
||||
- User-Settings 1.15.2.
|
||||
|
||||
### Api Changes
|
||||
|
||||
- Logger is no more injected. Instead Core use a static ```CoreLogger```. You now have to set the Logger instance, on Application create:
|
||||
```
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
CoreLogger.set(CoreExampleLogger())
|
||||
```
|
||||
- There is also a new KeyStoreCrypto LogTag object you must be aware:
|
||||
```
|
||||
object LogTag {
|
||||
/** Tag for KeyStore initialization check failure. */
|
||||
const val KEYSTORE_INIT = "core.crypto.common.keystore.init"
|
||||
|
||||
/** Tag for KeyStore encrypt failure. */
|
||||
const val KEYSTORE_ENCRYPT = "core.crypto.common.keystore.encrypt"
|
||||
|
||||
/** Tag for KeyStore decrypt failure. */
|
||||
const val KEYSTORE_DECRYPT = "core.crypto.common.keystore.decrypt"
|
||||
}
|
||||
```
|
||||
|
||||
### New Features
|
||||
|
||||
- KeyStoreCrypto fallback if Android KeyStore is not properly working.
|
||||
|
||||
## Presentation [1.15.1]
|
||||
|
||||
Sep 21, 2021
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import androidx.room.ForeignKey
|
|||
import androidx.room.Index
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decryptOrElse
|
||||
import me.proton.core.data.room.db.CommonConverters
|
||||
import me.proton.core.domain.entity.Product
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -55,8 +55,10 @@ data class SessionEntity(
|
|||
) {
|
||||
fun toSession(keyStoreCrypto: KeyStoreCrypto): Session = Session(
|
||||
sessionId = sessionId,
|
||||
accessToken = accessToken.decryptWith(keyStoreCrypto),
|
||||
refreshToken = refreshToken.decryptWith(keyStoreCrypto),
|
||||
// Fall back to invalid tokens to force delete session on decryption failure.
|
||||
// See RefreshTokenHandler and sessionListener.onSessionForceLogout.
|
||||
accessToken = requireNotNull(accessToken.decryptOrElse(keyStoreCrypto) { "invalid" }),
|
||||
refreshToken = requireNotNull(refreshToken.decryptOrElse(keyStoreCrypto) { "invalid" }),
|
||||
scopes = CommonConverters.fromStringToListOfString(scopes).orEmpty()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
package me.proton.core.account.data.extension
|
||||
|
||||
import me.proton.core.account.data.entity.SessionEntity
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.data.room.db.CommonConverters
|
||||
import me.proton.core.domain.entity.Product
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -33,8 +33,8 @@ fun Session.toSessionEntity(
|
|||
): SessionEntity = SessionEntity(
|
||||
userId = userId,
|
||||
sessionId = sessionId,
|
||||
accessToken = accessToken.encryptWith(keyStoreCrypto),
|
||||
refreshToken = refreshToken.encryptWith(keyStoreCrypto),
|
||||
accessToken = accessToken.encrypt(keyStoreCrypto),
|
||||
refreshToken = refreshToken.encrypt(keyStoreCrypto),
|
||||
scopes = CommonConverters.fromListOfStringToString(scopes).orEmpty(),
|
||||
product = product
|
||||
)
|
||||
|
|
|
@ -38,7 +38,7 @@ import me.proton.core.account.domain.entity.SessionDetails
|
|||
import me.proton.core.account.domain.entity.SessionState
|
||||
import me.proton.core.account.domain.repository.AccountRepository
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.data.room.db.CommonConverters
|
||||
import me.proton.core.domain.entity.Product
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -215,8 +215,8 @@ class AccountRepositoryImpl(
|
|||
override suspend fun updateSessionToken(sessionId: SessionId, accessToken: String, refreshToken: String) =
|
||||
sessionDao.updateToken(
|
||||
sessionId,
|
||||
accessToken.encryptWith(keyStoreCrypto),
|
||||
refreshToken.encryptWith(keyStoreCrypto)
|
||||
accessToken.encrypt(keyStoreCrypto),
|
||||
refreshToken.encrypt(keyStoreCrypto)
|
||||
)
|
||||
|
||||
override fun getPrimaryUserId(): Flow<UserId?> =
|
||||
|
|
|
@ -67,6 +67,7 @@ class AccountRepositoryImplTest {
|
|||
private lateinit var metadataDao: AccountMetadataDao
|
||||
|
||||
private val simpleCrypto = object : KeyStoreCrypto {
|
||||
override fun isUsingKeyStore(): Boolean = false
|
||||
override fun encrypt(value: String): EncryptedString = value
|
||||
override fun encrypt(value: PlainByteArray): EncryptedByteArray = EncryptedByteArray(value.array)
|
||||
override fun decrypt(value: EncryptedString): String = value
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import me.proton.core.auth.domain.entity.SessionInfo
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.crypto.common.srp.SrpProofs
|
||||
|
@ -47,7 +47,7 @@ class PerformLogin @Inject constructor(
|
|||
username = username,
|
||||
clientSecret = clientSecret
|
||||
)
|
||||
password.decryptWith(keyStoreCrypto).toByteArray().use {
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use {
|
||||
val clientProofs: SrpProofs = srpCrypto.generateSrpProofs(
|
||||
username = username,
|
||||
password = it.array,
|
||||
|
|
|
@ -22,7 +22,7 @@ import me.proton.core.account.domain.entity.AccountType
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -74,7 +74,7 @@ class SetupPrimaryKeys @Inject constructor(
|
|||
}
|
||||
val modulus = authRepository.randomModulus()
|
||||
|
||||
password.decryptWith(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
val auth = srpCrypto.calculatePasswordVerifier(
|
||||
username = email,
|
||||
password = decryptedPassword.array,
|
||||
|
|
|
@ -20,7 +20,7 @@ package me.proton.core.auth.domain.usecase
|
|||
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.user.domain.UserManager
|
||||
|
@ -42,7 +42,7 @@ class UnlockUserPrimaryKey @Inject constructor(
|
|||
suspend operator fun invoke(
|
||||
userId: UserId,
|
||||
password: EncryptedString
|
||||
): UserManager.UnlockResult = password.decryptWith(keyStoreCrypto).toByteArray().use {
|
||||
): UserManager.UnlockResult = password.decrypt(keyStoreCrypto).toByteArray().use {
|
||||
userManager.unlockWithPassword(userId, it)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ package me.proton.core.auth.domain.usecase.signup
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.user.domain.entity.CreateUserType
|
||||
|
@ -44,7 +44,7 @@ class PerformCreateExternalEmailUser @Inject constructor(
|
|||
require(email.isNotBlank()) { "Email must not be empty." }
|
||||
val modulus = authRepository.randomModulus()
|
||||
|
||||
password.decryptWith(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
val auth = srpCrypto.calculatePasswordVerifier(
|
||||
username = email,
|
||||
password = decryptedPassword.array,
|
||||
|
|
|
@ -21,7 +21,7 @@ package me.proton.core.auth.domain.usecase.signup
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.user.domain.entity.CreateUserType
|
||||
|
@ -51,7 +51,7 @@ class PerformCreateUser @Inject constructor(
|
|||
) { "Recovery Email and Phone could not be set together" }
|
||||
val modulus = authRepository.randomModulus()
|
||||
|
||||
password.decryptWith(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
val auth = srpCrypto.calculatePasswordVerifier(
|
||||
username = username,
|
||||
password = decryptedPassword.array,
|
||||
|
|
|
@ -28,7 +28,7 @@ plugins {
|
|||
id("dagger.hilt.android.plugin")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android(useDataBinding = true)
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ import me.proton.core.auth.domain.usecase.UnlockUserPrimaryKey
|
|||
import me.proton.core.auth.presentation.entity.signup.SubscriptionDetails
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.humanverification.domain.HumanVerificationManager
|
||||
import me.proton.core.humanverification.presentation.HumanVerificationOrchestrator
|
||||
|
@ -112,7 +112,7 @@ internal class LoginViewModel @Inject constructor(
|
|||
) = flow<State> {
|
||||
emit(State.Processing)
|
||||
|
||||
val encryptedPassword = password.encryptWith(keyStoreCrypto)
|
||||
val encryptedPassword = password.encrypt(keyStoreCrypto)
|
||||
|
||||
val sessionInfo = performLogin.invoke(username, encryptedPassword)
|
||||
val userId = sessionInfo.userId
|
||||
|
|
|
@ -32,7 +32,7 @@ import me.proton.core.auth.domain.AccountWorkflowHandler
|
|||
import me.proton.core.auth.domain.usecase.UnlockUserPrimaryKey
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.presentation.viewmodel.ProtonViewModel
|
||||
import me.proton.core.user.domain.UserManager
|
||||
|
@ -72,7 +72,7 @@ class TwoPassModeViewModel @Inject constructor(
|
|||
) = flow {
|
||||
emit(State.Processing)
|
||||
|
||||
val encryptedPassword = password.encryptWith(keyStoreCrypto)
|
||||
val encryptedPassword = password.encrypt(keyStoreCrypto)
|
||||
val state = unlockUserPrimaryKey(userId, encryptedPassword)
|
||||
|
||||
emit(state)
|
||||
|
|
|
@ -37,8 +37,8 @@ import me.proton.core.auth.presentation.entity.signup.SubscriptionDetails
|
|||
import me.proton.core.auth.presentation.viewmodel.AuthViewModel
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.humanverification.domain.HumanVerificationManager
|
||||
import me.proton.core.humanverification.presentation.HumanVerificationOrchestrator
|
||||
import me.proton.core.humanverification.presentation.onHumanVerificationFailed
|
||||
|
@ -82,9 +82,9 @@ internal class SignupViewModel @Inject constructor(
|
|||
var externalEmail: String? = null
|
||||
|
||||
var password: String
|
||||
get() = _password.decryptWith(keyStoreCrypto)
|
||||
get() = _password.decrypt(keyStoreCrypto)
|
||||
set(value) {
|
||||
_password = value.encryptWith(keyStoreCrypto)
|
||||
_password = value.encrypt(keyStoreCrypto)
|
||||
}
|
||||
|
||||
override val recoveryEmailAddress: String?
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.app.Application
|
|||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatDelegate.setCompatVectorFromResourcesEnabled
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import timber.log.Timber
|
||||
import timber.log.Timber.DebugTree
|
||||
|
||||
|
@ -44,6 +45,8 @@ class CoreExampleApp : Application() {
|
|||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
CoreLogger.set(CoreExampleLogger())
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(DebugTree())
|
||||
} else {
|
||||
|
|
|
@ -22,13 +22,11 @@ import dagger.Module
|
|||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.proton.android.core.coreexample.CoreExampleLogger
|
||||
import me.proton.android.core.coreexample.api.CoreExampleRepository
|
||||
import me.proton.core.account.domain.entity.AccountType
|
||||
import me.proton.core.auth.domain.ClientSecret
|
||||
import me.proton.core.domain.entity.Product
|
||||
import me.proton.core.network.data.ApiProvider
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
@ -49,11 +47,6 @@ object ApplicationModule {
|
|||
@ClientSecret
|
||||
fun provideClientSecret(): String = ""
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideLogger(): Logger =
|
||||
CoreExampleLogger()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCoreExampleRepository(apiProvider: ApiProvider): CoreExampleRepository =
|
||||
|
|
|
@ -46,7 +46,6 @@ import me.proton.core.network.domain.humanverification.HumanVerificationProvider
|
|||
import me.proton.core.network.domain.server.ServerTimeListener
|
||||
import me.proton.core.network.domain.session.SessionListener
|
||||
import me.proton.core.network.domain.session.SessionProvider
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import okhttp3.Cache
|
||||
import java.io.File
|
||||
import javax.inject.Singleton
|
||||
|
@ -86,7 +85,6 @@ class NetworkModule {
|
|||
@Singleton
|
||||
fun provideApiFactory(
|
||||
@ApplicationContext context: Context,
|
||||
logger: Logger,
|
||||
apiClient: ApiClient,
|
||||
clientIdProvider: ClientIdProvider,
|
||||
serverTimeListener: ServerTimeListener,
|
||||
|
@ -102,7 +100,6 @@ class NetworkModule {
|
|||
apiClient,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
networkManager,
|
||||
networkPrefs,
|
||||
sessionProvider,
|
||||
|
|
|
@ -41,6 +41,7 @@ import me.proton.core.accountmanager.presentation.onAccountCreateAddressFailed
|
|||
import me.proton.core.accountmanager.presentation.onAccountCreateAddressNeeded
|
||||
import me.proton.core.accountmanager.presentation.onAccountTwoPassModeFailed
|
||||
import me.proton.core.accountmanager.presentation.onAccountTwoPassModeNeeded
|
||||
import me.proton.core.accountmanager.presentation.onSessionForceLogout
|
||||
import me.proton.core.accountmanager.presentation.onSessionSecondFactorNeeded
|
||||
import me.proton.core.auth.presentation.AuthOrchestrator
|
||||
import me.proton.core.domain.entity.Product
|
||||
|
@ -49,11 +50,13 @@ import me.proton.core.humanverification.domain.HumanVerificationManager
|
|||
import me.proton.core.humanverification.presentation.HumanVerificationOrchestrator
|
||||
import me.proton.core.humanverification.presentation.observe
|
||||
import me.proton.core.humanverification.presentation.onHumanVerificationNeeded
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AccountViewModel @Inject constructor(
|
||||
private val accountManager: AccountManager,
|
||||
private val userManager: UserManager,
|
||||
private val humanVerificationManager: HumanVerificationManager,
|
||||
private var authOrchestrator: AuthOrchestrator,
|
||||
private var humanVerificationOrchestrator: HumanVerificationOrchestrator
|
||||
|
@ -84,6 +87,7 @@ class AccountViewModel @Inject constructor(
|
|||
|
||||
with(authOrchestrator) {
|
||||
accountManager.observe(context.lifecycle, minActiveState = Lifecycle.State.CREATED)
|
||||
.onSessionForceLogout { userManager.lock(it.userId) }
|
||||
.onSessionSecondFactorNeeded { startSecondFactorWorkflow(it) }
|
||||
.onAccountTwoPassModeNeeded { startTwoPassModeWorkflow(it) }
|
||||
.onAccountCreateAddressNeeded { startChooseAddressWorkflow(it) }
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -23,9 +23,12 @@ import android.security.keystore.KeyProperties
|
|||
import android.util.Base64
|
||||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.PlainByteArray
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.LogTag
|
||||
import me.proton.core.crypto.common.keystore.PlainByteArray
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import java.security.Key
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
|
@ -67,37 +70,67 @@ class AndroidKeyStoreCrypto private constructor(
|
|||
)
|
||||
it.generateKey()
|
||||
}
|
||||
}.let { keyStoreKey ->
|
||||
// Check if encrypt/decrypt is properly working (CP-1500).
|
||||
runCatching {
|
||||
val message = "message"
|
||||
val encrypted = encrypt(message, keyStoreKey)
|
||||
val decrypted = decrypt(encrypted, keyStoreKey)
|
||||
check(message == decrypted)
|
||||
keyStoreKey
|
||||
}.getOrElse {
|
||||
CoreLogger.e(LogTag.KEYSTORE_INIT, it)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun encrypt(value: PlainByteArray): EncryptedByteArray {
|
||||
private fun encrypt(value: PlainByteArray, key: Key): EncryptedByteArray {
|
||||
val cipher = Cipher.getInstance(cipherTransformation)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key)
|
||||
val cipherByteArray = cipher.doFinal(value.array)
|
||||
return EncryptedByteArray(cipher.iv + cipherByteArray)
|
||||
}
|
||||
|
||||
override fun decrypt(value: EncryptedByteArray): PlainByteArray {
|
||||
private fun decrypt(value: EncryptedByteArray, key: Key): PlainByteArray {
|
||||
val cipher = Cipher.getInstance(cipherTransformation)
|
||||
val iv = value.array.copyOf(cipherIvBytes)
|
||||
val cipherByteArray = value.array.copyOfRange(cipherIvBytes, value.array.size)
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(cipherGCMTagBits, iv))
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(cipherGCMTagBits, iv))
|
||||
return PlainByteArray(cipher.doFinal(cipherByteArray))
|
||||
}
|
||||
|
||||
override fun encrypt(value: String): EncryptedString {
|
||||
private fun encrypt(value: String, key: Key): EncryptedString {
|
||||
return value.encodeToByteArray().use {
|
||||
Base64.encodeToString(encrypt(it).array, Base64.NO_WRAP)
|
||||
Base64.encodeToString(encrypt(it, key).array, Base64.NO_WRAP)
|
||||
}
|
||||
}
|
||||
|
||||
override fun decrypt(value: EncryptedString): String {
|
||||
private fun decrypt(value: EncryptedString, key: Key): String {
|
||||
val encryptedByteArray = Base64.decode(value, Base64.NO_WRAP)
|
||||
return decrypt(EncryptedByteArray(encryptedByteArray)).use {
|
||||
return decrypt(EncryptedByteArray(encryptedByteArray), key).use {
|
||||
it.array.decodeToString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isUsingKeyStore(): Boolean = secretKey != null
|
||||
|
||||
override fun encrypt(value: PlainByteArray): EncryptedByteArray {
|
||||
return secretKey?.let { encrypt(value, it) } ?: EncryptedByteArray(value.array.copyOf())
|
||||
}
|
||||
|
||||
override fun decrypt(value: EncryptedByteArray): PlainByteArray {
|
||||
return secretKey?.let { decrypt(value, it) } ?: PlainByteArray(value.array.copyOf())
|
||||
}
|
||||
|
||||
override fun encrypt(value: String): EncryptedString {
|
||||
return secretKey?.let { encrypt(value, it) } ?: value
|
||||
}
|
||||
|
||||
override fun decrypt(value: EncryptedString): String {
|
||||
return secretKey?.let { decrypt(value, it) } ?: value
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_MASTER_KEY_ALIAS = "_me_proton_core_data_crypto_master_key_"
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
implementation(
|
||||
|
|
|
@ -32,9 +32,29 @@ data class EncryptedByteArray(val array: ByteArray) {
|
|||
/**
|
||||
* Decrypt an [EncryptedByteArray] using a [KeyStoreCrypto].
|
||||
*/
|
||||
fun EncryptedByteArray.decryptWith(keyStoreCrypto: KeyStoreCrypto) = keyStoreCrypto.decrypt(this)
|
||||
fun EncryptedByteArray.decrypt(crypto: KeyStoreCrypto) = crypto.decrypt(this)
|
||||
|
||||
/**
|
||||
* Encrypt a [PlainByteArray] using a [KeyStoreCrypto].
|
||||
*/
|
||||
fun PlainByteArray.encryptWith(keyStoreCrypto: KeyStoreCrypto) = keyStoreCrypto.encrypt(this)
|
||||
fun PlainByteArray.encrypt(crypto: KeyStoreCrypto) = crypto.encrypt(this)
|
||||
|
||||
/**
|
||||
* Returns decrypted value, or the result of [onFailure] function on decryption failure.
|
||||
*
|
||||
* @see [EncryptedByteArray.decrypt]
|
||||
*/
|
||||
fun EncryptedByteArray.decryptOrElse(
|
||||
crypto: KeyStoreCrypto,
|
||||
onFailure: (Throwable) -> PlainByteArray?
|
||||
) = crypto.decryptOrElse(this, onFailure)
|
||||
|
||||
/**
|
||||
* Returns encrypted value, or the result of [onFailure] function on encryption failure.
|
||||
*
|
||||
* @see [PlainByteArray.encrypt]
|
||||
*/
|
||||
fun PlainByteArray.encryptOrElse(
|
||||
crypto: KeyStoreCrypto,
|
||||
onFailure: (Throwable) -> EncryptedByteArray?
|
||||
) = crypto.encryptOrElse(this, onFailure)
|
||||
|
|
|
@ -26,9 +26,29 @@ typealias EncryptedString = String
|
|||
/**
|
||||
* Decrypt an [EncryptedString] using a [KeyStoreCrypto].
|
||||
*/
|
||||
fun EncryptedString.decryptWith(crypto: KeyStoreCrypto) = crypto.decrypt(this)
|
||||
fun EncryptedString.decrypt(crypto: KeyStoreCrypto) = crypto.decrypt(this)
|
||||
|
||||
/**
|
||||
* Encrypt a [String] using a [KeyStoreCrypto].
|
||||
*/
|
||||
fun String.encryptWith(crypto: KeyStoreCrypto) = crypto.encrypt(this)
|
||||
fun String.encrypt(crypto: KeyStoreCrypto) = crypto.encrypt(this)
|
||||
|
||||
/**
|
||||
* Returns decrypted value, or the result of onFailure function on decryption failure.
|
||||
*
|
||||
* @see [EncryptedString.decryptWith]
|
||||
*/
|
||||
fun EncryptedString.decryptOrElse(
|
||||
crypto: KeyStoreCrypto,
|
||||
onFailure: (Throwable) -> String?
|
||||
) = crypto.decryptOrElse(this, onFailure)
|
||||
|
||||
/**
|
||||
* Returns encrypted value, or the result of [onFailure] function on encryption failure.
|
||||
*
|
||||
* @see [String.encrypt]
|
||||
*/
|
||||
fun String.encryptOrElse(
|
||||
crypto: KeyStoreCrypto,
|
||||
onFailure: (Throwable) -> EncryptedString?
|
||||
) = crypto.encryptOrElse(this, onFailure)
|
||||
|
|
|
@ -18,11 +18,18 @@
|
|||
|
||||
package me.proton.core.crypto.common.keystore
|
||||
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
|
||||
/**
|
||||
* KeyStore Cryptographic interface providing [encrypt] function on [String] and [PlainByteArray],
|
||||
* and a [decrypt] function on [EncryptedString] and [EncryptedByteArray].
|
||||
*/
|
||||
interface KeyStoreCrypto {
|
||||
/**
|
||||
* Returns whether System Keystore is being used providing secure key, or false otherwise.
|
||||
*/
|
||||
fun isUsingKeyStore(): Boolean
|
||||
|
||||
/**
|
||||
* Encrypt a [String] [value] and return an [EncryptedString].
|
||||
*/
|
||||
|
@ -43,3 +50,74 @@ interface KeyStoreCrypto {
|
|||
*/
|
||||
fun decrypt(value: EncryptedByteArray): PlainByteArray
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns encrypted value, or the result of [onFailure] function on encryption failure.
|
||||
*
|
||||
* @see [KeyStoreCrypto.encrypt]
|
||||
*/
|
||||
fun KeyStoreCrypto.encryptOrElse(
|
||||
value: String,
|
||||
onFailure: (Throwable) -> EncryptedString?
|
||||
): EncryptedString? = runCatching {
|
||||
encrypt(value)
|
||||
}.getOrElse {
|
||||
CoreLogger.e(LogTag.KEYSTORE_ENCRYPT, it)
|
||||
onFailure(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns encrypted value, or the result of [onFailure] function on encryption failure.
|
||||
*
|
||||
* @see [KeyStoreCrypto.encrypt]
|
||||
*/
|
||||
fun KeyStoreCrypto.encryptOrElse(
|
||||
value: PlainByteArray,
|
||||
onFailure: (Throwable) -> EncryptedByteArray?
|
||||
): EncryptedByteArray? = runCatching {
|
||||
encrypt(value)
|
||||
}.getOrElse {
|
||||
CoreLogger.e(LogTag.KEYSTORE_ENCRYPT, it)
|
||||
onFailure(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns decrypted value, or the result of [onFailure] function on decryption failure.
|
||||
*
|
||||
* @see [KeyStoreCrypto.decrypt]
|
||||
*/
|
||||
fun KeyStoreCrypto.decryptOrElse(
|
||||
value: EncryptedString,
|
||||
onFailure: (Throwable) -> String?
|
||||
): String? = runCatching {
|
||||
decrypt(value)
|
||||
}.getOrElse {
|
||||
CoreLogger.e(LogTag.KEYSTORE_DECRYPT, it)
|
||||
onFailure(it)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns decrypted value, or the result of [onFailure] function on decryption failure.
|
||||
*
|
||||
* @see [KeyStoreCrypto.decrypt]
|
||||
*/
|
||||
fun KeyStoreCrypto.decryptOrElse(
|
||||
value: EncryptedByteArray,
|
||||
onFailure: (Throwable) -> PlainByteArray?
|
||||
): PlainByteArray? = runCatching {
|
||||
decrypt(value)
|
||||
}.getOrElse {
|
||||
CoreLogger.e(LogTag.KEYSTORE_DECRYPT, it)
|
||||
onFailure(it)
|
||||
}
|
||||
|
||||
object LogTag {
|
||||
/** Tag for KeyStore initialization check failure. */
|
||||
const val KEYSTORE_INIT = "core.crypto.common.keystore.init"
|
||||
|
||||
/** Tag for KeyStore encrypt failure. */
|
||||
const val KEYSTORE_ENCRYPT = "core.crypto.common.keystore.encrypt"
|
||||
|
||||
/** Tag for KeyStore decrypt failure. */
|
||||
const val KEYSTORE_DECRYPT = "core.crypto.common.keystore.decrypt"
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ plugins {
|
|||
kotlin("kapt")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android(minSdk = 23)
|
||||
|
||||
|
|
|
@ -21,13 +21,13 @@ package me.proton.core.humanverification.data.entity
|
|||
import androidx.room.Entity
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.network.domain.humanverification.HumanVerificationDetails
|
||||
import me.proton.core.network.domain.humanverification.HumanVerificationState
|
||||
import me.proton.core.network.domain.humanverification.VerificationMethod
|
||||
import me.proton.core.crypto.common.keystore.decryptOrElse
|
||||
import me.proton.core.network.domain.client.ClientId
|
||||
import me.proton.core.network.domain.client.ClientIdType
|
||||
import me.proton.core.network.domain.client.CookieSessionId
|
||||
import me.proton.core.network.domain.humanverification.HumanVerificationDetails
|
||||
import me.proton.core.network.domain.humanverification.HumanVerificationState
|
||||
import me.proton.core.network.domain.humanverification.VerificationMethod
|
||||
import me.proton.core.network.domain.session.SessionId
|
||||
|
||||
@Entity(
|
||||
|
@ -50,7 +50,9 @@ data class HumanVerificationEntity(
|
|||
verificationMethods = verificationMethods.map { VerificationMethod.getByValue(it) },
|
||||
captchaVerificationToken = captchaVerificationToken,
|
||||
state = state,
|
||||
tokenType = humanHeaderTokenType?.decryptWith(keyStoreCrypto),
|
||||
tokenCode = humanHeaderTokenCode?.decryptWith(keyStoreCrypto)
|
||||
// Fall back to an invalid captcha to force delete token on decryption failure.
|
||||
// See HumanVerificationInvalidHandler and HumanVerificationListener.onHumanVerificationInvalid.
|
||||
tokenType = humanHeaderTokenType?.decryptOrElse(keyStoreCrypto) { "captcha" },
|
||||
tokenCode = humanHeaderTokenCode?.decryptOrElse(keyStoreCrypto) { "invalid" }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.first
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onSubscription
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.humanverification.data.db.HumanVerificationDatabase
|
||||
import me.proton.core.humanverification.data.entity.HumanVerificationEntity
|
||||
import me.proton.core.humanverification.domain.repository.HumanVerificationRepository
|
||||
|
@ -67,8 +67,8 @@ class HumanVerificationRepositoryImpl(
|
|||
verificationMethods = details.verificationMethods.map { method -> method.value },
|
||||
captchaVerificationToken = details.captchaVerificationToken,
|
||||
state = details.state,
|
||||
humanHeaderTokenType = details.tokenType?.encryptWith(keyStoreCrypto),
|
||||
humanHeaderTokenCode = details.tokenCode?.encryptWith(keyStoreCrypto)
|
||||
humanHeaderTokenType = details.tokenType?.encrypt(keyStoreCrypto),
|
||||
humanHeaderTokenCode = details.tokenCode?.encrypt(keyStoreCrypto)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ class HumanVerificationRepositoryImpl(
|
|||
humanVerificationDetailsDao.updateStateAndToken(
|
||||
clientId.id,
|
||||
state,
|
||||
tokenType?.encryptWith(keyStoreCrypto),
|
||||
tokenCode?.encryptWith(keyStoreCrypto)
|
||||
tokenType?.encrypt(keyStoreCrypto),
|
||||
tokenCode?.encrypt(keyStoreCrypto)
|
||||
)
|
||||
}
|
||||
getHumanVerificationDetails(clientId)?.let { tryEmitStateChanged(it) }
|
||||
|
|
|
@ -60,6 +60,7 @@ class HumanVerificationRepositoryImplTest {
|
|||
private val clientId = ClientId.AccountSession(session1.sessionId)
|
||||
|
||||
private val simpleCrypto = object : KeyStoreCrypto {
|
||||
override fun isUsingKeyStore(): Boolean = false
|
||||
override fun encrypt(value: String): EncryptedString = "encrypted-$value"
|
||||
override fun encrypt(value: PlainByteArray): EncryptedByteArray = EncryptedByteArray(value.array)
|
||||
override fun decrypt(value: EncryptedString): String = "decrypted-$value"
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ plugins {
|
|||
id("dagger.hilt.android.plugin")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android(useDataBinding = true)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ package me.proton.core.key.domain
|
|||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.crypto.common.keystore.PlainByteArray
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.key.domain.entity.key.KeyId
|
||||
import me.proton.core.key.domain.entity.key.PrivateKey
|
||||
import me.proton.core.key.domain.entity.keyholder.KeyHolder
|
||||
|
@ -39,7 +39,7 @@ class TestKeyHolder(
|
|||
key = privateKeyArmored,
|
||||
isPrimary = isPrimary,
|
||||
// Encrypt passphrase as it should be stored in PrivateKey.
|
||||
passphrase = PlainByteArray(privateKeyPassphrase).encryptWith(context.keyStoreCrypto)
|
||||
passphrase = PlainByteArray(privateKeyPassphrase).encrypt(context.keyStoreCrypto)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
implementation(
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
package me.proton.core.key.domain
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.crypto.common.pgp.DecryptedData
|
||||
|
@ -668,7 +668,7 @@ fun KeyHolderContext.decryptAndVerifyNestedKey(
|
|||
privateKey = nestedPrivateKey.privateKey.copy(
|
||||
passphrase = decryptDataOrNull(nestedPrivateKey.passphrase)
|
||||
?.takeIf { verifyKeyRing.verifyData(context, it, nestedPrivateKey.passphraseSignature) }
|
||||
?.let { plain -> plain.use { it.encryptWith(context.keyStoreCrypto) } }
|
||||
?.let { plain -> plain.use { it.encrypt(context.keyStoreCrypto) } }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -705,7 +705,7 @@ fun KeyHolderContext.encryptAndSignNestedKey(
|
|||
encryptKeyRing: PublicKeyRing = publicKeyRing
|
||||
): NestedPrivateKey {
|
||||
checkNotNull(nestedPrivateKey.privateKey.passphrase) { "Cannot encrypt without passphrase." }
|
||||
return nestedPrivateKey.privateKey.passphrase.decryptWith(context.keyStoreCrypto).use { passphrase ->
|
||||
return nestedPrivateKey.privateKey.passphrase.decrypt(context.keyStoreCrypto).use { passphrase ->
|
||||
nestedPrivateKey.copy(
|
||||
privateKey = nestedPrivateKey.privateKey.copy(passphrase = null),
|
||||
passphrase = encryptKeyRing.encryptData(context, passphrase.array),
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package me.proton.core.key.domain
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.pgp.EncryptedMessage
|
||||
import me.proton.core.crypto.common.pgp.KeyPacket
|
||||
import me.proton.core.crypto.common.pgp.SessionKey
|
||||
|
@ -181,7 +181,7 @@ fun PrivateKey.signData(context: CryptoContext, data: ByteArray): Signature =
|
|||
* @see [UnlockedPrivateKey.lock]
|
||||
*/
|
||||
fun PrivateKey.unlock(context: CryptoContext): UnlockedPrivateKey =
|
||||
requireNotNull(passphrase).decryptWith(context.keyStoreCrypto).use { decrypted ->
|
||||
requireNotNull(passphrase).decrypt(context.keyStoreCrypto).use { decrypted ->
|
||||
context.pgpCrypto.unlock(key, decrypted.array).let {
|
||||
UnlockedPrivateKey(it, isPrimary)
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ fun PrivateKey.unlock(context: CryptoContext): UnlockedPrivateKey =
|
|||
* @see [UnlockedPrivateKey.lock]
|
||||
*/
|
||||
fun PrivateKey.unlockOrNull(context: CryptoContext): UnlockedPrivateKey? =
|
||||
passphrase?.decryptWith(context.keyStoreCrypto)?.use { decrypted ->
|
||||
passphrase?.decrypt(context.keyStoreCrypto)?.use { decrypted ->
|
||||
context.pgpCrypto.unlockOrNull(key, decrypted.array)?.let {
|
||||
UnlockedPrivateKey(it, isPrimary)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ package me.proton.core.key.domain
|
|||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.pgp.EncryptedMessage
|
||||
import me.proton.core.crypto.common.pgp.KeyPacket
|
||||
import me.proton.core.crypto.common.pgp.SessionKey
|
||||
|
@ -211,16 +211,15 @@ fun UnlockedPrivateKey.lock(
|
|||
isActive: Boolean = true,
|
||||
canEncrypt: Boolean = true,
|
||||
canVerify: Boolean = true,
|
||||
): PrivateKey =
|
||||
passphrase.decryptWith(context.keyStoreCrypto).use { decrypted ->
|
||||
context.pgpCrypto.lock(unlockedKey.value, decrypted.array).let {
|
||||
PrivateKey(
|
||||
key = it,
|
||||
isPrimary = isPrimary,
|
||||
isActive = isActive,
|
||||
canEncrypt = canEncrypt,
|
||||
canVerify = canVerify,
|
||||
passphrase = passphrase
|
||||
)
|
||||
}
|
||||
): PrivateKey = passphrase.decrypt(context.keyStoreCrypto).use { decrypted ->
|
||||
context.pgpCrypto.lock(unlockedKey.value, decrypted.array).let {
|
||||
PrivateKey(
|
||||
key = it,
|
||||
isPrimary = isPrimary,
|
||||
isActive = isActive,
|
||||
canEncrypt = canEncrypt,
|
||||
canVerify = canVerify,
|
||||
passphrase = passphrase
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package me.proton.core.key.domain.entity.key
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.crypto.common.pgp.EncryptedMessage
|
||||
|
@ -65,7 +65,7 @@ data class NestedPrivateKey(
|
|||
domain = domain,
|
||||
passphrase = passphrase.array
|
||||
)
|
||||
val encryptedPassphrase = passphrase.encryptWith(context.keyStoreCrypto)
|
||||
val encryptedPassphrase = passphrase.encrypt(context.keyStoreCrypto)
|
||||
val keyHolderPrivateKey = PrivateKey(
|
||||
key = privateKey,
|
||||
isPrimary = true,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package me.proton.core.key.domain.extension
|
||||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.crypto.common.pgp.updatePrivateKeyPassphraseOrNull
|
||||
import me.proton.core.key.domain.entity.key.Key
|
||||
|
@ -29,7 +29,7 @@ fun KeyHolderPrivateKey.updatePrivateKeyPassphraseOrNull(
|
|||
cryptoContext: CryptoContext,
|
||||
newPassphrase: ByteArray
|
||||
): Key? {
|
||||
val passphrase = privateKey.passphrase?.decryptWith(cryptoContext.keyStoreCrypto)?.array ?: return null
|
||||
val passphrase = privateKey.passphrase?.decrypt(cryptoContext.keyStoreCrypto)?.array ?: return null
|
||||
return cryptoContext.pgpCrypto.updatePrivateKeyPassphraseOrNull(
|
||||
privateKey = privateKey.key,
|
||||
passphrase = passphrase,
|
||||
|
|
|
@ -52,6 +52,9 @@ class TestCryptoContext : CryptoContext {
|
|||
|
||||
// Use the defaultKey to encrypt/decrypt.
|
||||
override val keyStoreCrypto: KeyStoreCrypto = object : KeyStoreCrypto {
|
||||
|
||||
override fun isUsingKeyStore(): Boolean = false
|
||||
|
||||
override fun encrypt(value: String): EncryptedString =
|
||||
value.toByteArray().encrypt(defaultKey).fromByteArray()
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package me.proton.core.key.domain
|
||||
|
||||
import me.proton.core.crypto.common.keystore.PlainByteArray
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.key.domain.entity.key.KeyId
|
||||
import me.proton.core.key.domain.entity.key.PrivateKey
|
||||
import me.proton.core.key.domain.entity.keyholder.KeyHolder
|
||||
|
@ -46,7 +46,7 @@ class TestKeyHolder(
|
|||
isPrimary = isPrimary,
|
||||
isActive = isActive,
|
||||
// Encrypt passphrase as it should be stored in PrivateKey.
|
||||
passphrase = passphrase?.let { PlainByteArray(passphrase).encryptWith(context.keyStoreCrypto) }
|
||||
passphrase = passphrase?.let { PlainByteArray(passphrase).encrypt(context.keyStoreCrypto) }
|
||||
).also { key ->
|
||||
// Workaround: Remember unlockedKey to be able to decrypt messages encrypted with PublicKey.
|
||||
val publicKey = context.pgpCrypto.getPublicKey(key.key)
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ import me.proton.core.network.domain.server.ServerTimeListener
|
|||
import me.proton.core.network.domain.session.SessionId
|
||||
import me.proton.core.network.domain.session.SessionListener
|
||||
import me.proton.core.network.domain.session.SessionProvider
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import me.proton.core.util.kotlin.ProtonCoreConfig
|
||||
import okhttp3.Cache
|
||||
import okhttp3.JavaNetCookieJar
|
||||
|
@ -71,7 +70,6 @@ class ApiManagerFactory(
|
|||
private val apiClient: ApiClient,
|
||||
private val clientIdProvider: ClientIdProvider,
|
||||
private val serverTimeListener: ServerTimeListener,
|
||||
private val logger: Logger,
|
||||
private val networkManager: NetworkManager,
|
||||
private val prefs: NetworkPrefs,
|
||||
private val sessionProvider: SessionProvider,
|
||||
|
@ -117,7 +115,7 @@ class ApiManagerFactory(
|
|||
|
||||
private val dohProvider by lazy {
|
||||
val dohServices = Constants.DOH_PROVIDERS_URLS.map { serviceUrl ->
|
||||
DnsOverHttpsProviderRFC8484(baseOkHttpClient, serviceUrl, apiClient, networkManager, logger)
|
||||
DnsOverHttpsProviderRFC8484(baseOkHttpClient, serviceUrl, apiClient, networkManager)
|
||||
}
|
||||
DohProvider(baseUrl, apiClient, dohServices, mainScope, prefs, ::javaMonoClockMs)
|
||||
}
|
||||
|
@ -169,7 +167,6 @@ class ApiManagerFactory(
|
|||
apiClient,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
sessionId,
|
||||
sessionProvider,
|
||||
humanVerificationProvider,
|
||||
|
@ -199,7 +196,6 @@ class ApiManagerFactory(
|
|||
apiClient,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
sessionId,
|
||||
sessionProvider,
|
||||
humanVerificationProvider,
|
||||
|
|
|
@ -20,7 +20,7 @@ package me.proton.core.network.data
|
|||
import kotlinx.serialization.SerializationException
|
||||
import me.proton.core.network.domain.ApiResult
|
||||
import me.proton.core.network.domain.NetworkManager
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import okhttp3.Response
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
@ -32,7 +32,6 @@ import javax.net.ssl.SSLPeerUnverifiedException
|
|||
|
||||
internal suspend fun <Api, T> safeApiCall(
|
||||
networkManager: NetworkManager,
|
||||
logger: Logger,
|
||||
api: Api,
|
||||
block: suspend (Api) -> T
|
||||
): ApiResult<T> {
|
||||
|
@ -58,7 +57,7 @@ internal suspend fun <Api, T> safeApiCall(
|
|||
ApiResult.Error.Connection(networkManager.isConnectedToNetwork(), e)
|
||||
}
|
||||
if (result is ApiResult.Error) {
|
||||
result.cause?.let { logger.e(LogTag.DEFAULT, it) }
|
||||
result.cause?.let { CoreLogger.e(LogTag.DEFAULT, it) }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -19,17 +19,17 @@ package me.proton.core.network.data
|
|||
|
||||
import android.os.SystemClock
|
||||
import me.proton.core.network.domain.ApiClient
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
|
||||
internal fun OkHttpClient.Builder.initLogging(client: ApiClient, logger: Logger): OkHttpClient.Builder {
|
||||
internal fun OkHttpClient.Builder.initLogging(client: ApiClient): OkHttpClient.Builder {
|
||||
if (client.enableDebugLogging) {
|
||||
// HttpLoggingInterceptor generate log messages and forward them into provided Logger.
|
||||
addInterceptor(
|
||||
HttpLoggingInterceptor(
|
||||
logger = object : HttpLoggingInterceptor.Logger {
|
||||
override fun log(message: String) = logger.d(LogTag.DEFAULT, message)
|
||||
override fun log(message: String) = CoreLogger.d(LogTag.DEFAULT, message)
|
||||
}
|
||||
).apply { level = HttpLoggingInterceptor.Level.BODY }
|
||||
)
|
||||
|
@ -38,7 +38,7 @@ internal fun OkHttpClient.Builder.initLogging(client: ApiClient, logger: Logger)
|
|||
addInterceptor { chain ->
|
||||
val request = chain.request()
|
||||
val auth = request.header("Authorization").formatToken(client)
|
||||
logger.log(
|
||||
CoreLogger.log(
|
||||
LogTag.API_CALL,
|
||||
with(request) { "--> $method $url (auth $auth)" },
|
||||
)
|
||||
|
@ -46,7 +46,7 @@ internal fun OkHttpClient.Builder.initLogging(client: ApiClient, logger: Logger)
|
|||
val startMs = SystemClock.elapsedRealtime()
|
||||
val response = chain.proceed(request)
|
||||
val durationMs = SystemClock.elapsedRealtime() - startMs
|
||||
logger.log(
|
||||
CoreLogger.log(
|
||||
LogTag.API_CALL,
|
||||
with(response) { "<-- $code $message ${request.method} ${request.url} (${durationMs}ms)" }
|
||||
)
|
||||
|
|
|
@ -35,7 +35,7 @@ import me.proton.core.network.domain.server.ServerTimeListener
|
|||
import me.proton.core.network.domain.session.Session
|
||||
import me.proton.core.network.domain.session.SessionId
|
||||
import me.proton.core.network.domain.session.SessionProvider
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
import me.proton.core.util.kotlin.takeIfNotBlank
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
|
@ -65,7 +65,6 @@ internal class ProtonApiBackend<Api : BaseRetrofitApi>(
|
|||
private val client: ApiClient,
|
||||
private val clientIdProvider: ClientIdProvider,
|
||||
serverTimeListener: ServerTimeListener,
|
||||
private val logger: Logger,
|
||||
private val sessionId: SessionId?,
|
||||
private val sessionProvider: SessionProvider,
|
||||
private val humanVerificationProvider: HumanVerificationProvider,
|
||||
|
@ -85,7 +84,7 @@ internal class ProtonApiBackend<Api : BaseRetrofitApi>(
|
|||
val chain = handleTimeoutTag(orgChain)
|
||||
chain.proceed(prepareHeaders(chain.request()).build())
|
||||
}
|
||||
.initLogging(client, logger)
|
||||
.initLogging(client)
|
||||
.addInterceptor(ServerErrorInterceptor())
|
||||
.addInterceptor(TooManyRequestInterceptor(sessionId, wallClockMs))
|
||||
.addNetworkInterceptor(ServerTimeInterceptor(serverTimeListener))
|
||||
|
@ -147,7 +146,7 @@ internal class ProtonApiBackend<Api : BaseRetrofitApi>(
|
|||
invokeInternal(call.block)
|
||||
|
||||
private suspend fun <T> invokeInternal(block: suspend Api.() -> T): ApiResult<T> =
|
||||
safeApiCall(networkManager, logger, api, block)
|
||||
safeApiCall(networkManager, api, block)
|
||||
|
||||
override suspend fun refreshSession(session: Session): ApiResult<Session> {
|
||||
val result = invokeInternal {
|
||||
|
@ -155,8 +154,7 @@ internal class ProtonApiBackend<Api : BaseRetrofitApi>(
|
|||
}
|
||||
return when (result) {
|
||||
is ApiResult.Success -> {
|
||||
logger.log(LogTag.REFRESH_TOKEN, "new access token: ${result.value.accessToken.formatToken(client)}")
|
||||
logger.log(LogTag.REFRESH_TOKEN, "new refresh token: ${result.value.refreshToken.formatToken(client)}")
|
||||
CoreLogger.log(LogTag.REFRESH_TOKEN, "Access & refresh tokens refreshed.")
|
||||
ApiResult.Success(
|
||||
session.refreshWith(
|
||||
accessToken = result.value.accessToken,
|
||||
|
|
|
@ -24,7 +24,6 @@ import me.proton.core.network.domain.ApiClient
|
|||
import me.proton.core.network.domain.ApiResult
|
||||
import me.proton.core.network.domain.DohService
|
||||
import me.proton.core.network.domain.NetworkManager
|
||||
import me.proton.core.util.kotlin.Logger
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.ResponseBody
|
||||
import org.apache.commons.codec.binary.Base32
|
||||
|
@ -43,8 +42,7 @@ class DnsOverHttpsProviderRFC8484(
|
|||
baseOkHttpClient: OkHttpClient,
|
||||
private val baseUrl: String,
|
||||
client: ApiClient,
|
||||
private val networkManager: NetworkManager,
|
||||
private val logger: Logger
|
||||
private val networkManager: NetworkManager
|
||||
) : DohService {
|
||||
|
||||
private val api: DnsOverHttpsRetrofitApi
|
||||
|
@ -68,7 +66,7 @@ class DnsOverHttpsProviderRFC8484(
|
|||
.connectTimeout(TIMEOUT_S, TimeUnit.SECONDS)
|
||||
.writeTimeout(TIMEOUT_S, TimeUnit.SECONDS)
|
||||
.readTimeout(TIMEOUT_S, TimeUnit.SECONDS)
|
||||
.initLogging(client, logger)
|
||||
.initLogging(client)
|
||||
|
||||
val okClient = httpClientBuilder.build()
|
||||
api = Retrofit.Builder()
|
||||
|
@ -87,10 +85,12 @@ class DnsOverHttpsProviderRFC8484(
|
|||
.setRecursionDesired(true)
|
||||
.setQuestion(question)
|
||||
.build()
|
||||
val queryMessageBase64 = Base64.encodeToString(queryMessage.toArray(),
|
||||
Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
|
||||
val queryMessageBase64 = Base64.encodeToString(
|
||||
queryMessage.toArray(),
|
||||
Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP
|
||||
)
|
||||
|
||||
val response = safeApiCall(networkManager, logger, api) {
|
||||
val response = safeApiCall(networkManager, api) {
|
||||
api.getServers(baseUrl.removeSuffix("/"), queryMessageBase64)
|
||||
}
|
||||
if (response is ApiResult.Success) {
|
||||
|
|
|
@ -31,7 +31,6 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
|
|||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import me.proton.core.network.data.util.MockApiClient
|
||||
import me.proton.core.network.data.util.MockClientId
|
||||
import me.proton.core.network.data.util.MockLogger
|
||||
import me.proton.core.network.data.util.MockNetworkManager
|
||||
import me.proton.core.network.data.util.MockNetworkPrefs
|
||||
import me.proton.core.network.data.util.MockSession
|
||||
|
@ -133,7 +132,6 @@ internal class ApiManagerTests {
|
|||
apiClient,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
MockLogger(),
|
||||
networkManager,
|
||||
prefs,
|
||||
sessionProvider,
|
||||
|
|
|
@ -24,7 +24,6 @@ import io.mockk.impl.annotations.MockK
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import me.proton.core.network.data.doh.DnsOverHttpsProviderRFC8484
|
||||
import me.proton.core.network.data.util.MockApiClient
|
||||
import me.proton.core.network.data.util.MockLogger
|
||||
import me.proton.core.network.domain.NetworkManager
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
|
@ -70,8 +69,7 @@ internal class DohProviderTests {
|
|||
okHttpClient,
|
||||
webServer.url("/").toString(),
|
||||
client,
|
||||
networkManager,
|
||||
MockLogger()
|
||||
networkManager
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,6 @@ internal class HumanVerificationTests {
|
|||
client,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
networkManager,
|
||||
prefs,
|
||||
sessionProvider,
|
||||
|
@ -184,7 +183,6 @@ internal class HumanVerificationTests {
|
|||
client,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
sessionId,
|
||||
sessionProvider,
|
||||
humanVerificationProvider,
|
||||
|
|
|
@ -107,7 +107,6 @@ internal class ProtonApiBackendTests {
|
|||
@BeforeTest
|
||||
fun before() {
|
||||
MockKAnnotations.init(this)
|
||||
logger = MockLogger()
|
||||
client = MockApiClient()
|
||||
prefs = MockNetworkPrefs()
|
||||
|
||||
|
@ -123,7 +122,6 @@ internal class ProtonApiBackendTests {
|
|||
client,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
networkManager,
|
||||
prefs,
|
||||
sessionProvider,
|
||||
|
@ -163,7 +161,6 @@ internal class ProtonApiBackendTests {
|
|||
client,
|
||||
clientIdProvider,
|
||||
serverTimeListener,
|
||||
logger,
|
||||
session.sessionId,
|
||||
sessionProvider,
|
||||
humanVerificationProvider,
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 1)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 1)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 1)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import me.proton.core.auth.domain.ClientSecret
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpProofs
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -57,8 +57,8 @@ class PerformUpdateLoginPassword @Inject constructor(
|
|||
)
|
||||
val modulus = authRepository.randomModulus()
|
||||
|
||||
password.decryptWith(keyStore).toByteArray().use { decryptedPassword ->
|
||||
newPassword.decryptWith(keyStore).toByteArray().use { decryptedNewPassword ->
|
||||
password.decrypt(keyStore).toByteArray().use { decryptedPassword ->
|
||||
newPassword.decrypt(keyStore).toByteArray().use { decryptedNewPassword ->
|
||||
val clientProofs: SrpProofs = srp.generateSrpProofs(
|
||||
username = username,
|
||||
password = decryptedPassword.array,
|
||||
|
|
|
@ -23,7 +23,7 @@ import me.proton.core.auth.domain.ClientSecret
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.crypto.common.srp.SrpProofs
|
||||
|
@ -50,7 +50,7 @@ class PerformUpdateRecoveryEmail @Inject constructor(
|
|||
username = username,
|
||||
clientSecret = clientSecret
|
||||
)
|
||||
password.decryptWith(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
password.decrypt(keyStoreCrypto).toByteArray().use { decryptedPassword ->
|
||||
val clientProofs: SrpProofs = srpCrypto.generateSrpProofs(
|
||||
username = username,
|
||||
password = decryptedPassword.array,
|
||||
|
|
|
@ -22,7 +22,7 @@ import me.proton.core.auth.domain.ClientSecret
|
|||
import me.proton.core.auth.domain.repository.AuthRepository
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.srp.SrpProofs
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -61,8 +61,8 @@ class PerformUpdateUserPassword @Inject constructor(
|
|||
organizationRepository.getOrganizationKeys(userId)
|
||||
} else null
|
||||
|
||||
loginPassword.decryptWith(keyStore).toByteArray().use { decryptedLoginPassword ->
|
||||
newPassword.decryptWith(keyStore).toByteArray().use { decryptedNewPassword ->
|
||||
loginPassword.decrypt(keyStore).toByteArray().use { decryptedLoginPassword ->
|
||||
newPassword.decrypt(keyStore).toByteArray().use { decryptedNewPassword ->
|
||||
val clientProofs: SrpProofs = srp.generateSrpProofs(
|
||||
username = username,
|
||||
password = decryptedLoginPassword.array,
|
||||
|
|
|
@ -27,7 +27,7 @@ plugins {
|
|||
id("dagger.hilt.android.plugin")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 1)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android(useDataBinding = true)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.flow
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.presentation.viewmodel.ProtonViewModel
|
||||
import me.proton.core.usersettings.domain.entity.UserSettings
|
||||
|
@ -95,8 +95,8 @@ class PasswordManagementViewModel @Inject constructor(
|
|||
return@flow
|
||||
}
|
||||
emit(State.UpdatingLoginPassword)
|
||||
val encryptedPassword = password.encryptWith(keyStoreCrypto)
|
||||
val encryptedNewPassword = newPassword.encryptWith(keyStoreCrypto)
|
||||
val encryptedPassword = password.encrypt(keyStoreCrypto)
|
||||
val encryptedNewPassword = newPassword.encrypt(keyStoreCrypto)
|
||||
|
||||
val result = performUpdateLoginPassword(
|
||||
userId = userId,
|
||||
|
@ -121,8 +121,8 @@ class PasswordManagementViewModel @Inject constructor(
|
|||
secondFactorCode: String = ""
|
||||
) = flow {
|
||||
emit(if (twoPasswordMode == true) State.UpdatingMailboxPassword else State.UpdatingSinglePassModePassword)
|
||||
val encryptedLoginPassword = loginPassword.encryptWith(keyStoreCrypto)
|
||||
val encryptedNewMailboxPassword = newMailboxPassword.encryptWith(keyStoreCrypto)
|
||||
val encryptedLoginPassword = loginPassword.encrypt(keyStoreCrypto)
|
||||
val encryptedNewMailboxPassword = newMailboxPassword.encrypt(keyStoreCrypto)
|
||||
val result = performUpdateUserPassword.invoke(
|
||||
twoPasswordMode = twoPasswordMode!!,
|
||||
userId = userId,
|
||||
|
|
|
@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.flow
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.presentation.viewmodel.ProtonViewModel
|
||||
import me.proton.core.user.domain.repository.UserRepository
|
||||
|
@ -84,7 +84,7 @@ class UpdateRecoveryEmailViewModel @Inject constructor(
|
|||
secondFactorCode: String
|
||||
) = flow {
|
||||
emit(State.UpdatingCurrent)
|
||||
val encryptedPassword = password.encryptWith(keyStoreCrypto)
|
||||
val encryptedPassword = password.encrypt(keyStoreCrypto)
|
||||
val user = userRepository.getUser(userId)
|
||||
val username = requireNotNull(user.name ?: user.email)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("android")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
android()
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ package me.proton.core.user.data
|
|||
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
@ -86,7 +86,7 @@ class UserAddressKeySecretProvider(
|
|||
// New address key format -> user keys encrypt token + signature -> address passphrase.
|
||||
cryptoContext.pgpCrypto.generateNewToken().use { passphrase ->
|
||||
UserAddressKeySecret(
|
||||
passphrase = passphrase.encryptWith(keyStoreCrypto),
|
||||
passphrase = passphrase.encrypt(keyStoreCrypto),
|
||||
token = userPrivateKey.encryptData(cryptoContext, passphrase.array),
|
||||
signature = userPrivateKey.signData(cryptoContext, passphrase.array)
|
||||
)
|
||||
|
@ -102,7 +102,7 @@ class UserAddressKeySecretProvider(
|
|||
isPrimary: Boolean
|
||||
): UserAddressKey {
|
||||
val secret = generateUserAddressKeySecret(userPrivateKey, generateOldFormat)
|
||||
secret.passphrase.decryptWith(keyStoreCrypto).use { decryptedPassphrase ->
|
||||
secret.passphrase.decrypt(keyStoreCrypto).use { decryptedPassphrase ->
|
||||
val email = userAddress.emailSplit
|
||||
val privateKey = PrivateKey(
|
||||
key = cryptoContext.pgpCrypto.generateNewPrivateKey(
|
||||
|
|
|
@ -24,8 +24,8 @@ import me.proton.core.crypto.common.context.CryptoContext
|
|||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
import me.proton.core.crypto.common.keystore.PlainByteArray
|
||||
import me.proton.core.crypto.common.keystore.decryptWith
|
||||
import me.proton.core.crypto.common.keystore.encryptWith
|
||||
import me.proton.core.crypto.common.keystore.decrypt
|
||||
import me.proton.core.crypto.common.keystore.encrypt
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.crypto.common.srp.Auth
|
||||
|
@ -103,7 +103,7 @@ class UserManagerImpl(
|
|||
?: return UnlockResult.Error.NoKeySaltsForPrimaryKey
|
||||
|
||||
val passphrase = pgp.getPassphrase(password.array, primaryKeySalt).use {
|
||||
it.encryptWith(keyStore)
|
||||
it.encrypt(keyStore)
|
||||
}
|
||||
return unlockWithPassphrase(userId, passphrase, refresh = false)
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class UserManagerImpl(
|
|||
auth: Auth?,
|
||||
orgPrivateKey: Armored?
|
||||
): Boolean {
|
||||
newPassword.decryptWith(keyStore).toByteArray().use { decryptedNewPassword ->
|
||||
newPassword.decrypt(keyStore).toByteArray().use { decryptedNewPassword ->
|
||||
val keySalt = pgp.generateNewKeySalt()
|
||||
pgp.getPassphrase(decryptedNewPassword.array, keySalt).use { newPassphrase ->
|
||||
val addresses = userAddressRepository.getAddresses(userId, refresh = true)
|
||||
|
@ -157,7 +157,7 @@ class UserManagerImpl(
|
|||
// Update organization key if provided.
|
||||
val updatedOrgPrivateKey = orgPrivateKey?.let { key ->
|
||||
val encryptedPassphrase = requireNotNull(passphraseRepository.getPassphrase(userId))
|
||||
encryptedPassphrase.decryptWith(keyStore).use {
|
||||
encryptedPassphrase.decrypt(keyStore).use {
|
||||
key.updatePrivateKeyPassphrase(cryptoContext, it.array, newPassphrase.array)
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ class UserManagerImpl(
|
|||
)
|
||||
|
||||
// We know we can unlock the key with this passphrase as we just generated from it.
|
||||
passphraseRepository.setPassphrase(userId, newPassphrase.encryptWith(keyStore))
|
||||
passphraseRepository.setPassphrase(userId, newPassphrase.encrypt(keyStore))
|
||||
|
||||
// Refresh User and Addresses.
|
||||
userAddressRepository.getAddresses(userId, refresh = true)
|
||||
|
@ -202,7 +202,7 @@ class UserManagerImpl(
|
|||
domain = domain,
|
||||
passphrase = passphrase.array
|
||||
)
|
||||
val encryptedPassphrase = passphrase.encryptWith(keyStore)
|
||||
val encryptedPassphrase = passphrase.encrypt(keyStore)
|
||||
val userPrivateKey = PrivateKey(
|
||||
key = privateKey,
|
||||
isPrimary = true,
|
||||
|
|
|
@ -23,7 +23,7 @@ plugins {
|
|||
kotlin("jvm")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
implementation(
|
||||
|
|
|
@ -24,7 +24,7 @@ plugins {
|
|||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
libVersion = Version(1, 15, 0)
|
||||
libVersion = Version(1, 15, 2)
|
||||
|
||||
dependencies {
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package me.proton.core.util.kotlin
|
||||
|
||||
import me.proton.core.util.kotlin.CoreLogger.set
|
||||
import org.jetbrains.annotations.NonNls
|
||||
|
||||
/**
|
||||
|
@ -58,4 +59,55 @@ interface Logger {
|
|||
}
|
||||
|
||||
/** Type for all tags used in conjunction with [Logger.log]. */
|
||||
inline class LoggerLogTag(val name: String)
|
||||
@JvmInline
|
||||
value class LoggerLogTag(val name: String)
|
||||
|
||||
/**
|
||||
* Main object/singleton any Core module is using to log.
|
||||
*
|
||||
* Call [set] to set your own [Logger].
|
||||
*/
|
||||
object CoreLogger : Logger {
|
||||
|
||||
private var logger: Logger? = null
|
||||
|
||||
fun set(logger: Logger) {
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
override fun e(tag: String, e: Throwable) {
|
||||
logger?.e(tag, e)
|
||||
}
|
||||
|
||||
override fun e(tag: String, e: Throwable, message: String) {
|
||||
logger?.e(tag, e, message)
|
||||
}
|
||||
|
||||
override fun i(tag: String, message: String) {
|
||||
logger?.i(tag, message)
|
||||
}
|
||||
|
||||
override fun i(tag: String, e: Throwable, message: String) {
|
||||
logger?.i(tag, e, message)
|
||||
}
|
||||
|
||||
override fun d(tag: String, message: String) {
|
||||
logger?.d(tag, message)
|
||||
}
|
||||
|
||||
override fun d(tag: String, e: Throwable, message: String) {
|
||||
logger?.d(tag, e, message)
|
||||
}
|
||||
|
||||
override fun v(tag: String, message: String) {
|
||||
logger?.v(tag, message)
|
||||
}
|
||||
|
||||
override fun v(tag: String, e: Throwable, message: String) {
|
||||
logger?.v(tag, e, message)
|
||||
}
|
||||
|
||||
override fun log(tag: LoggerLogTag, message: String) {
|
||||
logger?.log(tag, message)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue