More cleanup/code lisibility
This commit is contained in:
parent
7ddea99fc6
commit
2d6f57e214
|
@ -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?
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue