using Gee; using Xmpp.Xep; using Xmpp; namespace Xmpp.Xep.Omemo { public abstract class OmemoDecryptor : XmppStreamModule { public static Xmpp.ModuleIdentity IDENTITY = new Xmpp.ModuleIdentity(NS_URI, "0384_omemo_decryptor"); public abstract uint32 own_device_id { get; } public abstract string decrypt(uint8[] ciphertext, uint8[] key, uint8[] iv) throws GLib.Error; public abstract uint8[] decrypt_key(ParsedData data, Jid from_jid) throws GLib.Error; public ParsedData? parse_node(StanzaNode encrypted_node) { ParsedData ret = new ParsedData(); StanzaNode? header_node = encrypted_node.get_subnode("header"); if (header_node == null) { warning("Can't parse OMEMO node: No header node"); return null; } ret.sid = header_node.get_attribute_int("sid", -1); if (ret.sid == -1) { warning("Can't parse OMEMO node: No sid"); return null; } string? payload_str = encrypted_node.get_deep_string_content("payload"); if (payload_str != null) ret.ciphertext = Base64.decode(payload_str); string? iv_str = header_node.get_deep_string_content("iv"); if (iv_str == null) { warning("Can't parse OMEMO node: No iv"); return null; } ret.iv = Base64.decode(iv_str); foreach (StanzaNode key_node in header_node.get_subnodes("key")) { debug("Is ours? %d =? %u", key_node.get_attribute_int("rid"), own_device_id); if (key_node.get_attribute_int("rid") == own_device_id) { string? key_node_content = key_node.get_string_content(); if (key_node_content == null) continue; uchar[] encrypted_key = Base64.decode(key_node_content); ret.our_potential_encrypted_keys[new Bytes.take(encrypted_key)] = key_node.get_attribute_bool("prekey"); } } return ret; } public override void attach(XmppStream stream) { } public override void detach(XmppStream stream) { } public override string get_ns() { return NS_URI; } public override string get_id() { return IDENTITY.id; } } public class ParsedData { public int sid; public uint8[] ciphertext; public uint8[] iv; public uchar[] encrypted_key; public bool is_prekey; public HashMap our_potential_encrypted_keys = new HashMap(); } }