001/** 002 * 003 * Copyright 2017 Paul Schaub 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.omemo; 018 019import static org.jivesoftware.smackx.omemo.util.OmemoConstants.BODY_OMEMO_HINT; 020import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO; 021import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL; 022 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.Set; 026 027import org.jivesoftware.smack.packet.Message; 028import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement; 029import org.jivesoftware.smackx.hints.element.StoreHint; 030import org.jivesoftware.smackx.omemo.element.OmemoElement; 031import org.jivesoftware.smackx.omemo.internal.OmemoDevice; 032import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; 033 034import org.jxmpp.jid.Jid; 035 036public class OmemoMessage { 037 038 private final OmemoElement element; 039 private final byte[] messageKey, iv; 040 041 OmemoMessage(OmemoElement element, byte[] key, byte[] iv) { 042 this.element = element; 043 this.messageKey = key; 044 this.iv = iv; 045 } 046 047 /** 048 * Return the original OmemoElement (<encrypted/>). 049 * 050 * @return omemoElement 051 */ 052 public OmemoElement getElement() { 053 return element; 054 } 055 056 /** 057 * Return the messageKey (or transported key in case of a KeyTransportMessage). 058 * 059 * @return key 060 */ 061 public byte[] getKey() { 062 return messageKey.clone(); 063 } 064 065 /** 066 * Return the initialization vector belonging to the key. 067 * @return initialization vector 068 */ 069 public byte[] getIv() { 070 return iv.clone(); 071 } 072 073 /** 074 * Outgoing OMEMO message. 075 */ 076 public static class Sent extends OmemoMessage { 077 private final Set<OmemoDevice> intendedDevices = new HashSet<>(); 078 private final HashMap<OmemoDevice, Throwable> skippedDevices = new HashMap<>(); 079 080 /** 081 * Create a new outgoing OMEMO message. 082 * @param element OmemoElement 083 * @param key messageKey (or transported key) 084 * @param iv initialization vector belonging to key 085 * @param intendedDevices devices the client intended to encrypt the message for 086 * @param skippedDevices devices which were skipped during encryption process because encryption 087 * failed for some reason 088 */ 089 Sent(OmemoElement element, byte[] key, byte[] iv, Set<OmemoDevice> intendedDevices, HashMap<OmemoDevice, Throwable> skippedDevices) { 090 super(element, key, iv); 091 this.intendedDevices.addAll(intendedDevices); 092 this.skippedDevices.putAll(skippedDevices); 093 } 094 095 /** 096 * Return a list of all devices the sender originally intended to encrypt the message for. 097 * @return list of intended recipients. 098 */ 099 public Set<OmemoDevice> getIntendedDevices() { 100 return intendedDevices; 101 } 102 103 /** 104 * Return a map of all skipped recipients and the reasons for skipping. 105 * @return map of skipped recipients and reasons for that. 106 */ 107 public HashMap<OmemoDevice, Throwable> getSkippedDevices() { 108 return skippedDevices; 109 } 110 111 /** 112 * Determine, if some recipients were skipped during encryption. 113 * @return true if recipients were skipped. 114 */ 115 public boolean isMissingRecipients() { 116 return !getSkippedDevices().isEmpty(); 117 } 118 119 /** 120 * Return the OmemoElement wrapped in a Message ready to be sent. 121 * The message is addressed to recipient, contains the OmemoElement 122 * as well as an optional clear text hint as body, a MAM storage hint 123 * and an EME hint about OMEMO encryption. 124 * 125 * @param recipient recipient for the to-field of the message. 126 * @return Message 127 */ 128 public Message asMessage(Jid recipient) { 129 130 Message messageStanza = new Message(); 131 messageStanza.setTo(recipient); 132 messageStanza.addExtension(getElement()); 133 134 if (OmemoConfiguration.getAddOmemoHintBody()) { 135 messageStanza.setBody(BODY_OMEMO_HINT); 136 } 137 138 StoreHint.set(messageStanza); 139 messageStanza.addExtension(new ExplicitMessageEncryptionElement(OMEMO_NAMESPACE_V_AXOLOTL, OMEMO)); 140 141 return messageStanza; 142 } 143 } 144 145 /** 146 * Incoming OMEMO message. 147 */ 148 public static class Received extends OmemoMessage { 149 private final String message; 150 private final OmemoFingerprint sendersFingerprint; 151 private final OmemoDevice senderDevice; 152 private final boolean preKeyMessage; 153 154 /** 155 * Create a new incoming OMEMO message. 156 * @param element original OmemoElement 157 * @param key message key (or transported key) 158 * @param iv respective initialization vector 159 * @param body decrypted body 160 * @param sendersFingerprint OmemoFingerprint of the senders identityKey 161 * @param senderDevice OmemoDevice of the sender 162 * @param preKeyMessage if this was a preKeyMessage or not 163 */ 164 Received(OmemoElement element, byte[] key, byte[] iv, String body, OmemoFingerprint sendersFingerprint, OmemoDevice senderDevice, boolean preKeyMessage) { 165 super(element, key, iv); 166 this.message = body; 167 this.sendersFingerprint = sendersFingerprint; 168 this.senderDevice = senderDevice; 169 this.preKeyMessage = preKeyMessage; 170 } 171 172 /** 173 * Return the decrypted body of the message. 174 * @return decrypted body 175 */ 176 public String getBody() { 177 return message; 178 } 179 180 /** 181 * Return the fingerprint of the messages sender device. 182 * @return fingerprint of sender 183 */ 184 public OmemoFingerprint getSendersFingerprint() { 185 return sendersFingerprint; 186 } 187 188 /** 189 * Return the OmemoDevice which sent the message. 190 * @return senderDevice 191 */ 192 public OmemoDevice getSenderDevice() { 193 return senderDevice; 194 } 195 196 /** 197 * Return true, if this message was sent as a preKeyMessage. 198 * @return preKeyMessage or not 199 */ 200 boolean isPreKeyMessage() { 201 return preKeyMessage; 202 } 203 204 /** 205 * Return true, if the message was a KeyTransportMessage. 206 * A KeyTransportMessage is a OmemoMessage without a payload. 207 * @return keyTransportMessage? 208 */ 209 public boolean isKeyTransportMessage() { 210 return message == null; 211 } 212 } 213}