use of org.jivesoftware.smackx.omemo.exceptions.NoIdentityKeyException in project Smack by igniterealtime.
the class OmemoService method decryptMessage.
/**
* Decrypt an OMEMO message.
*
* @param managerGuard authenticated OmemoManager.
* @param senderJid BareJid of the sender.
* @param omemoElement omemoElement.
* @return decrypted OmemoMessage object.
*
* @throws CorruptedOmemoKeyException if the identityKey of the sender is damaged.
* @throws CryptoFailedException if decryption fails.
* @throws NoRawSessionException if we have no session with the device and it sent a normal (non-preKey) message.
* @throws IOException if an I/O error occurred.
*/
OmemoMessage.Received decryptMessage(OmemoManager.LoggedInOmemoManager managerGuard, BareJid senderJid, OmemoElement omemoElement) throws CorruptedOmemoKeyException, CryptoFailedException, NoRawSessionException, IOException {
OmemoManager manager = managerGuard.get();
int senderId = omemoElement.getHeader().getSid();
OmemoDevice senderDevice = new OmemoDevice(senderJid, senderId);
CipherAndAuthTag cipherAndAuthTag = getOmemoRatchet(manager).retrieveMessageKeyAndAuthTag(senderDevice, omemoElement);
// Retrieve senders fingerprint.
OmemoFingerprint senderFingerprint;
try {
senderFingerprint = getOmemoStoreBackend().getFingerprint(manager.getOwnDevice(), senderDevice);
} catch (NoIdentityKeyException e) {
throw new AssertionError("Cannot retrieve OmemoFingerprint of sender although decryption was successful: " + e);
}
// Reset the message counter.
omemoStore.storeOmemoMessageCounter(manager.getOwnDevice(), senderDevice, 0);
if (omemoElement.isMessageElement()) {
// Use symmetric message key to decrypt message payload.
String plaintext = OmemoRatchet.decryptMessageElement(omemoElement, cipherAndAuthTag);
return new OmemoMessage.Received(omemoElement, cipherAndAuthTag.getKey(), cipherAndAuthTag.getIv(), plaintext, senderFingerprint, senderDevice, cipherAndAuthTag.wasPreKeyEncrypted());
} else {
// KeyTransportMessages don't require decryption of the payload.
return new OmemoMessage.Received(omemoElement, cipherAndAuthTag.getKey(), cipherAndAuthTag.getIv(), null, senderFingerprint, senderDevice, cipherAndAuthTag.wasPreKeyEncrypted());
}
}
use of org.jivesoftware.smackx.omemo.exceptions.NoIdentityKeyException 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.NoIdentityKeyException 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);
}
Aggregations