Skip to content

Commit

Permalink
Make encryption keys align with iOS (#273)
Browse files Browse the repository at this point in the history
* enforce encryption keys like iOS

* fix up all the tests
  • Loading branch information
nplasterer authored Jul 10, 2024
1 parent 3272933 commit 25dfd96
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 51 deletions.
41 changes: 30 additions & 11 deletions library/src/androidTest/java/org/xmtp/android/library/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.xmtp.android.library.messages.PrivateKeyBundleV1Builder
import org.xmtp.android.library.messages.generate
import org.xmtp.proto.message.contents.PrivateKeyOuterClass
import uniffi.xmtpv3.GenericException
import java.security.SecureRandom
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit

Expand Down Expand Up @@ -83,12 +84,14 @@ class ClientTest {

@Test
fun testV3CanBeCreatedWithBundle() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
val client =
Client().create(account = fakeWallet, options = options)
Expand Down Expand Up @@ -118,6 +121,7 @@ class ClientTest {

@Test
fun testCreatesAV3Client() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val client =
Expand All @@ -126,7 +130,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
runBlocking {
Expand All @@ -137,6 +142,7 @@ class ClientTest {

@Test
fun testCanDeleteDatabase() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val fakeWallet2 = PrivateKeyBuilder()
Expand All @@ -146,7 +152,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
val client2 =
Expand All @@ -155,7 +162,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)

Expand All @@ -173,7 +181,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)

Expand All @@ -185,6 +194,7 @@ class ClientTest {

@Test
fun testCreatesAV3DevClient() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val client =
Expand All @@ -193,7 +203,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.DEV, true),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
runBlocking {
Expand All @@ -203,6 +214,7 @@ class ClientTest {

@Test
fun testCreatesAV3ProductionClient() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val client =
Expand All @@ -211,7 +223,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.PRODUCTION, true),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
runBlocking {
Expand Down Expand Up @@ -301,6 +314,7 @@ class ClientTest {

@Test
fun testCanDropReconnectDatabase() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val fakeWallet = PrivateKeyBuilder()
val fakeWallet2 = PrivateKeyBuilder()
Expand All @@ -310,7 +324,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
val alixClient =
Expand All @@ -319,7 +334,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)

Expand Down Expand Up @@ -348,6 +364,7 @@ class ClientTest {

@Test
fun testCanGetAnInboxIdFromAddress() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
val alixWallet = PrivateKeyBuilder()
val boWallet = PrivateKeyBuilder()
Expand All @@ -357,7 +374,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
val boClient =
Expand All @@ -366,7 +384,8 @@ class ClientTest {
options = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
val boInboxId = runBlocking {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.walletAddress
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption
import java.security.SecureRandom

@RunWith(AndroidJUnit4::class)
class GroupPermissionsTest {
Expand All @@ -30,13 +31,15 @@ class GroupPermissionsTest {

@Before
fun setUp() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
fixtures =
fixtures(
clientOptions = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
alixWallet = fixtures.aliceAccount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.xmtp.android.library.messages.walletAddress
import org.xmtp.proto.mls.message.contents.TranscriptMessages
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration
import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption
import java.security.SecureRandom

@RunWith(AndroidJUnit4::class)
class GroupTest {
Expand All @@ -43,13 +44,15 @@ class GroupTest {

@Before
fun setUp() {
val key = SecureRandom().generateSeed(32)
val context = InstrumentationRegistry.getInstrumentation().targetContext
fixtures =
fixtures(
clientOptions = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context
appContext = context,
dbEncryptionKey = key
)
)
alixWallet = fixtures.aliceAccount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.xmtp.android.library.codecs.GroupUpdatedCodec
import org.xmtp.android.library.messages.PrivateKey
import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.walletAddress
import java.security.SecureRandom

@RunWith(AndroidJUnit4::class)
class GroupUpdatedTest {
Expand All @@ -31,11 +32,13 @@ class GroupUpdatedTest {

@Before
fun setUp() {
val key = SecureRandom().generateSeed(32)
fixtures = fixtures(
clientOptions = ClientOptions(
ClientOptions.Api(XMTPEnvironment.LOCAL, false),
enableV3 = true,
appContext = context,
dbEncryptionKey = key
)
)
alixWallet = fixtures.aliceAccount
Expand Down
40 changes: 2 additions & 38 deletions library/src/main/java/org/xmtp/android/library/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ package org.xmtp.android.library

import android.content.Context
import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Log
import com.google.crypto.tink.subtle.Base64
import com.google.gson.GsonBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.web3j.crypto.Keys
import org.web3j.crypto.Keys.toChecksumAddress
import org.xmtp.android.library.codecs.ContentCodec
Expand Down Expand Up @@ -52,14 +48,11 @@ import uniffi.xmtpv3.getInboxIdForAddress
import uniffi.xmtpv3.getVersionInfo
import java.io.File
import java.nio.charset.StandardCharsets
import java.security.KeyStore
import java.text.SimpleDateFormat
import java.time.Instant
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey

typealias PublishResponse = org.xmtp.proto.message.api.v1.MessageApiOuterClass.PublishResponse
typealias QueryResponse = org.xmtp.proto.message.api.v1.MessageApiOuterClass.QueryResponse
Expand Down Expand Up @@ -337,37 +330,8 @@ class Client() {
directoryFile.mkdir()
dbPath = directoryFile.absolutePath + "/$alias.db3"

val encryptionKey = if (options.dbEncryptionKey == null) {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
withContext(Dispatchers.IO) {
keyStore.load(null)
}

val entry = keyStore.getEntry(alias, null)

val retrievedKey: SecretKey = if (entry is KeyStore.SecretKeyEntry) {
entry.secretKey
} else {
val keyGenerator =
KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
val keyGenParameterSpec = KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()

keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey()
}
retrievedKey.encoded
} else {
options.dbEncryptionKey
}
val encryptionKey = options.dbEncryptionKey
?: throw XMTPException("No encryption key passed for the database. Please store and provide a secure encryption key.")

createClient(
logger = logger,
Expand Down

0 comments on commit 25dfd96

Please sign in to comment.