use of org.jivesoftware.smackx.omemo.element.OmemoKeyElement in project Smack by igniterealtime.
the class OmemoRatchet method retrieveMessageKeyAndAuthTag.
/**
* Try to decrypt the transported message key using the double ratchet session.
*
* @param element omemoElement
* @return tuple of cipher generated from the unpacked message key and the auth-tag
*
* @throws CryptoFailedException if decryption using the double ratchet fails
* @throws NoRawSessionException if we have no session, but the element was NOT a PreKeyMessage
* @throws IOException if an I/O error occurred.
*/
CipherAndAuthTag retrieveMessageKeyAndAuthTag(OmemoDevice sender, OmemoElement element) throws CryptoFailedException, NoRawSessionException, IOException {
int keyId = omemoManager.getDeviceId();
byte[] unpackedKey = null;
List<CryptoFailedException> decryptExceptions = new ArrayList<>();
List<OmemoKeyElement> keys = element.getHeader().getKeys();
boolean preKey = false;
// Find key with our ID.
for (OmemoKeyElement k : keys) {
if (k.getId() == keyId) {
try {
unpackedKey = doubleRatchetDecrypt(sender, k.getData());
preKey = k.isPreKey();
break;
} catch (CryptoFailedException e) {
// There might be multiple keys with our id, but we can only decrypt one.
// So we can't throw the exception, when decrypting the first duplicate which is not for us.
decryptExceptions.add(e);
} catch (CorruptedOmemoKeyException e) {
decryptExceptions.add(new CryptoFailedException(e));
} catch (UntrustedOmemoIdentityException e) {
LOGGER.log(Level.WARNING, "Received message from " + sender + " contained unknown identityKey. Ignore message.", e);
}
}
}
if (unpackedKey == null) {
if (!decryptExceptions.isEmpty()) {
throw MultipleCryptoFailedException.from(decryptExceptions);
}
throw new CryptoFailedException("Transported key could not be decrypted, since no suitable message key " + "was provided. Provides keys: " + keys);
}
// Split in AES auth-tag and key
byte[] messageKey = new byte[16];
byte[] authTag = null;
if (unpackedKey.length == 32) {
authTag = new byte[16];
// copy key part into messageKey
System.arraycopy(unpackedKey, 0, messageKey, 0, 16);
// copy tag part into authTag
System.arraycopy(unpackedKey, 16, authTag, 0, 16);
} else if (element.isKeyTransportElement() && unpackedKey.length == 16) {
messageKey = unpackedKey;
} else {
throw new CryptoFailedException("MessageKey has wrong length: " + unpackedKey.length + ". Probably legacy auth tag format.");
}
return new CipherAndAuthTag(messageKey, element.getHeader().getIv(), authTag, preKey);
}
use of org.jivesoftware.smackx.omemo.element.OmemoKeyElement in project Smack by igniterealtime.
the class OmemoVAxolotlElementTest method serializationTest.
@Test
public void serializationTest() throws Exception {
byte[] payload = "This is payload.".getBytes(StandardCharsets.UTF_8);
int keyId1 = 8;
int keyId2 = 33333;
byte[] keyData1 = "KEYDATA".getBytes(StandardCharsets.UTF_8);
byte[] keyData2 = "DATAKEY".getBytes(StandardCharsets.UTF_8);
int sid = 12131415;
byte[] iv = OmemoMessageBuilder.generateIv();
ArrayList<OmemoKeyElement> keys = new ArrayList<>();
keys.add(new OmemoKeyElement(keyData1, keyId1));
keys.add(new OmemoKeyElement(keyData2, keyId2, true));
OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(sid, keys, iv);
OmemoElement_VAxolotl element = new OmemoElement_VAxolotl(header, payload);
String expected = "<encrypted xmlns='eu.siacs.conversations.axolotl'>" + "<header sid='12131415'>" + "<key rid='8'>" + Base64.encodeToString(keyData1) + "</key>" + "<key prekey='true' rid='33333'>" + Base64.encodeToString(keyData2) + "</key>" + "<iv>" + Base64.encodeToString(iv) + "</iv>" + "</header>" + "<payload>" + Base64.encodeToString(payload) + "</payload>" + "</encrypted>";
String actual = element.toXML().toString();
assertEquals("Serialized xml of OmemoElement must match.", expected, actual);
OmemoElement_VAxolotl parsed = new OmemoVAxolotlProvider().parse(TestUtils.getParser(actual));
assertEquals("Parsed OmemoElement must equal the original.", element.toXML().toString(), parsed.toXML().toString());
}
use of org.jivesoftware.smackx.omemo.element.OmemoKeyElement in project Smack by igniterealtime.
the class OmemoMessageBuilder method addRecipient.
/**
* Add a new recipient device to the message.
*
* @param contactsDevice device of the recipient
*
* @throws NoIdentityKeyException if we have no identityKey of that device. Can be fixed by fetching and
* processing the devices bundle.
* @throws CorruptedOmemoKeyException if the identityKey of that device is corrupted.
* @throws UndecidedOmemoIdentityException if the user hasn't yet decided whether to trust that device or not.
* @throws UntrustedOmemoIdentityException if the user has decided not to trust that device.
* @throws IOException if an I/O error occurred.
*/
public void addRecipient(OmemoDevice contactsDevice) throws NoIdentityKeyException, CorruptedOmemoKeyException, UndecidedOmemoIdentityException, UntrustedOmemoIdentityException, IOException {
OmemoFingerprint fingerprint;
fingerprint = OmemoService.getInstance().getOmemoStoreBackend().getFingerprint(userDevice, contactsDevice);
switch(trustCallback.getTrust(contactsDevice, fingerprint)) {
case undecided:
throw new UndecidedOmemoIdentityException(contactsDevice);
case trusted:
CiphertextTuple encryptedKey = ratchet.doubleRatchetEncrypt(contactsDevice, messageKey);
keys.add(new OmemoKeyElement(encryptedKey.getCiphertext(), contactsDevice.getDeviceId(), encryptedKey.isPreKeyMessage()));
break;
case untrusted:
throw new UntrustedOmemoIdentityException(contactsDevice, fingerprint);
}
}
use of org.jivesoftware.smackx.omemo.element.OmemoKeyElement in project Smack by igniterealtime.
the class OmemoVAxolotlProvider method parse.
@Override
public OmemoElement_VAxolotl parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException {
int sid = -1;
ArrayList<OmemoKeyElement> keys = new ArrayList<>();
byte[] iv = null;
byte[] payload = null;
outerloop: while (true) {
XmlPullParser.Event tag = parser.next();
switch(tag) {
case START_ELEMENT:
String name = parser.getName();
switch(name) {
case OmemoHeaderElement.ELEMENT:
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals(OmemoHeaderElement.ATTR_SID)) {
sid = Integer.parseInt(parser.getAttributeValue(i));
}
}
break;
case OmemoKeyElement.ELEMENT:
boolean prekey = false;
int rid = -1;
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals(OmemoKeyElement.ATTR_PREKEY)) {
prekey = Boolean.parseBoolean(parser.getAttributeValue(i));
} else if (parser.getAttributeName(i).equals(OmemoKeyElement.ATTR_RID)) {
rid = Integer.parseInt(parser.getAttributeValue(i));
}
}
keys.add(new OmemoKeyElement(Base64.decode(parser.nextText()), rid, prekey));
break;
case OmemoHeaderElement.ATTR_IV:
iv = Base64.decode(parser.nextText());
break;
case ATTR_PAYLOAD:
payload = Base64.decode(parser.nextText());
break;
}
break;
case END_ELEMENT:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
default:
// Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
break;
}
}
OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(sid, keys, iv);
return new OmemoElement_VAxolotl(header, payload);
}
Aggregations