OmemoMessage.java
/**
*
* Copyright 2017 Paul Schaub
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.omemo;
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.BODY_OMEMO_HINT;
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO;
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.MessageBuilder;
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
import org.jivesoftware.smackx.hints.element.StoreHint;
import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
import org.jxmpp.jid.Jid;
public class OmemoMessage {
private final OmemoElement element;
private final byte[] messageKey, iv;
OmemoMessage(OmemoElement element, byte[] key, byte[] iv) {
this.element = element;
this.messageKey = key;
this.iv = iv;
}
/**
* Return the original OmemoElement (<encrypted/>).
*
* @return omemoElement of the message
*/
public OmemoElement getElement() {
return element;
}
/**
* Return the messageKey (or transported key in case of a KeyTransportMessage).
*
* @return encryption key that protects the message payload
*/
public byte[] getKey() {
return messageKey.clone();
}
/**
* Return the initialization vector belonging to the key.
*
* @return initialization vector
*/
public byte[] getIv() {
return iv.clone();
}
/**
* Outgoing OMEMO message.
*/
public static class Sent extends OmemoMessage {
private final Set<OmemoDevice> intendedDevices = new HashSet<>();
private final HashMap<OmemoDevice, Throwable> skippedDevices = new HashMap<>();
/**
* Create a new outgoing OMEMO message.
*
* @param element OmemoElement
* @param key messageKey (or transported key)
* @param iv initialization vector belonging to key
* @param intendedDevices devices the client intended to encrypt the message for
* @param skippedDevices devices which were skipped during encryption process because encryption
* failed for some reason
*/
Sent(OmemoElement element, byte[] key, byte[] iv, Set<OmemoDevice> intendedDevices, HashMap<OmemoDevice, Throwable> skippedDevices) {
super(element, key, iv);
this.intendedDevices.addAll(intendedDevices);
this.skippedDevices.putAll(skippedDevices);
}
/**
* Return a list of all devices the sender originally intended to encrypt the message for.
*
* @return list of intended recipients.
*/
public Set<OmemoDevice> getIntendedDevices() {
return intendedDevices;
}
/**
* Return a map of all skipped recipients and the reasons for skipping.
*
* @return map of skipped recipients and reasons for that.
*/
public HashMap<OmemoDevice, Throwable> getSkippedDevices() {
return skippedDevices;
}
/**
* Determine, if some recipients were skipped during encryption.
*
* @return true if recipients were skipped.
*/
public boolean isMissingRecipients() {
return !getSkippedDevices().isEmpty();
}
/**
* Return the OmemoElement wrapped in a Message ready to be sent.
* The message is addressed to recipient, contains the OmemoElement
* as well as an optional clear text hint as body, a MAM storage hint
* and an EME hint about OMEMO encryption.
*
* @param messageBuilder a message builder which will be used to build the message.
* @param recipient recipient for the to-field of the message.
* @return the build message.
*/
public Message buildMessage(MessageBuilder messageBuilder, Jid recipient) {
messageBuilder.ofType(Message.Type.chat).to(recipient);
messageBuilder.addExtension(getElement());
if (OmemoConfiguration.getAddOmemoHintBody()) {
messageBuilder.setBody(BODY_OMEMO_HINT);
}
StoreHint.set(messageBuilder);
messageBuilder.addExtension(new ExplicitMessageEncryptionElement(OMEMO_NAMESPACE_V_AXOLOTL, OMEMO));
return messageBuilder.build();
}
}
/**
* Incoming OMEMO message.
*/
public static class Received extends OmemoMessage {
private final String message;
private final OmemoFingerprint sendersFingerprint;
private final OmemoDevice senderDevice;
private final boolean preKeyMessage;
/**
* Create a new incoming OMEMO message.
*
* @param element original OmemoElement
* @param key message key (or transported key)
* @param iv respective initialization vector
* @param body decrypted body
* @param sendersFingerprint OmemoFingerprint of the senders identityKey
* @param senderDevice OmemoDevice of the sender
* @param preKeyMessage if this was a preKeyMessage or not
*/
Received(OmemoElement element, byte[] key, byte[] iv, String body, OmemoFingerprint sendersFingerprint, OmemoDevice senderDevice, boolean preKeyMessage) {
super(element, key, iv);
this.message = body;
this.sendersFingerprint = sendersFingerprint;
this.senderDevice = senderDevice;
this.preKeyMessage = preKeyMessage;
}
/**
* Return the decrypted body of the message.
*
* @return decrypted body
*/
public String getBody() {
return message;
}
/**
* Return the fingerprint of the messages sender device.
*
* @return fingerprint of sender
*/
public OmemoFingerprint getSendersFingerprint() {
return sendersFingerprint;
}
/**
* Return the OmemoDevice which sent the message.
*
* @return OMEMO device that sent the message.
*/
public OmemoDevice getSenderDevice() {
return senderDevice;
}
/**
* Return true, if this message was sent as a preKeyMessage.
*
* @return preKeyMessage or not
*/
boolean isPreKeyMessage() {
return preKeyMessage;
}
/**
* Return true, if the message was a KeyTransportMessage.
* A KeyTransportMessage is a OmemoMessage without a payload.
*
* @return keyTransportMessage?
*/
public boolean isKeyTransportMessage() {
return message == null;
}
}
}