Skip to content

Commit

Permalink
Migrate from libsignal-protocol-java to libsignal
Browse files Browse the repository at this point in the history
  • Loading branch information
vanitasvitae committed Oct 5, 2024
1 parent de56468 commit 585a1e2
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 121 deletions.
2 changes: 1 addition & 1 deletion smack-omemo-signal/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies {
api project(":smack-im")
api project(":smack-extensions")
api project(":smack-omemo")
implementation 'org.whispersystems:signal-protocol-java:2.8.1'
implementation 'org.signal:libsignal-client:0.26.0'

// TODO: Migrate Junit4 tests to Junit5.
testImplementation "org.junit.vintage:junit-vintage-engine:$junitVersion"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
import org.jivesoftware.smackx.omemo.CachingOmemoStore;
import org.jivesoftware.smackx.omemo.OmemoStore;

import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SessionCipher;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;

/**
* Implementation of the CachingOmemoStore for smack-omemo-signal.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
import org.jivesoftware.smackx.omemo.FileBasedOmemoStore;
import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;

import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SessionCipher;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;

/**
* Implementation of a FileBasedOmemoStore for the smack-omemo-signal module.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,27 @@
*/
package org.jivesoftware.smackx.omemo.signal;

import java.io.IOException;
import java.util.List;
import java.util.TreeMap;

import org.jivesoftware.smackx.omemo.element.OmemoBundleElement;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.ecc.Curve;
import org.signal.libsignal.protocol.ecc.ECKeyPair;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;
import org.signal.libsignal.protocol.util.Medium;

import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.util.KeyHelper;
import java.io.IOException;
import java.util.List;
import java.util.TreeMap;

/**
* Concrete implementation of the KeyUtil for an implementation using the Signal library.
Expand All @@ -51,34 +52,58 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe

@Override
public IdentityKeyPair generateOmemoIdentityKeyPair() {
return KeyHelper.generateIdentityKeyPair();
return IdentityKeyPair.generate();
}

@Override
@SuppressWarnings("NonApiType")
public TreeMap<Integer, PreKeyRecord> generateOmemoPreKeys(int currentPreKeyId, int count) {
List<PreKeyRecord> preKeyRecords = KeyHelper.generatePreKeys(currentPreKeyId, count);
List<PreKeyRecord> preKeyRecords = generatePreKeys(currentPreKeyId, count);
TreeMap<Integer, PreKeyRecord> map = new TreeMap<>();
for (PreKeyRecord p : preKeyRecords) {
map.put(p.getId(), p);
}
return map;
}

private static List<PreKeyRecord> generatePreKeys(int start, int count) {
List<PreKeyRecord> results = new ArrayList<>(count);

start--;

for (int i=0;i<count;i++) {
int pkIdx = ((start + i) % (Medium.MAX_VALUE-1)) + 1;
results.add(new PreKeyRecord(pkIdx, Curve.generateKeyPair()));
}

return results;
}

@Override
public SignedPreKeyRecord generateOmemoSignedPreKey(IdentityKeyPair identityKeyPair, int currentPreKeyId)
throws CorruptedOmemoKeyException {
try {
return KeyHelper.generateSignedPreKey(identityKeyPair, currentPreKeyId);
return generateSignedPreKey(identityKeyPair, currentPreKeyId);
} catch (InvalidKeyException e) {
throw new CorruptedOmemoKeyException(e);
}
}

private static SignedPreKeyRecord generateSignedPreKey(IdentityKeyPair identityKeyPair, int signedPreKeyId) throws InvalidKeyException {
ECKeyPair keyPair = Curve.generateKeyPair();
byte[] signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize());

return new SignedPreKeyRecord(signedPreKeyId, System.currentTimeMillis(), keyPair, signature);
}

@Override
public SignedPreKeyRecord signedPreKeyFromBytes(byte[] data) throws IOException {
if (data == null) return null;
return new SignedPreKeyRecord(data);
try {
return new SignedPreKeyRecord(data);
} catch (InvalidMessageException e) {
throw new IOException(e);
}
}

@Override
Expand All @@ -89,7 +114,11 @@ public byte[] signedPreKeyToBytes(SignedPreKeyRecord signedPreKeyRecord) {
@Override
public SessionRecord rawSessionFromBytes(byte[] data) throws IOException {
if (data == null) return null;
return new SessionRecord(data);
try {
return new SessionRecord(data);
} catch (InvalidMessageException e) {
throw new IOException(e);
}
}

@Override
Expand All @@ -100,11 +129,7 @@ public byte[] rawSessionToBytes(SessionRecord session) {
@Override
public IdentityKeyPair identityKeyPairFromBytes(byte[] data) throws CorruptedOmemoKeyException {
if (data == null) return null;
try {
return new IdentityKeyPair(data);
} catch (InvalidKeyException e) {
throw new CorruptedOmemoKeyException(e);
}
return new IdentityKeyPair(data);
}

@Override
Expand Down Expand Up @@ -135,7 +160,11 @@ public byte[] preKeyToBytes(PreKeyRecord preKeyRecord) {
@Override
public PreKeyRecord preKeyFromBytes(byte[] bytes) throws IOException {
if (bytes == null) return null;
return new PreKeyRecord(bytes);
try {
return new PreKeyRecord(bytes);
} catch (InvalidMessageException e) {
throw new IOException(e);
}
}

@Override
Expand Down Expand Up @@ -188,7 +217,11 @@ public byte[] preKeyPublicKeyForBundle(ECPublicKey preKey) {

@Override
public byte[] preKeyForBundle(PreKeyRecord preKeyRecord) {
return preKeyRecord.getKeyPair().getPublicKey().serialize();
try {
return preKeyRecord.getKeyPair().getPublicKey().serialize();
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,27 @@
import org.jivesoftware.smackx.omemo.internal.CiphertextTuple;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;

import org.whispersystems.libsignal.DuplicateMessageException;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.InvalidKeyIdException;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.InvalidVersionException;
import org.whispersystems.libsignal.LegacyMessageException;
import org.whispersystems.libsignal.NoSessionException;
import org.whispersystems.libsignal.SessionCipher;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.UntrustedIdentityException;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.protocol.CiphertextMessage;
import org.whispersystems.libsignal.protocol.PreKeySignalMessage;
import org.whispersystems.libsignal.protocol.SignalMessage;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.signal.libsignal.protocol.DuplicateMessageException;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.InvalidKeyIdException;
import org.signal.libsignal.protocol.InvalidMessageException;
import org.signal.libsignal.protocol.InvalidVersionException;
import org.signal.libsignal.protocol.LegacyMessageException;
import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.UntrustedIdentityException;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.protocol.message.CiphertextMessage;
import org.signal.libsignal.protocol.message.PreKeySignalMessage;
import org.signal.libsignal.protocol.message.SignalMessage;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;


public class SignalOmemoRatchet
extends OmemoRatchet<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
Expand Down Expand Up @@ -103,7 +104,7 @@ public byte[] doubleRatchetDecrypt(OmemoDevice sender, byte[] encryptedKey)
catch (UntrustedIdentityException e) {
throw new AssertionError("Signals trust management MUST be disabled.");
}
catch (LegacyMessageException | InvalidKeyException e) {
catch (InvalidKeyException e) {
throw new CryptoFailedException(e);
}
catch (InvalidKeyIdException e) {
Expand Down Expand Up @@ -134,7 +135,15 @@ public byte[] doubleRatchetDecrypt(OmemoDevice sender, byte[] encryptedKey)
LOGGER.log(Level.INFO, "Decryption of SignalMessage from " + sender +
" failed, since the message has been decrypted before.");
return null;
} catch (InvalidVersionException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
} catch (LegacyMessageException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}

return decryptedKey;
Expand All @@ -156,7 +165,7 @@ public CiphertextTuple doubleRatchetEncrypt(OmemoDevice recipient, byte[] messag
}

private SessionCipher getCipher(OmemoDevice device) {
return new SessionCipher(storeConnector, storeConnector, storeConnector, storeConnector,
return new SessionCipher(storeConnector, storeConnector, storeConnector, null, storeConnector,
SignalOmemoStoreConnector.asAddress(device));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;

import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SessionBuilder;
import org.whispersystems.libsignal.SessionCipher;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.UntrustedIdentityException;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;

import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.SessionBuilder;
import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.UntrustedIdentityException;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;


/**
* Concrete implementation of the OmemoService using the Signal library.
Expand Down Expand Up @@ -103,7 +105,7 @@ protected void processBundle(OmemoManager omemoManager,
try {
builder.process(contactsBundle);
LOGGER.log(Level.FINE, "Session built with " + contactsDevice);
} catch (org.whispersystems.libsignal.InvalidKeyException e) {
} catch (org.signal.libsignal.protocol.InvalidKeyException e) {
throw new CorruptedOmemoKeyException(e);
} catch (UntrustedIdentityException e) {
// This should never happen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
import org.jivesoftware.smackx.omemo.OmemoStore;
import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;

import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.SessionCipher;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.state.PreKeyBundle;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.signal.libsignal.protocol.IdentityKey;
import org.signal.libsignal.protocol.IdentityKeyPair;
import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.signal.libsignal.protocol.state.PreKeyBundle;
import org.signal.libsignal.protocol.state.PreKeyRecord;
import org.signal.libsignal.protocol.state.SessionRecord;
import org.signal.libsignal.protocol.state.SignedPreKeyRecord;

/**
* Implementation of the OmemoStore using the Signal library.
Expand Down
Loading

0 comments on commit 585a1e2

Please sign in to comment.