feat(crypto): Added serializeKeys and deserializeKeys functions.

This commit is contained in:
Neil Marietta 2024-04-11 16:40:31 +02:00
parent 053a4263fb
commit b8ffd6787c
8 changed files with 69 additions and 2 deletions

View File

@ -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()
}

View File

@ -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;

View File

@ -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])
}
}

View File

@ -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

View File

@ -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;

View File

@ -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].
*

View File

@ -20,6 +20,7 @@ import studio.forface.easygradle.dsl.*
plugins {
protonKotlinLibrary
kotlin("plugin.serialization")
}
protonBuild {

View File

@ -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 {