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.smack.packet.MessageBuilder; 029 030import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement; 031import org.jivesoftware.smackx.hints.element.StoreHint; 032import org.jivesoftware.smackx.omemo.element.OmemoElement; 033import org.jivesoftware.smackx.omemo.internal.OmemoDevice; 034import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; 035 036import org.jxmpp.jid.Jid; 037 038public class OmemoMessage { 039 040 private final OmemoElement element; 041 private final byte[] messageKey, iv; 042 043 OmemoMessage(OmemoElement element, byte[] key, byte[] iv) { 044 this.element = element; 045 this.messageKey = key; 046 this.iv = iv; 047 } 048 049 /** 050 * Return the original OmemoElement (<encrypted/>). 051 * 052 * @return omemoElement of the message 053 */ 054 public OmemoElement getElement() { 055 return element; 056 } 057 058 /** 059 * Return the messageKey (or transported key in case of a KeyTransportMessage). 060 * 061 * @return encryption key that protects the message payload 062 */ 063 public byte[] getKey() { 064 return messageKey.clone(); 065 } 066 067 /** 068 * Return the initialization vector belonging to the key. 069 * 070 * @return initialization vector 071 */ 072 public byte[] getIv() { 073 return iv.clone(); 074 } 075 076 /** 077 * Outgoing OMEMO message. 078 */ 079 public static class Sent extends OmemoMessage { 080 private final Set<OmemoDevice> intendedDevices = new HashSet<>(); 081 private final HashMap<OmemoDevice, Throwable> skippedDevices = new HashMap<>(); 082 083 /** 084 * Create a new outgoing OMEMO message. 085 * 086 * @param element OmemoElement 087 * @param key messageKey (or transported key) 088 * @param iv initialization vector belonging to key 089 * @param intendedDevices devices the client intended to encrypt the message for 090 * @param skippedDevices devices which were skipped during encryption process because encryption 091 * failed for some reason 092 */ 093 Sent(OmemoElement element, byte[] key, byte[] iv, Set<OmemoDevice> intendedDevices, HashMap<OmemoDevice, Throwable> skippedDevices) { 094 super(element, key, iv); 095 this.intendedDevices.addAll(intendedDevices); 096 this.skippedDevices.putAll(skippedDevices); 097 } 098 099 /** 100 * Return a list of all devices the sender originally intended to encrypt the message for. 101 * 102 * @return list of intended recipients. 103 */ 104 public Set<OmemoDevice> getIntendedDevices() { 105 return intendedDevices; 106 } 107 108 /** 109 * Return a map of all skipped recipients and the reasons for skipping. 110 * 111 * @return map of skipped recipients and reasons for that. 112 */ 113 public HashMap<OmemoDevice, Throwable> getSkippedDevices() { 114 return skippedDevices; 115 } 116 117 /** 118 * Determine, if some recipients were skipped during encryption. 119 * 120 * @return true if recipients were skipped. 121 */ 122 public boolean isMissingRecipients() { 123 return !getSkippedDevices().isEmpty(); 124 } 125 126 /** 127 * Return the OmemoElement wrapped in a Message ready to be sent. 128 * The message is addressed to recipient, contains the OmemoElement 129 * as well as an optional clear text hint as body, a MAM storage hint 130 * and an EME hint about OMEMO encryption. 131 * 132 * @param messageBuilder a message builder which will be used to build the message. 133 * @param recipient recipient for the to-field of the message. 134 * @return the build message. 135 */ 136 public Message buildMessage(MessageBuilder messageBuilder, Jid recipient) { 137 messageBuilder.ofType(Message.Type.chat).to(recipient); 138 139 messageBuilder.addExtension(getElement()); 140 141 if (OmemoConfiguration.getAddOmemoHintBody()) { 142 messageBuilder.setBody(BODY_OMEMO_HINT); 143 } 144 145 StoreHint.set(messageBuilder); 146 messageBuilder.addExtension(new ExplicitMessageEncryptionElement(OMEMO_NAMESPACE_V_AXOLOTL, OMEMO)); 147 148 return messageBuilder.build(); 149 } 150 } 151 152 /** 153 * Incoming OMEMO message. 154 */ 155 public static class Received extends OmemoMessage { 156 private final String message; 157 private final OmemoFingerprint sendersFingerprint; 158 private final OmemoDevice senderDevice; 159 private final boolean preKeyMessage; 160 161 /** 162 * Create a new incoming OMEMO message. 163 * 164 * @param element original OmemoElement 165 * @param key message key (or transported key) 166 * @param iv respective initialization vector 167 * @param body decrypted body 168 * @param sendersFingerprint OmemoFingerprint of the senders identityKey 169 * @param senderDevice OmemoDevice of the sender 170 * @param preKeyMessage if this was a preKeyMessage or not 171 */ 172 Received(OmemoElement element, byte[] key, byte[] iv, String body, OmemoFingerprint sendersFingerprint, OmemoDevice senderDevice, boolean preKeyMessage) { 173 super(element, key, iv); 174 this.message = body; 175 this.sendersFingerprint = sendersFingerprint; 176 this.senderDevice = senderDevice; 177 this.preKeyMessage = preKeyMessage; 178 } 179 180 /** 181 * Return the decrypted body of the message. 182 * 183 * @return decrypted body 184 */ 185 public String getBody() { 186 return message; 187 } 188 189 /** 190 * Return the fingerprint of the messages sender device. 191 * 192 * @return fingerprint of sender 193 */ 194 public OmemoFingerprint getSendersFingerprint() { 195 return sendersFingerprint; 196 } 197 198 /** 199 * Return the OmemoDevice which sent the message. 200 * 201 * @return OMEMO device that sent the message. 202 */ 203 public OmemoDevice getSenderDevice() { 204 return senderDevice; 205 } 206 207 /** 208 * Return true, if this message was sent as a preKeyMessage. 209 * 210 * @return preKeyMessage or not 211 */ 212 boolean isPreKeyMessage() { 213 return preKeyMessage; 214 } 215 216 /** 217 * Return true, if the message was a KeyTransportMessage. 218 * A KeyTransportMessage is a OmemoMessage without a payload. 219 * 220 * @return keyTransportMessage? 221 */ 222 public boolean isKeyTransportMessage() { 223 return message == null; 224 } 225 } 226}