Skip to content

Commit

Permalink
Add MlsClientTest
Browse files Browse the repository at this point in the history
  • Loading branch information
spoonman01 committed Nov 6, 2024
1 parent bd63528 commit 595ac21
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ libs/
.project
.settings
.DS_Store
xenon-unit-test-*/
mls/
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.wire</groupId>
<artifactId>xenon</artifactId>
<version>1.6.4</version>
<version>1.7.0</version>

<name>Xenon</name>
<description>Base Wire Bots Library</description>
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/wire/xenon/backend/models/ClientUpdate.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public static class MlsPublicKeys {
public String ecdsaSecp256r1Sha256;
@JsonProperty("ecdsa_secp384r1_sha384")
public String ecdsaSecp384r1Sha384;
@JsonProperty("ecdsa_secp512r1_sha512")
public String ecdsaSecp512r1Sha512;
@JsonProperty("ecdsa_secp521r1_sha512")
public String ecdsaSecp521r1Sha512;
@JsonProperty("ed25519")
public String ed25519;
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/com/wire/xenon/crypto/mls/CryptoMlsClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.wire.crypto.client.GroupInfo
import com.wire.crypto.client.MLSClient
import com.wire.crypto.client.MLSGroupId
import com.wire.crypto.client.MlsMessage
import com.wire.crypto.client.PlaintextMessage
import com.wire.crypto.client.Welcome
import kotlinx.coroutines.runBlocking
import java.io.Closeable
Expand All @@ -28,11 +29,18 @@ class CryptoMlsClient : Closeable {
}

fun getId(): String = clientId
fun getCoreCryptoClient(): MLSClient = mlsClient

private fun getDirectoryPath(clientId: String): String {
return "mls/$clientId"
}

fun encrypt(mlsGroupId: String, plainMessage: ByteArray): ByteArray? {
val mlsGroupIdBytes: ByteArray = Base64.getDecoder().decode(mlsGroupId)
val encryptedMessage = runBlocking { mlsClient.encryptMessage(MLSGroupId(mlsGroupIdBytes), PlaintextMessage(plainMessage)) }
return encryptedMessage.value
}

// Group id needs to be fetched by API given qualified id of the conversation or maybe also create a cache/table, then take base64 string and byte array
// encryptedMessage is payload.data (string) -> decodeBase64Bytes (take the string as base64 and then get byte array)
fun decrypt(mlsGroupId: String, encryptedMessage: String): ByteArray? {
Expand Down
81 changes: 81 additions & 0 deletions src/test/java/com/wire/xenon/MlsClientTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.wire.xenon;

import com.wire.crypto.CoreCryptoException;
import com.wire.xenon.crypto.mls.CryptoMlsClient;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertThrows;

public class MlsClientTest {
@Test
public void testMlsClientInitialization() {
String client1 = "alice1_" + UUID.randomUUID();
CryptoMlsClient mlsClient = new CryptoMlsClient(client1, "pwd");
assert mlsClient != null;
mlsClient.close();

CryptoMlsClient mlsSameClient = new CryptoMlsClient(client1, "pwd");
assert mlsSameClient != null;
assert mlsSameClient.getId().equals(client1);

final byte[] publicKey = mlsSameClient.getPublicKey();
assert publicKey.length > 10;

final List<byte[]> keyPackages = mlsSameClient.generateKeyPackages(10);
assert keyPackages.size() == 10;
mlsSameClient.close();
}

@Test
public void testMlsClientFailOnDifferentPassword(){
String client1 = "alice1_" + UUID.randomUUID();
CryptoMlsClient mlsClient = new CryptoMlsClient(client1, "pwd");
assert mlsClient != null;
mlsClient.close();

assertThrows(CoreCryptoException.class, () -> {
new CryptoMlsClient(client1, "WRONG_PASSWORD");
});
}

@Test
public void testMlsClientCreateConversationAndEncrypt() throws IOException {
String client1 = "alice1_" + UUID.randomUUID();
// Group ID in base64 format, copied from a real one
String groupIdBase64 = "AAEAAliWyGZ3/FqGpDPZdcuLQ0UAYW50YS53aXJlLmxpbms=";

// GroupInfo of a real conversation, stored in a binary test file
InputStream inputStream = new FileInputStream("src/test/resources/tmp.bin");
byte[] groupInfo = inputStream.readAllBytes();

// Create a new client and join the conversation
CryptoMlsClient mlsClient = new CryptoMlsClient(client1, "pwd");
final byte[] commitBundle = mlsClient.createJoinConversationRequest(groupInfo);
assert commitBundle.length > groupInfo.length;
mlsClient.markConversationAsJoined(groupIdBase64);

// Encrypt a message for the joined conversation
String plainMessage = UUID.randomUUID().toString();
final byte[] encryptedMessage = mlsClient.encrypt(groupIdBase64, plainMessage.getBytes());
assert encryptedMessage.length > 10;
final String encryptedBase64Message = Base64.getEncoder().encodeToString(encryptedMessage);

// assertThrows cannot check for exception messages, so had to use try-catch and assert we have the correct error
try {
mlsClient.decrypt(groupIdBase64, encryptedBase64Message);
throw new IllegalArgumentException("Decryption should fail");
} catch (Exception e) {
// Unfortunately it is not possible for a single client to decrypt a message it encrypted itself
// By getting the duplicated message exception we know that the encryption and decryption works
// but we cannot attest that the decrypted message is the same as the original
assert e.getMessage().contains("DuplicateMessage: We already decrypted this message once");
}
}
}
Binary file added src/test/resources/tmp.bin
Binary file not shown.

0 comments on commit 595ac21

Please sign in to comment.