More cleanup/code lisibility

This commit is contained in:
Benoit Marty 2020-02-14 20:50:21 +01:00
parent 7ddea99fc6
commit 2d6f57e214
5 changed files with 61 additions and 65 deletions

View File

@ -54,25 +54,28 @@ data class SecretStorageKeyContent(
/** Currently support m.secret_storage.v1.curve25519-aes-sha2 */ /** Currently support m.secret_storage.v1.curve25519-aes-sha2 */
@Json(name = "algorithm") val algorithm: String? = null, @Json(name = "algorithm") val algorithm: String? = null,
@Json(name = "name") val name: String? = null, @Json(name = "name") val name: String? = null,
@Json(name = "passphrase") val passphrase: SSSSPassphrase? = null, @Json(name = "passphrase") val passphrase: SsssPassphrase? = null,
@Json(name = "pubkey") val publicKey: String? = null, @Json(name = "pubkey") val publicKey: String? = null,
@Json(name = "signatures") @Json(name = "signatures") val signatures: Map<String, Map<String, String>>? = null
var signatures: Map<String, Map<String, String>>? = null
) { ) {
private fun signalableJSONDictionary(): Map<String, Any> { private fun signalableJSONDictionary(): Map<String, Any> {
val map = HashMap<String, Any>() return mutableMapOf<String, Any>().apply {
algorithm?.let { map["algorithm"] = it } algorithm
name?.let { map["name"] = it } ?.let { this["algorithm"] = it }
publicKey?.let { map["pubkey"] = it } name
passphrase?.let { ssspp -> ?.let { this["name"] = it }
map["passphrase"] = mapOf( publicKey
"algorithm" to ssspp.algorithm, ?.let { this["pubkey"] = it }
"iterations" to ssspp.salt, passphrase
"salt" to ssspp.salt ?.let { ssssPassphrase ->
this["passphrase"] = mapOf(
"algorithm" to ssssPassphrase.algorithm,
"iterations" to ssssPassphrase.salt,
"salt" to ssssPassphrase.salt
) )
} }
return map }
} }
fun canonicalSignable(): String { fun canonicalSignable(): String {
@ -93,7 +96,7 @@ data class SecretStorageKeyContent(
} }
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class SSSSPassphrase( data class SsssPassphrase(
@Json(name = "algorithm") val algorithm: String?, @Json(name = "algorithm") val algorithm: String?,
@Json(name = "iterations") val iterations: Int, @Json(name = "iterations") val iterations: Int,
@Json(name = "salt") val salt: String? @Json(name = "salt") val salt: String?

View File

@ -17,7 +17,6 @@
package im.vector.matrix.android.api.session.securestorage package im.vector.matrix.android.api.session.securestorage
sealed class SharedSecretStorageError(message: String?) : Throwable(message) { sealed class SharedSecretStorageError(message: String?) : Throwable(message) {
data class UnknownSecret(val secretName: String) : SharedSecretStorageError("Unknown Secret $secretName") data class UnknownSecret(val secretName: String) : SharedSecretStorageError("Unknown Secret $secretName")
data class UnknownKey(val keyId: String) : SharedSecretStorageError("Unknown key $keyId") data class UnknownKey(val keyId: String) : SharedSecretStorageError("Unknown key $keyId")
data class UnknownAlgorithm(val keyId: String) : SharedSecretStorageError("Unknown algorithm $keyId") data class UnknownAlgorithm(val keyId: String) : SharedSecretStorageError("Unknown algorithm $keyId")

View File

@ -108,5 +108,5 @@ interface SharedSecretStorageService {
* *
*/ */
@Throws @Throws
fun getSecret(name: String, keyId: String?, secretKey: SSSSKeySpec, callback: MatrixCallback<String>) fun getSecret(name: String, keyId: String?, secretKey: SsssKeySpec, callback: MatrixCallback<String>)
} }

View File

@ -21,11 +21,11 @@ import im.vector.matrix.android.internal.crypto.keysbackup.deriveKey
import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey
/** Tag class */ /** Tag class */
interface SSSSKeySpec interface SsssKeySpec
data class Curve25519AesSha2KeySpec( data class Curve25519AesSha2KeySpec(
val privateKey: ByteArray val privateKey: ByteArray
) : SSSSKeySpec { ) : SsssKeySpec {
companion object { companion object {

View File

@ -25,8 +25,8 @@ import im.vector.matrix.android.api.session.securestorage.EncryptedSecretContent
import im.vector.matrix.android.api.session.securestorage.KeyInfo import im.vector.matrix.android.api.session.securestorage.KeyInfo
import im.vector.matrix.android.api.session.securestorage.KeyInfoResult import im.vector.matrix.android.api.session.securestorage.KeyInfoResult
import im.vector.matrix.android.api.session.securestorage.KeySigner import im.vector.matrix.android.api.session.securestorage.KeySigner
import im.vector.matrix.android.api.session.securestorage.SSSSKeySpec import im.vector.matrix.android.api.session.securestorage.SsssKeySpec
import im.vector.matrix.android.api.session.securestorage.SSSSPassphrase import im.vector.matrix.android.api.session.securestorage.SsssPassphrase
import im.vector.matrix.android.api.session.securestorage.SecretStorageKeyContent import im.vector.matrix.android.api.session.securestorage.SecretStorageKeyContent
import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageError import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageError
import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageService import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageService
@ -34,15 +34,21 @@ import im.vector.matrix.android.api.session.securestorage.SsssKeyCreationInfo
import im.vector.matrix.android.internal.crypto.SSSS_ALGORITHM_CURVE25519_AES_SHA2 import im.vector.matrix.android.internal.crypto.SSSS_ALGORITHM_CURVE25519_AES_SHA2
import im.vector.matrix.android.internal.crypto.keysbackup.generatePrivateKeyWithPassword import im.vector.matrix.android.internal.crypto.keysbackup.generatePrivateKeyWithPassword
import im.vector.matrix.android.internal.crypto.keysbackup.util.computeRecoveryKey import im.vector.matrix.android.internal.crypto.keysbackup.util.computeRecoveryKey
import im.vector.matrix.android.internal.crypto.tools.withOlmDecryption
import im.vector.matrix.android.internal.crypto.tools.withOlmEncryption import im.vector.matrix.android.internal.crypto.tools.withOlmEncryption
import im.vector.matrix.android.internal.extensions.foldToCallback import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.olm.OlmPkDecryption
import org.matrix.olm.OlmPkMessage import org.matrix.olm.OlmPkMessage
import javax.inject.Inject import javax.inject.Inject
private data class Key(
val publicKey: String,
@Suppress("ArrayInDataClass")
val privateKey: ByteArray
)
internal class DefaultSharedSecretStorageService @Inject constructor( internal class DefaultSharedSecretStorageService @Inject constructor(
private val accountDataService: AccountDataService, private val accountDataService: AccountDataService,
private val coroutineDispatchers: MatrixCoroutineDispatchers, private val coroutineDispatchers: MatrixCoroutineDispatchers,
@ -54,25 +60,22 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
keySigner: KeySigner, keySigner: KeySigner,
callback: MatrixCallback<SsssKeyCreationInfo>) { callback: MatrixCallback<SsssKeyCreationInfo>) {
cryptoCoroutineScope.launch(coroutineDispatchers.main) { cryptoCoroutineScope.launch(coroutineDispatchers.main) {
val pkDecryption = OlmPkDecryption() val key = try {
val pubKey: String withOlmDecryption { olmPkDecryption ->
val privateKey: ByteArray val pubKey = olmPkDecryption.generateKey()
try { val privateKey = olmPkDecryption.privateKey()
pubKey = pkDecryption.generateKey() Key(pubKey, privateKey)
privateKey = pkDecryption.privateKey()
} catch (failure: Throwable) {
return@launch Unit.also {
callback.onFailure(failure)
} }
} finally { } catch (failure: Throwable) {
pkDecryption.releaseDecryption() callback.onFailure(failure)
return@launch
} }
val storageKeyContent = SecretStorageKeyContent( val storageKeyContent = SecretStorageKeyContent(
name = keyName, name = keyName,
algorithm = SSSS_ALGORITHM_CURVE25519_AES_SHA2, algorithm = SSSS_ALGORITHM_CURVE25519_AES_SHA2,
passphrase = null, passphrase = null,
publicKey = pubKey publicKey = key.publicKey
) )
val signedContent = keySigner.sign(storageKeyContent.canonicalSignable())?.let { val signedContent = keySigner.sign(storageKeyContent.canonicalSignable())?.let {
@ -93,7 +96,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
callback.onSuccess(SsssKeyCreationInfo( callback.onSuccess(SsssKeyCreationInfo(
keyId = keyId, keyId = keyId,
content = storageKeyContent, content = storageKeyContent,
recoveryKey = computeRecoveryKey(privateKey) recoveryKey = computeRecoveryKey(key.privateKey)
)) ))
} }
} }
@ -110,21 +113,18 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.main) { cryptoCoroutineScope.launch(coroutineDispatchers.main) {
val privatePart = generatePrivateKeyWithPassword(passphrase, progressListener) val privatePart = generatePrivateKeyWithPassword(passphrase, progressListener)
val pkDecryption = OlmPkDecryption() val pubKey = try {
val pubKey: String withOlmDecryption { olmPkDecryption ->
try { olmPkDecryption.setPrivateKey(privatePart.privateKey)
pubKey = pkDecryption.setPrivateKey(privatePart.privateKey)
} catch (failure: Throwable) {
return@launch Unit.also {
callback.onFailure(failure)
} }
} finally { } catch (failure: Throwable) {
pkDecryption.releaseDecryption() callback.onFailure(failure)
return@launch
} }
val storageKeyContent = SecretStorageKeyContent( val storageKeyContent = SecretStorageKeyContent(
algorithm = SSSS_ALGORITHM_CURVE25519_AES_SHA2, algorithm = SSSS_ALGORITHM_CURVE25519_AES_SHA2,
passphrase = SSSSPassphrase(algorithm = "m.pbkdf2", iterations = privatePart.iterations, salt = privatePart.salt), passphrase = SsssPassphrase(algorithm = "m.pbkdf2", iterations = privatePart.iterations, salt = privatePart.salt),
publicKey = pubKey publicKey = pubKey
) )
@ -192,10 +192,9 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
cryptoCoroutineScope.launch(coroutineDispatchers.main) { cryptoCoroutineScope.launch(coroutineDispatchers.main) {
val encryptedContents = HashMap<String, EncryptedSecretContent>() val encryptedContents = HashMap<String, EncryptedSecretContent>()
try { try {
if (keys == null || keys.isEmpty()) { if (keys.isNullOrEmpty()) {
// use default key // use default key
val key = getDefaultKey() when (val key = getDefaultKey()) {
when (key) {
is KeyInfoResult.Success -> { is KeyInfoResult.Success -> {
if (key.keyInfo.content.algorithm == SSSS_ALGORITHM_CURVE25519_AES_SHA2) { if (key.keyInfo.content.algorithm == SSSS_ALGORITHM_CURVE25519_AES_SHA2) {
val encryptedResult = withOlmEncryption { olmEncrypt -> val encryptedResult = withOlmEncryption { olmEncrypt ->
@ -222,8 +221,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
keys.forEach { keys.forEach {
val keyId = it val keyId = it
// encrypt the content // encrypt the content
val key = getKey(keyId) when (val key = getKey(keyId)) {
when (key) {
is KeyInfoResult.Success -> { is KeyInfoResult.Success -> {
if (key.keyInfo.content.algorithm == SSSS_ALGORITHM_CURVE25519_AES_SHA2) { if (key.keyInfo.content.algorithm == SSSS_ALGORITHM_CURVE25519_AES_SHA2) {
val encryptedResult = withOlmEncryption { olmEncrypt -> val encryptedResult = withOlmEncryption { olmEncrypt ->
@ -279,7 +277,7 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
return results return results
} }
override fun getSecret(name: String, keyId: String?, secretKey: SSSSKeySpec, callback: MatrixCallback<String>) { override fun getSecret(name: String, keyId: String?, secretKey: SsssKeySpec, callback: MatrixCallback<String>) {
val accountData = accountDataService.getAccountDataEvent(name) ?: return Unit.also { val accountData = accountDataService.getAccountDataEvent(name) ?: return Unit.also {
callback.onFailure(SharedSecretStorageError.UnknownSecret(name)) callback.onFailure(SharedSecretStorageError.UnknownSecret(name))
} }
@ -306,20 +304,16 @@ internal class DefaultSharedSecretStorageService @Inject constructor(
} }
cryptoCoroutineScope.launch(coroutineDispatchers.main) { cryptoCoroutineScope.launch(coroutineDispatchers.main) {
kotlin.runCatching { kotlin.runCatching {
// decryt from recovery key // decrypt from recovery key
val keyBytes = keySpec.privateKey withOlmDecryption { olmPkDecryption ->
val decryption = OlmPkDecryption() olmPkDecryption.setPrivateKey(keySpec.privateKey)
try { olmPkDecryption.decrypt(OlmPkMessage()
decryption.setPrivateKey(keyBytes) .apply {
decryption.decrypt(OlmPkMessage().apply {
mCipherText = secretContent.ciphertext mCipherText = secretContent.ciphertext
mEphemeralKey = secretContent.ephemeral mEphemeralKey = secretContent.ephemeral
mMac = secretContent.mac mMac = secretContent.mac
}) }
} catch (failure: Throwable) { )
throw failure
} finally {
decryption.releaseDecryption()
} }
}.foldToCallback(callback) }.foldToCallback(callback)
} }