using Gee; using Xmpp.Xep; using Xmpp; namespace Xmpp.Xep.Omemo { public const string NS_URI = "eu.siacs.conversations.axolotl"; public const string NODE_DEVICELIST = NS_URI + ".devicelist"; public const string NODE_BUNDLES = NS_URI + ".bundles"; public const string NODE_VERIFICATION = NS_URI + ".verification"; public abstract class OmemoEncryptor : XmppStreamModule { public static Xmpp.ModuleIdentity IDENTITY = new Xmpp.ModuleIdentity(NS_URI, "0384_omemo_encryptor"); public abstract uint32 own_device_id { get; } public abstract EncryptionData encrypt_plaintext(string plaintext) throws GLib.Error; public abstract void encrypt_key(Xep.Omemo.EncryptionData encryption_data, Jid jid, int32 device_id) throws GLib.Error; public abstract EncryptionResult encrypt_key_to_recipient(XmppStream stream, Xep.Omemo.EncryptionData enc_data, Jid recipient) throws GLib.Error; 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 EncryptionData { public uint32 own_device_id; public uint8[] ciphertext; public uint8[] keytag; public uint8[] iv; public Gee.List key_nodes = new ArrayList(); public EncryptionData(uint32 own_device_id) { this.own_device_id = own_device_id; } public void add_device_key(int device_id, uint8[] device_key, bool prekey) { StanzaNode key_node = new StanzaNode.build("key", NS_URI) .put_attribute("rid", device_id.to_string()) .put_node(new StanzaNode.text(Base64.encode(device_key))); if (prekey) { key_node.put_attribute("prekey", "true"); } key_nodes.add(key_node); } public StanzaNode get_encrypted_node() { StanzaNode encrypted_node = new StanzaNode.build("encrypted", NS_URI).add_self_xmlns(); StanzaNode header_node = new StanzaNode.build("header", NS_URI) .put_attribute("sid", own_device_id.to_string()) .put_node(new StanzaNode.build("iv", NS_URI).put_node(new StanzaNode.text(Base64.encode(iv)))); encrypted_node.put_node(header_node); if (ciphertext != null) { StanzaNode payload_node = new StanzaNode.build("payload", NS_URI) .put_node(new StanzaNode.text(Base64.encode(ciphertext))); encrypted_node.put_node(payload_node); } foreach (StanzaNode key_node in key_nodes) { header_node.put_node(key_node); } return encrypted_node; } } public class EncryptionResult { public int lost { get; internal set; } public int success { get; internal set; } public int unknown { get; internal set; } public int failure { get; internal set; } } public class EncryptState { public bool encrypted { get; internal set; } public int other_devices { get; internal set; } public int other_success { get; internal set; } public int other_lost { get; internal set; } public int other_unknown { get; internal set; } public int other_failure { get; internal set; } public int other_waiting_lists { get; internal set; } public int own_devices { get; internal set; } public int own_success { get; internal set; } public int own_lost { get; internal set; } public int own_unknown { get; internal set; } public int own_failure { get; internal set; } public bool own_list { get; internal set; } public void add_result(EncryptionResult enc_res, bool own) { if (own) { own_lost += enc_res.lost; own_success += enc_res.success; own_unknown += enc_res.unknown; own_failure += enc_res.failure; } else { other_lost += enc_res.lost; other_success += enc_res.success; other_unknown += enc_res.unknown; other_failure += enc_res.failure; } } public string to_string() { return @"EncryptState (encrypted=$encrypted, other=(devices=$other_devices, success=$other_success, lost=$other_lost, unknown=$other_unknown, failure=$other_failure, waiting_lists=$other_waiting_lists, own=(devices=$own_devices, success=$own_success, lost=$own_lost, unknown=$own_unknown, failure=$own_failure, list=$own_list))"; } } }