Search in sources :

Example 1 with OmemoKeyElement

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);
}
Also used : MultipleCryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException) CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) OmemoKeyElement(org.jivesoftware.smackx.omemo.element.OmemoKeyElement) ArrayList(java.util.ArrayList) CipherAndAuthTag(org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag) UntrustedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)

Example 2 with OmemoKeyElement

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());
}
Also used : OmemoElement_VAxolotl(org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl) OmemoVAxolotlProvider(org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider) OmemoKeyElement(org.jivesoftware.smackx.omemo.element.OmemoKeyElement) OmemoHeaderElement_VAxolotl(org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl) ArrayList(java.util.ArrayList) Test(org.junit.Test)

Example 3 with OmemoKeyElement

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);
    }
}
Also used : UndecidedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException) OmemoKeyElement(org.jivesoftware.smackx.omemo.element.OmemoKeyElement) OmemoFingerprint(org.jivesoftware.smackx.omemo.trust.OmemoFingerprint) UntrustedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException) CiphertextTuple(org.jivesoftware.smackx.omemo.internal.CiphertextTuple)

Example 4 with OmemoKeyElement

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);
}
Also used : OmemoElement_VAxolotl(org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl) OmemoKeyElement(org.jivesoftware.smackx.omemo.element.OmemoKeyElement) OmemoHeaderElement_VAxolotl(org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl) ArrayList(java.util.ArrayList)

Aggregations

OmemoKeyElement (org.jivesoftware.smackx.omemo.element.OmemoKeyElement)4 ArrayList (java.util.ArrayList)3 OmemoElement_VAxolotl (org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl)2 OmemoHeaderElement_VAxolotl (org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl)2 UntrustedOmemoIdentityException (org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException)2 CorruptedOmemoKeyException (org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)1 CryptoFailedException (org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException)1 MultipleCryptoFailedException (org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException)1 UndecidedOmemoIdentityException (org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException)1 CipherAndAuthTag (org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag)1 CiphertextTuple (org.jivesoftware.smackx.omemo.internal.CiphertextTuple)1 OmemoVAxolotlProvider (org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider)1 OmemoFingerprint (org.jivesoftware.smackx.omemo.trust.OmemoFingerprint)1 Test (org.junit.Test)1