Compare commits
3 Commits
669ea34b98
...
5eaac491d9
Author | SHA1 | Date |
---|---|---|
Neil Marietta | 5eaac491d9 | |
Neil Marietta | b8ffd6787c | |
proton-ci | 053a4263fb |
|
@ -18,6 +18,7 @@
|
|||
|
||||
package me.proton.core.test.android.mocks
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import io.mockk.mockk
|
||||
import me.proton.core.crypto.common.pgp.Armored
|
||||
import me.proton.core.crypto.common.pgp.DataPacket
|
||||
|
@ -40,6 +41,8 @@ import me.proton.core.crypto.common.pgp.Unarmored
|
|||
import me.proton.core.crypto.common.pgp.UnlockedKey
|
||||
import me.proton.core.crypto.common.pgp.VerificationTime
|
||||
import me.proton.core.crypto.common.pgp.VerificationContext
|
||||
import me.proton.core.util.kotlin.deserialize
|
||||
import me.proton.core.util.kotlin.serialize
|
||||
import java.io.File
|
||||
import java.util.Base64
|
||||
|
||||
|
@ -59,6 +62,15 @@ class FakePGPCrypto : PGPCrypto {
|
|||
return true
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ByteArrayList(val keys: List<ByteArray>)
|
||||
|
||||
override fun serializeKeys(keys: List<Unarmored>): ByteArray =
|
||||
ByteArrayList(keys).serialize().encodeToByteArray()
|
||||
|
||||
override fun deserializeKeys(keys: ByteArray): List<Unarmored> =
|
||||
keys.decodeToString().deserialize<ByteArrayList>().keys
|
||||
|
||||
override fun lock(unlockedKey: Unarmored, passphrase: ByteArray): Armored {
|
||||
return decoder.decode(unlockedKey).decodeToString()
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ public final class me/proton/core/crypto/android/pgp/GOpenPGPCrypto : me/proton/
|
|||
public fun decryptSessionKeyWithPassword ([B[B)Lme/proton/core/crypto/common/pgp/SessionKey;
|
||||
public fun decryptText (Ljava/lang/String;[B)Ljava/lang/String;
|
||||
public fun decryptTextWithPassword (Ljava/lang/String;[B)Ljava/lang/String;
|
||||
public fun deserializeKeys ([B)Ljava/util/List;
|
||||
public fun encryptAndSignData ([BLjava/lang/String;[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
public fun encryptAndSignData ([BLme/proton/core/crypto/common/pgp/SessionKey;[BLme/proton/core/crypto/common/pgp/SignatureContext;)[B
|
||||
public fun encryptAndSignDataWithCompression ([BLjava/lang/String;[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
|
@ -96,6 +97,7 @@ public final class me/proton/core/crypto/android/pgp/GOpenPGPCrypto : me/proton/
|
|||
public fun isPublicKey (Ljava/lang/String;)Z
|
||||
public fun isValidKey (Ljava/lang/String;)Z
|
||||
public fun lock ([B[B)Ljava/lang/String;
|
||||
public fun serializeKeys (Ljava/util/List;)[B
|
||||
public fun signData ([B[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
public fun signDataEncrypted ([B[BLjava/util/List;Lme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
public fun signFile (Ljava/io/File;[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
|
|
|
@ -1794,4 +1794,19 @@ internal class GOpenPGPCryptoTest {
|
|||
val decryptedData = crypto.decryptDataWithPassword(encryptedMessage, password)
|
||||
assertContentEquals(expected = data, actual = decryptedData)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun serializeAndDeserializeUnlockedKey() {
|
||||
// Given
|
||||
val unlockedKey1 = crypto.unlock(TestKey.privateKey, TestKey.privateKeyPassphrase)
|
||||
val unlockedKey2 = crypto.unlock(TestKey.privateKey2, TestKey.privateKey2Passphrase)
|
||||
val keys = listOf(unlockedKey1.value, unlockedKey2.value)
|
||||
// When
|
||||
val serialized = crypto.serializeKeys(keys)
|
||||
val deserialized = crypto.deserializeKeys(serialized)
|
||||
// Then
|
||||
assertTrue(deserialized.size == 2)
|
||||
assertContentEquals(expected = keys[0], actual = deserialized[0])
|
||||
assertContentEquals(expected = keys[1], actual = deserialized[1])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,16 @@ class GOpenPGPCrypto : PGPCrypto {
|
|||
private fun newKeyRing(keys: List<CloseableUnlockedKey>) =
|
||||
CloseableUnlockedKeyRing(Crypto.newKeyRing(null).apply { keys.forEach { addKey(it.value) } })
|
||||
|
||||
override fun serializeKeys(keys: List<Unarmored>): ByteArray =
|
||||
newKeyRing(newKeys(keys)).use { it.value.serialize() }
|
||||
|
||||
override fun deserializeKeys(keys: ByteArray): List<Unarmored> =
|
||||
CloseableUnlockedKeyRing(Crypto.newKeyRingFromBinary(keys)).use { keyRing ->
|
||||
val count = keyRing.value.countEntities()
|
||||
val indices = 0..<count
|
||||
indices.map { index -> keyRing.value.getKey(index).serialize() }
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Public Key
|
||||
|
|
|
@ -216,6 +216,7 @@ public abstract interface class me/proton/core/crypto/common/pgp/PGPCrypto {
|
|||
public abstract fun decryptSessionKeyWithPassword ([B[B)Lme/proton/core/crypto/common/pgp/SessionKey;
|
||||
public abstract fun decryptText (Ljava/lang/String;[B)Ljava/lang/String;
|
||||
public abstract fun decryptTextWithPassword (Ljava/lang/String;[B)Ljava/lang/String;
|
||||
public abstract fun deserializeKeys ([B)Ljava/util/List;
|
||||
public abstract fun encryptAndSignData ([BLjava/lang/String;[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
public abstract fun encryptAndSignData ([BLme/proton/core/crypto/common/pgp/SessionKey;[BLme/proton/core/crypto/common/pgp/SignatureContext;)[B
|
||||
public abstract fun encryptAndSignDataWithCompression ([BLjava/lang/String;[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
|
@ -255,6 +256,7 @@ public abstract interface class me/proton/core/crypto/common/pgp/PGPCrypto {
|
|||
public abstract fun isPublicKey (Ljava/lang/String;)Z
|
||||
public abstract fun isValidKey (Ljava/lang/String;)Z
|
||||
public abstract fun lock ([B[B)Ljava/lang/String;
|
||||
public abstract fun serializeKeys (Ljava/util/List;)[B
|
||||
public abstract fun signData ([B[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
public abstract fun signDataEncrypted ([B[BLjava/util/List;Lme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
public abstract fun signFile (Ljava/io/File;[BLme/proton/core/crypto/common/pgp/SignatureContext;)Ljava/lang/String;
|
||||
|
|
|
@ -43,6 +43,20 @@ interface PGPCrypto {
|
|||
*/
|
||||
fun isValidKey(key: Armored): Boolean
|
||||
|
||||
/**
|
||||
* Serialize a list of [Unarmored] unlocked keys into a [ByteArray].
|
||||
*
|
||||
* @see deserializeKeys
|
||||
*/
|
||||
fun serializeKeys(keys: List<Unarmored>): ByteArray
|
||||
|
||||
/**
|
||||
* Deserialize a [ByteArray] of unlocked keys into an [Unarmored] list.
|
||||
*
|
||||
* @see serializeKeys
|
||||
*/
|
||||
fun deserializeKeys(keys: ByteArray): List<Unarmored>
|
||||
|
||||
/**
|
||||
* Lock [unlockedKey] using [passphrase].
|
||||
*
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
"-trimpath"
|
||||
],
|
||||
"build_name":"gopenpgp",
|
||||
"commit_message":"feat(gopenpgp): Update to gopenpgp v2.7.5-proton.",
|
||||
"upload_branch":"update-2.7.5",
|
||||
"commit_message":"feat(gopenpgp): Update to gopenpgp v2.8.0-alpha.1-proton.",
|
||||
"upload_branch":"update-2.8.0-alpha.1",
|
||||
"java_pkg":"com.proton.gopenpgp",
|
||||
"targets":[
|
||||
"android"
|
||||
|
@ -20,7 +20,7 @@
|
|||
{
|
||||
"module":{
|
||||
"path":"github.com/ProtonMail/gopenpgp/v2",
|
||||
"version":"v2.7.5-proton"
|
||||
"version":"v2.8.0-alpha.1-proton"
|
||||
},
|
||||
"packages":[
|
||||
"crypto",
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -20,6 +20,7 @@ import studio.forface.easygradle.dsl.*
|
|||
|
||||
plugins {
|
||||
protonKotlinLibrary
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
protonBuild {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package me.proton.core.key.domain
|
||||
|
||||
import io.mockk.mockk
|
||||
import kotlinx.serialization.Serializable
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.EncryptedByteArray
|
||||
import me.proton.core.crypto.common.keystore.EncryptedString
|
||||
|
@ -51,6 +52,8 @@ import me.proton.core.crypto.common.pgp.VerificationTime
|
|||
import me.proton.core.crypto.common.srp.Auth
|
||||
import me.proton.core.crypto.common.srp.SrpCrypto
|
||||
import me.proton.core.crypto.common.srp.SrpProofs
|
||||
import me.proton.core.util.kotlin.deserialize
|
||||
import me.proton.core.util.kotlin.serialize
|
||||
import java.io.File
|
||||
|
||||
open class TestCryptoContext : CryptoContext {
|
||||
|
@ -572,11 +575,19 @@ open class TestCryptoContext : CryptoContext {
|
|||
override suspend fun getCurrentTime(): Long = 0
|
||||
|
||||
override fun isPublicKey(key: Armored): Boolean = key.contains("privateKey")
|
||||
override fun isPrivateKey(key: Armored): Boolean =
|
||||
key.contains("privateKey")
|
||||
override fun isPrivateKey(key: Armored): Boolean = key.contains("privateKey")
|
||||
override fun isValidKey(key: Armored): Boolean = key.contains("privateKey")
|
||||
|
||||
override fun serializeKeys(keys: List<Unarmored>): ByteArray =
|
||||
ByteArrayList(keys).serialize().encodeToByteArray()
|
||||
|
||||
override fun deserializeKeys(keys: ByteArray): List<Unarmored> =
|
||||
keys.decodeToString().deserialize<ByteArrayList>().keys
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ByteArrayList(val keys: List<ByteArray>)
|
||||
|
||||
override val pgpCrypto = TestPGPCrypto()
|
||||
|
||||
override val srpCrypto = object : SrpCrypto {
|
||||
|
|
|
@ -10,33 +10,6 @@ public final class me/proton/core/userrecovery/domain/LogTag {
|
|||
public static final field INSTANCE Lme/proton/core/userrecovery/domain/LogTag;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/ByteArrayList {
|
||||
public static final field Companion Lme/proton/core/userrecovery/domain/usecase/ByteArrayList$Companion;
|
||||
public fun <init> (Ljava/util/List;)V
|
||||
public final fun component1 ()Ljava/util/List;
|
||||
public final fun copy (Ljava/util/List;)Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;
|
||||
public static synthetic fun copy$default (Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;Ljava/util/List;ILjava/lang/Object;)Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getKeys ()Ljava/util/List;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/ByteArrayList$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lme/proton/core/userrecovery/domain/usecase/ByteArrayList$$serializer;
|
||||
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;
|
||||
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lme/proton/core/userrecovery/domain/usecase/ByteArrayList;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/ByteArrayList$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class me/proton/core/userrecovery/domain/usecase/GetRecoveryFile {
|
||||
public fun <init> (Lme/proton/core/user/domain/UserManager;Lme/proton/core/crypto/common/context/CryptoContext;)V
|
||||
public final fun invoke (Lme/proton/core/domain/entity/UserId;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
|
|
|
@ -18,13 +18,12 @@
|
|||
|
||||
package me.proton.core.userrecovery.domain.usecase
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import me.proton.core.crypto.common.context.CryptoContext
|
||||
import me.proton.core.crypto.common.keystore.use
|
||||
import me.proton.core.crypto.common.pgp.EncryptedMessage
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.key.domain.unlockOrNull
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.util.kotlin.serialize
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -46,15 +45,10 @@ class GetRecoveryFile @Inject constructor(
|
|||
val privateKeys = activeKeys.map { it.privateKey }
|
||||
val unlockedKeys = privateKeys.mapNotNull { it.unlockOrNull(cryptoContext)?.unlockedKey }
|
||||
check(unlockedKeys.isNotEmpty())
|
||||
val byteArrayList = ByteArrayList(unlockedKeys.map { it.value })
|
||||
val fileByteArray = byteArrayList.serialize().encodeToByteArray()
|
||||
val secret = pgpCrypto.getBase64Decoded(primaryKeyRecoverySecret)
|
||||
return pgpCrypto.encryptDataWithPassword(fileByteArray, secret)
|
||||
pgpCrypto.serializeKeys(unlockedKeys.map { it.value }).use {
|
||||
unlockedKeys.forEach { unlockedKey -> unlockedKey.close() }
|
||||
val secret = pgpCrypto.getBase64Decoded(primaryKeyRecoverySecret)
|
||||
return pgpCrypto.encryptDataWithPassword(it.array, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Replace with proper binary serialization (pgp).")
|
||||
@Serializable
|
||||
data class ByteArrayList(
|
||||
val keys: List<ByteArray>
|
||||
)
|
||||
|
|
|
@ -29,7 +29,6 @@ import me.proton.core.key.domain.entity.key.UnlockedPrivateKey
|
|||
import me.proton.core.key.domain.lock
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.repository.PassphraseRepository
|
||||
import me.proton.core.util.kotlin.deserialize
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetRecoveryPrivateKeys @Inject constructor(
|
||||
|
@ -48,9 +47,9 @@ class GetRecoveryPrivateKeys @Inject constructor(
|
|||
secrets.forEach { secret ->
|
||||
val decodedSecret = pgpCrypto.getBase64Decoded(secret)
|
||||
pgpCrypto.decryptDataWithPasswordOrNull(message, decodedSecret)?.let {
|
||||
val byteArrayList = it.decodeToString().deserialize<ByteArrayList>()
|
||||
val unlockedKeys = pgpCrypto.deserializeKeys(it)
|
||||
val passphrase = checkNotNull(passphraseRepository.getPassphrase(userId))
|
||||
return byteArrayList.keys.map { key ->
|
||||
return unlockedKeys.map { key ->
|
||||
UnlockedPrivateKey(TempUnlockedKey(key), isPrimary = false).use { unlocked ->
|
||||
unlocked.lock(cryptoContext, passphrase = passphrase, isPrimary = false)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue