use of org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException in project Smack by igniterealtime.
the class OmemoExceptionsTest method undecidedOmemoIdentityExceptionTest.
@Test
public void undecidedOmemoIdentityExceptionTest() throws XmppStringprepException {
OmemoDevice alice = new OmemoDevice(JidCreate.bareFrom("alice@server.tld"), 1234);
OmemoDevice bob = new OmemoDevice(JidCreate.bareFrom("bob@server.tld"), 5678);
OmemoDevice mallory = new OmemoDevice(JidCreate.bareFrom("mallory@server.tld"), 9876);
UndecidedOmemoIdentityException u = new UndecidedOmemoIdentityException(alice);
assertTrue(u.getUndecidedDevices().contains(alice));
assertTrue(u.getUndecidedDevices().size() == 1);
UndecidedOmemoIdentityException v = new UndecidedOmemoIdentityException(bob);
v.getUndecidedDevices().add(mallory);
assertTrue(v.getUndecidedDevices().size() == 2);
assertTrue(v.getUndecidedDevices().contains(bob));
assertTrue(v.getUndecidedDevices().contains(mallory));
u.getUndecidedDevices().add(bob);
u.join(v);
assertTrue(u.getUndecidedDevices().size() == 3);
}
use of org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException in project Smack by igniterealtime.
the class OmemoMessageBuilder method addRecipient.
/**
* Add a new recipient device to the message.
*
* @param contactsDevice device of the recipient
*
* @throws NoIdentityKeyException if we have no identityKey of that device. Can be fixed by fetching and
* processing the devices bundle.
* @throws CorruptedOmemoKeyException if the identityKey of that device is corrupted.
* @throws UndecidedOmemoIdentityException if the user hasn't yet decided whether to trust that device or not.
* @throws UntrustedOmemoIdentityException if the user has decided not to trust that device.
* @throws IOException if an I/O error occurred.
*/
public void addRecipient(OmemoDevice contactsDevice) throws NoIdentityKeyException, CorruptedOmemoKeyException, UndecidedOmemoIdentityException, UntrustedOmemoIdentityException, IOException {
OmemoFingerprint fingerprint;
fingerprint = OmemoService.getInstance().getOmemoStoreBackend().getFingerprint(userDevice, contactsDevice);
switch(trustCallback.getTrust(contactsDevice, fingerprint)) {
case undecided:
throw new UndecidedOmemoIdentityException(contactsDevice);
case trusted:
CiphertextTuple encryptedKey = ratchet.doubleRatchetEncrypt(contactsDevice, messageKey);
keys.add(new OmemoKeyElement(encryptedKey.getCiphertext(), contactsDevice.getDeviceId(), encryptedKey.isPreKeyMessage()));
break;
case untrusted:
throw new UntrustedOmemoIdentityException(contactsDevice, fingerprint);
}
}
use of org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException in project Smack by igniterealtime.
the class OmemoService method createRatchetUpdateElement.
/**
* Create an empty OMEMO message, which is used to forward the ratchet of the recipient.
* This message type is typically used to create stable sessions.
* Note that trust decisions are ignored for the creation of this message.
*
* @param managerGuard Logged in OmemoManager
* @param contactsDevice OmemoDevice of the contact
* @return ratchet update message
*
* @throws NoSuchAlgorithmException if AES algorithms are not supported on this system.
* @throws InterruptedException if the calling thread was interrupted.
* @throws SmackException.NoResponseException if there was no response from the remote entity.
* @throws CorruptedOmemoKeyException if our IdentityKeyPair is corrupted.
* @throws SmackException.NotConnectedException if the XMPP connection is not connected.
* @throws CannotEstablishOmemoSessionException if session negotiation fails.
* @throws IOException if an I/O error occurred.
*/
OmemoElement createRatchetUpdateElement(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDevice contactsDevice) throws InterruptedException, SmackException.NoResponseException, CorruptedOmemoKeyException, SmackException.NotConnectedException, CannotEstablishOmemoSessionException, NoSuchAlgorithmException, CryptoFailedException, IOException {
OmemoManager manager = managerGuard.get();
OmemoDevice userDevice = manager.getOwnDevice();
if (contactsDevice.equals(userDevice)) {
throw new IllegalArgumentException("\"Thou shall not update thy own ratchet!\" - William Shakespeare");
}
// Establish session if necessary
if (!hasSession(userDevice, contactsDevice)) {
buildFreshSessionWithDevice(manager.getConnection(), userDevice, contactsDevice);
}
// Generate fresh AES key and IV
byte[] messageKey = OmemoMessageBuilder.generateKey(KEYTYPE, KEYLENGTH);
byte[] iv = OmemoMessageBuilder.generateIv();
// Create message builder
OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> builder;
try {
builder = new OmemoMessageBuilder<>(userDevice, gullibleTrustCallback, getOmemoRatchet(manager), messageKey, iv, null);
} catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
throw new CryptoFailedException(e);
}
// Add recipient
try {
builder.addRecipient(contactsDevice);
} catch (UndecidedOmemoIdentityException | UntrustedOmemoIdentityException e) {
throw new AssertionError("Gullible Trust Callback reported undecided or untrusted device, " + "even though it MUST NOT do that.");
} catch (NoIdentityKeyException e) {
throw new AssertionError("We MUST have an identityKey for " + contactsDevice + " since we built a session." + e);
}
return builder.finish();
}
use of org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException in project Smack by igniterealtime.
the class OmemoService method encrypt.
/**
* Encrypt a message with a messageKey and an IV and create an OmemoMessage from it.
*
* @param managerGuard authenticated OmemoManager
* @param contactsDevices set of recipient OmemoDevices
* @param messageKey AES key to encrypt the message
* @param iv iv to be used with the messageKey
* @return OmemoMessage object which contains the OmemoElement and some information.
*
* @throws SmackException.NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
* @throws SmackException.NoResponseException if there was no response from the remote entity.
* @throws UndecidedOmemoIdentityException if the list of recipient devices contains undecided devices
* @throws CryptoFailedException if we are lacking some crypto primitives
* @throws IOException if an I/O error occurred.
*/
private OmemoMessage.Sent encrypt(OmemoManager.LoggedInOmemoManager managerGuard, Set<OmemoDevice> contactsDevices, byte[] messageKey, byte[] iv, String message) throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, UndecidedOmemoIdentityException, CryptoFailedException, IOException {
OmemoManager manager = managerGuard.get();
OmemoDevice userDevice = manager.getOwnDevice();
// Do not encrypt for our own device.
removeOurDevice(userDevice, contactsDevices);
buildMissingSessionsWithDevices(manager.getConnection(), userDevice, contactsDevices);
Set<OmemoDevice> undecidedDevices = getUndecidedDevices(userDevice, manager.getTrustCallback(), contactsDevices);
if (!undecidedDevices.isEmpty()) {
throw new UndecidedOmemoIdentityException(undecidedDevices);
}
// Keep track of skipped devices
HashMap<OmemoDevice, Throwable> skippedRecipients = new HashMap<>();
OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> builder;
try {
builder = new OmemoMessageBuilder<>(userDevice, manager.getTrustCallback(), getOmemoRatchet(managerGuard.get()), messageKey, iv, message);
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException e) {
throw new CryptoFailedException(e);
}
for (OmemoDevice contactsDevice : contactsDevices) {
// Build missing sessions
if (!hasSession(userDevice, contactsDevice)) {
try {
buildFreshSessionWithDevice(manager.getConnection(), userDevice, contactsDevice);
} catch (CorruptedOmemoKeyException | CannotEstablishOmemoSessionException e) {
LOGGER.log(Level.WARNING, "Could not build session with " + contactsDevice + ".", e);
skippedRecipients.put(contactsDevice, e);
continue;
}
}
int messageCounter = omemoStore.loadOmemoMessageCounter(userDevice, contactsDevice);
// Ignore read-only devices
if (OmemoConfiguration.getIgnoreReadOnlyDevices()) {
boolean readOnly = messageCounter >= OmemoConfiguration.getMaxReadOnlyMessageCount();
if (readOnly) {
LOGGER.log(Level.FINE, "Device " + contactsDevice + " seems to be read-only (We sent " + messageCounter + " messages without getting a reply back (max allowed is " + OmemoConfiguration.getMaxReadOnlyMessageCount() + "). Ignoring the device.");
skippedRecipients.put(contactsDevice, new ReadOnlyDeviceException(contactsDevice));
// Skip this device and handle next device
continue;
}
}
// Add recipients
try {
builder.addRecipient(contactsDevice);
} catch (NoIdentityKeyException | CorruptedOmemoKeyException e) {
LOGGER.log(Level.WARNING, "Encryption failed for device " + contactsDevice + ".", e);
skippedRecipients.put(contactsDevice, e);
} catch (UndecidedOmemoIdentityException e) {
throw new AssertionError("Recipients device seems to be undecided, even though we should have thrown" + " an exception earlier in that case. " + e);
} catch (UntrustedOmemoIdentityException e) {
LOGGER.log(Level.WARNING, "Device " + contactsDevice + " is untrusted. Message is not encrypted for it.");
skippedRecipients.put(contactsDevice, e);
}
// Increment the message counter of the device
omemoStore.storeOmemoMessageCounter(userDevice, contactsDevice, messageCounter + 1);
}
OmemoElement element = builder.finish();
return new OmemoMessage.Sent(element, messageKey, iv, contactsDevices, skippedRecipients);
}
use of org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException in project Smack by igniterealtime.
the class OmemoClient method handleInput.
public void handleInput(String input) throws NotConnectedException, NotLoggedInException, InterruptedException, IOException {
String[] com = input.split(" ", 3);
switch(com[0]) {
case "/omemo":
if (com.length < 3) {
print("Usage: /omemo <contact-jid> <message>");
return;
}
BareJid recipient = JidCreate.bareFrom(com[1]);
String body = com[2];
MessageBuilder messageBuilder = connection.getStanzaFactory().buildMessageStanza();
try {
Message omemoMessage = omemoManager.encrypt(recipient, body).buildMessage(messageBuilder, recipient);
connection.sendStanza(omemoMessage);
} catch (UndecidedOmemoIdentityException e) {
print("Undecided Identities!\n" + Arrays.toString(e.getUndecidedDevices().toArray()));
} catch (CryptoFailedException | SmackException.NoResponseException e) {
LOGGER.log(Level.SEVERE, "Unexpected Exception", e);
}
break;
case "/trust":
print("Trust");
if (com.length != 2) {
print("Usage: /trust <contact-jid>");
}
BareJid contact = JidCreate.bareFrom(com[1]);
HashMap<OmemoDevice, OmemoFingerprint> devices;
try {
devices = omemoManager.getActiveFingerprints(contact);
} catch (CorruptedOmemoKeyException | CannotEstablishOmemoSessionException | SmackException.NoResponseException e) {
LOGGER.log(Level.SEVERE, "Unexpected Exception", e);
return;
}
for (OmemoDevice d : devices.keySet()) {
print("Trust (1) or distrust (2)?\n" + devices.get(d).blocksOf8Chars());
if (Integer.parseInt(scanner.nextLine()) == 1) {
omemoManager.trustOmemoIdentity(d, devices.get(d));
} else {
omemoManager.distrustOmemoIdentity(d, devices.get(d));
}
}
print("Done.");
break;
case "/purge":
try {
omemoManager.purgeDeviceList();
print("Purged.");
} catch (XMPPException.XMPPErrorException | SmackException.NoResponseException | PubSubException.NotALeafNodeException e) {
LOGGER.log(Level.SEVERE, "Unexpected Exception", e);
}
}
}
Aggregations