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