use of org.jivesoftware.smackx.omemo.internal.OmemoDevice in project Smack by igniterealtime.
the class OmemoService method purgeDeviceList.
/**
* Publish a new DeviceList with just our device in it.
*
* @param managerGuard authenticated OmemoManager.
*
* @throws InterruptedException if the calling thread was interrupted.
* @throws XMPPException.XMPPErrorException if there was an XMPP error returned.
* @throws SmackException.NotConnectedException if the XMPP connection is not connected.
* @throws SmackException.NoResponseException if there was no response from the remote entity.
* @throws IOException if an I/O error occurred.
* @throws NotALeafNodeException if a PubSub leaf node operation was attempted on a non-leaf node.
*/
public void purgeDeviceList(OmemoManager.LoggedInOmemoManager managerGuard) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, IOException, NotALeafNodeException {
OmemoManager omemoManager = managerGuard.get();
OmemoDevice userDevice = omemoManager.getOwnDevice();
OmemoDeviceListElement_VAxolotl newList = new OmemoDeviceListElement_VAxolotl(Collections.singleton(userDevice.getDeviceId()));
// Merge list
getOmemoStoreBackend().mergeCachedDeviceList(userDevice, userDevice.getJid(), newList);
OmemoService.publishDeviceList(omemoManager.getConnection(), newList);
}
use of org.jivesoftware.smackx.omemo.internal.OmemoDevice in project Smack by igniterealtime.
the class OmemoService method decryptStanza.
/**
* Decrypt the OmemoElement inside the given Stanza and return it.
* Return null if something goes wrong.
*
* @param stanza stanza
* @param managerGuard authenticated OmemoManager
* @return decrypted OmemoMessage or null
*
* @throws IOException if an I/O error occurred.
*/
OmemoMessage.Received decryptStanza(Stanza stanza, OmemoManager.LoggedInOmemoManager managerGuard) throws IOException {
OmemoManager manager = managerGuard.get();
// Avoid the ratchet being manipulated and the bundle being published multiple times simultaneously
synchronized (manager) {
OmemoDevice userDevice = manager.getOwnDevice();
OmemoElement element = (OmemoElement) stanza.getExtensionElement(OmemoElement.NAME_ENCRYPTED, OmemoElement_VAxolotl.NAMESPACE);
if (element == null) {
return null;
}
OmemoMessage.Received decrypted = null;
BareJid sender;
try {
MultiUserChat muc = getMuc(manager.getConnection(), stanza.getFrom());
if (muc != null) {
Occupant occupant = muc.getOccupant(stanza.getFrom().asEntityFullJidIfPossible());
Jid occupantJid = occupant.getJid();
if (occupantJid == null) {
LOGGER.log(Level.WARNING, "MUC message received, but there is no way to retrieve the senders Jid. " + stanza.getFrom());
return null;
}
sender = occupantJid.asBareJid();
// try is for this
decrypted = decryptMessage(managerGuard, sender, element);
} else {
sender = stanza.getFrom().asBareJid();
// and this
decrypted = decryptMessage(managerGuard, sender, element);
}
if (decrypted.isPreKeyMessage() && OmemoConfiguration.getCompleteSessionWithEmptyMessage()) {
LOGGER.log(Level.FINE, "Received a preKeyMessage from " + decrypted.getSenderDevice() + ".\n" + "Complete the session by sending an empty response message.");
try {
sendRatchetUpdate(managerGuard, decrypted.getSenderDevice());
} catch (CannotEstablishOmemoSessionException e) {
throw new AssertionError("Since we successfully received a message, we MUST be able to " + "establish a session. " + e);
} catch (NoSuchAlgorithmException | InterruptedException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
LOGGER.log(Level.WARNING, "Cannot send a ratchet update message.", e);
}
}
} catch (NoRawSessionException e) {
OmemoDevice device = e.getDeviceWithoutSession();
LOGGER.log(Level.WARNING, "No raw session found for contact " + device + ". ", e);
} catch (CorruptedOmemoKeyException | CryptoFailedException e) {
LOGGER.log(Level.WARNING, "Could not decrypt incoming message: ", e);
}
// Upload fresh bundle.
if (getOmemoStoreBackend().loadOmemoPreKeys(userDevice).size() < OmemoConstants.PRE_KEY_COUNT_PER_BUNDLE) {
LOGGER.log(Level.FINE, "We used up a preKey. Upload a fresh bundle.");
try {
getOmemoStoreBackend().replenishKeys(userDevice);
OmemoBundleElement bundleElement = getOmemoStoreBackend().packOmemoBundle(userDevice);
publishBundle(manager.getConnection(), userDevice, bundleElement);
} catch (CorruptedOmemoKeyException | InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | NotALeafNodeException e) {
LOGGER.log(Level.WARNING, "Could not republish replenished bundle.", e);
}
}
return decrypted;
}
}
use of org.jivesoftware.smackx.omemo.internal.OmemoDevice in project Smack by igniterealtime.
the class OmemoService method buildMissingSessionsWithDevices.
/**
* Build sessions with all devices from the set, we don't have a session with yet.
* Return the set of all devices we have a session with afterwards.
*
* @param connection authenticated XMPP connection
* @param userDevice our OmemoDevice
* @param devices set of devices we may want to build a session with if necessary
* @return set of all devices with sessions
*
* @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 IOException if an I/O error occurred.
*/
private Set<OmemoDevice> buildMissingSessionsWithDevices(XMPPConnection connection, OmemoDevice userDevice, Set<OmemoDevice> devices) throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, IOException {
Set<OmemoDevice> devicesWithSession = new HashSet<>();
for (OmemoDevice device : devices) {
if (hasSession(userDevice, device)) {
devicesWithSession.add(device);
continue;
}
try {
buildFreshSessionWithDevice(connection, userDevice, device);
devicesWithSession.add(device);
} catch (CannotEstablishOmemoSessionException e) {
LOGGER.log(Level.WARNING, userDevice + " cannot establish session with " + device + " because their bundle could not be fetched.", e);
} catch (CorruptedOmemoKeyException e) {
LOGGER.log(Level.WARNING, userDevice + " could not establish session with " + device + "because their bundle seems to be corrupt.", e);
}
}
return devicesWithSession;
}
use of org.jivesoftware.smackx.omemo.internal.OmemoDevice in project Smack by igniterealtime.
the class OmemoService method init.
/**
* Initialize OMEMO functionality for the given {@link OmemoManager}.
*
* @param managerGuard OmemoManager we'd like to initialize.
*
* @throws InterruptedException if the calling thread was interrupted.
* @throws CorruptedOmemoKeyException if the OMEMO key is corrupted.
* @throws XMPPException.XMPPErrorException if there was an XMPP error returned.
* @throws SmackException.NotConnectedException if the XMPP connection is not connected.
* @throws SmackException.NoResponseException if there was no response from the remote entity.
* @throws PubSubException.NotALeafNodeException if a PubSub leaf node operation was attempted on a non-leaf node.
* @throws IOException if an I/O error occurred.
*/
void init(OmemoManager.LoggedInOmemoManager managerGuard) throws InterruptedException, CorruptedOmemoKeyException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, PubSubException.NotALeafNodeException, IOException {
OmemoManager manager = managerGuard.get();
OmemoDevice userDevice = manager.getOwnDevice();
// Create new keys if necessary and publish to the server.
getOmemoStoreBackend().replenishKeys(userDevice);
// Rotate signed preKey if necessary.
if (shouldRotateSignedPreKey(userDevice)) {
getOmemoStoreBackend().changeSignedPreKey(userDevice);
}
// Pack and publish bundle
OmemoBundleElement bundle = getOmemoStoreBackend().packOmemoBundle(userDevice);
publishBundle(manager.getConnection(), userDevice, bundle);
// Fetch device list and republish deviceId if necessary
refreshAndRepublishDeviceList(manager.getConnection(), userDevice);
}
use of org.jivesoftware.smackx.omemo.internal.OmemoDevice 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();
}
Aggregations