Commit b55c563e authored by Philipp Hörist's avatar Philipp Hörist

asdasd

parent 3e416ede
# -*- coding: utf-8 -*-
#
# Copyright 2015 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
#
# This file is part of python-omemo library.
#
# The python-omemo library is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# python-omemo is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# the python-omemo library. If not, see <http://www.gnu.org/licenses/>.
#
import os
import logging
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers import algorithms
from cryptography.hazmat.primitives.ciphers.modes import GCM
# On Windows we have to import a specific backend because the
# default_backend() mechanism doesnt work in Gajim for Windows.
# Its because of how Gajim is build with cx_freeze
if os.name == 'nt':
from cryptography.hazmat.backends.openssl import backend
else:
from cryptography.hazmat.backends import default_backend
log = logging.getLogger('gajim.plugin_system.omemo')
def aes_decrypt(_key, iv, payload):
""" Use AES128 GCM with the given key and iv to decrypt the payload. """
if len(_key) >= 32:
# XEP-0384
log.debug('XEP Compliant Key/Tag')
data = payload
key = _key[:16]
tag = _key[16:]
else:
# Legacy
log.debug('Legacy Key/Tag')
data = payload[:-16]
key = _key
tag = payload[-16:]
if os.name == 'nt':
_backend = backend
else:
_backend = default_backend()
decryptor = Cipher(
algorithms.AES(key),
GCM(iv, tag=tag),
backend=_backend).decryptor()
return decryptor.update(data) + decryptor.finalize()
def aes_encrypt(key, iv, plaintext):
""" Use AES128 GCM with the given key and iv to encrypt the plaintext. """
if os.name == 'nt':
_backend = backend
else:
_backend = default_backend()
encryptor = Cipher(
algorithms.AES(key),
GCM(iv),
backend=_backend).encryptor()
return encryptor.update(plaintext) + encryptor.finalize(), encryptor.tag
......@@ -45,7 +45,7 @@ try:
from cryptography.hazmat.primitives.ciphers import algorithms
from cryptography.hazmat.primitives.ciphers.modes import GCM
from cryptography.hazmat.backends import default_backend
from omemo.omemo.aes_gcm_native import aes_encrypt
from omemo2.aes_gcm_native import aes_encrypt
except ImportError:
log.exception('ImportError')
ERROR = True
......
[info]
name: OMEMO
short_name: omemo
name: OMEMO2
short_name: omemo2
version: 2.5.7
description: OMEMO is an XMPP Extension Protocol (XEP) for secure multi-client end-to-end encryption based on Axolotl and PEP. You need to install some dependencies, you can find install instructions for your system in the Github Wiki.
description: OMEMO
authors: Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
Daniel Gultsch <daniel@gultsch.de>
Philipp Hörist <philipp@hoerist.com>
......
......@@ -15,12 +15,12 @@ from gajim.common.connection_handlers_events import (
MessageReceivedEvent, MamMessageReceivedEvent, MessageNotSentEvent,
MamGcMessageReceivedEvent)
from omemo.xmpp import (
from omemo2.xmpp import (
NS_NOTIFY, NS_OMEMO, NS_EME, NS_HINTS, BundleInformationAnnouncement,
BundleInformationQuery, DeviceListAnnouncement, DevicelistQuery,
build_omemo_stanza, successful, unpack_device_bundle,
unpack_device_list_update, unpack_encrypted)
from omemoimpl.session_manager import SessionManager
from omemo2.omemoimpl.session_manager import SessionManager
DB_DIR_OLD = app.gajimpaths.data_root
DB_DIR_NEW = app.gajimpaths['MY_DATA']
......@@ -110,7 +110,7 @@ class OMEMOConnection:
SessionManager
"""
db_path = self.migrate_dbpath()
return SessionManager(self.own_jid, db_path, self.account, self)
return SessionManager(self.own_jid, db_path)
def signed_in(self, event):
""" Method called on SignIn
......@@ -638,7 +638,7 @@ class OMEMOConnection:
if self.get_own_jid().bareMatch(contact_jid):
log.info('%s => Received own device list: %s',
self.account, devices_list)
self.omemo.set_devicelist(contact_jid, devices_list)
self.omemo.set_devicelist(devices_list)
# remove contact from list, so on send button pressed
# we query for bundle and build a session
......@@ -653,7 +653,7 @@ class OMEMOConnection:
log.info('%s => Received device list for %s: %s',
self.account, contact_jid, devices_list)
self.omemo.set_devicelist(contact_jid, devices_list)
self.omemo.set_devicelist(devices_list, contact_jid)
# remove contact from list, so on send button pressed
# we query for bundle and build a session
if contact_jid in self.query_for_bundles:
......@@ -874,7 +874,7 @@ class OMEMOConnection:
self.omemo.clear_devicelist()
log.info('%s => Clearing devicelist', self.account)
device_announce = DeviceListAnnouncement(self.omemo.get_own_device_id())
device_announce = DeviceListAnnouncement([self.omemo.get_own_device_id()])
self.send_with_callback(device_announce, self.clear_device_list_result)
@staticmethod
......
from omemo.util import generateDeviceID
class DeviceManager:
def __init__(self):
self._devices = {}
self.own_device_id = None
self._init_devices()
def _init_devices(self):
self._devices = self.getActiveDevices()
self.own_device_id = self.getOwnDeviceId()
if self.own_device_id is None:
self.own_device_id = generateDeviceID()
def extend_devicelist(self, jid, device_list):
# Remove duplicates
device_list = set(device_list)
# Remove own device
if self.own_device_id in device_list:
device_list.remove(self.own_device_id)
if jid not in self._devices:
self.set_devicelist(jid, device_list)
else:
self._devices[jid].extend(device_list)
self.setDevicesActive(device_list)
def set_devicelist(self, jid, device_list):
# Remove duplicates
device_list = set(device_list)
# Remove own device
if self.own_device_id in device_list:
device_list.remove(self.own_device_id)
if jid not in self._devices:
self._devices[jid] = device_list
self.setDevicesActive(device_list)
else:
active = [d for d in device_list if d not in self._devices[jid]]
inactive = [d for d in self._devices[jid] if d not in device_list]
self._devices[jid] = device_list
self.setDevicesActive(active)
self.setDevicesInactive(inactive)
def get_devicelist(self, jid):
if jid not in self._devices:
return []
return self._devices[jid]
from omemo import SessionManager
import omemo
from .storage import SQLiteDatabase
from omemo.util import generateDeviceID
class SessionManager:
......@@ -7,25 +8,29 @@ class SessionManager:
# Database Inferface
self._store = SQLiteDatabase(db_path)
# OmemoSessionManager
self._sm = SessionManager(own_jid, self._store)
self._sm = omemo.SessionManager(own_jid, self._store, generateDeviceID())
def build_session(self, bundle):
self._store.createSession()
def get_bundle(self):
return self._sm.getState().getPublicBundle()
return self._sm.state.getPublicBundle()
def set_devicelist(self, device_list, jid=None):
self._sm.newDeviceList(device_list, jid)
def get_devicelist(self, jid, active=True):
return self._store.loadDevices(jid, active)
def get_devicelist(self, jid):
return self._sm.getDevices(jid)
def get_own_device_id(self):
return self._store.own_device_id
return self._sm.my_device_id
def get_own_devices(self):
return self._sm.getDevices()['active']
devices = self._sm.getDevices()['active']
if self._sm.my_device_id not in devices:
devices = list(devices)
devices.append(self._sm.my_device_id)
return devices
def get_devices_without_session(self, jid):
return self._store.getDevicesWithoutSession(jid)
......
......@@ -22,7 +22,7 @@ import pickle
import logging
from collections import namedtuple
from omemo.signal.storage import Storage
from omemo.storage import Storage
from omemo.x3dhdoubleratchet import X3DHDoubleRatchet
from omemo.signal.doubleratchet.doubleratchet import DoubleRatchet
......@@ -31,7 +31,7 @@ from .db_helpers import user_version
log = logging.getLogger('gajim.plugin_system.omemo.db')
class SQLiteDatabase(Storage, DeviceManager):
class SQLiteDatabase(Storage):
""" SQLite Database """
def __init__(self, db_path):
......@@ -48,6 +48,7 @@ class SQLiteDatabase(Storage, DeviceManager):
self._migrate_database()
self._con.execute("PRAGMA synchronous=FULL;")
self._con.commit()
self._own_device_id = None
def _create_database(self):
if user_version(self._con) == 0:
......@@ -57,17 +58,17 @@ class SQLiteDatabase(Storage, DeviceManager):
jid TEXT,
device_id INTEGER,
session omemo_session BLOB,
state omemo_state BLOB,
fingerprint TEXT,
active INTEGER DEFAULT 1,
trust INTEGER DEFAULT 1,
UNIQUE(jid, device_id));
'''
create_tables = '''
CREATE TABLE IF NOT EXISTS state (
_id INTEGER PRIMARY KEY,
device_id INTEGER,
state omemo_state BLOB;
state omemo_state BLOB
);
'''
create_db_sql = """
......@@ -76,7 +77,7 @@ class SQLiteDatabase(Storage, DeviceManager):
PRAGMA user_version=1;
END TRANSACTION;
""" % (create_tables)
self.con.executescript(create_db_sql)
self._con.executescript(create_db_sql)
def _migrate_database(self):
""" Migrates the DB
......@@ -99,28 +100,35 @@ class SQLiteDatabase(Storage, DeviceManager):
return named_row
def loadState(self):
q = 'SELECT state FROM state'
log.info('Load State')
q = 'SELECT device_id, state FROM state'
result = self._con.execute(q).fetchone()
if result is not None:
return result.session
def storeState(self, state):
q = 'INSERT OR REPLACE INTO state(_id, state) VALUES(?)'
self._con.execute(q, (1, state))
self._own_device_id = result.device_id
return {'state': result.state, 'device_id': result.device_id}
def storeState(self, state, device_id):
log.info('Store State')
self._own_device_id = device_id
q = 'INSERT OR REPLACE INTO state(device_id, state) VALUES(?, ?)'
self._con.execute(q, (device_id, state))
self._con.commit()
def loadSession(self, jid, device_id):
log.info('Load Session')
q = 'SELECT session FROM sessions WHERE jid = ? AND device_id = ?'
result = self._con.execute(q, (jid, device_id)).fetchone()
if result is not None:
return result.session
def storeSession(self, jid, device_id, session):
log.info('Store Session: %s, %s', jid, device_id)
q = 'UPDATE sessions SET session = ? WHERE jid= ? AND device_id = ?'
self._con.execute(q, (session, jid, device_id))
self._con.commit()
def createSession(self, jid, device_id, session):
log.info('Create Session')
q = '''INSERT INTO sessions(jid, device_id, session, trust, active)
VALUES (?, ?, ?, 1, 1)'''
self._con.execute(q, (jid, device_id, session))
......@@ -133,17 +141,30 @@ class SQLiteDatabase(Storage, DeviceManager):
return self.loadDevices(jid, 0)
def loadDevices(self, jid, active):
q = 'SELECT device_id FROM devices WHERE jid = ? AND active = ?'
q = 'SELECT device_id FROM sessions WHERE jid = ? AND active = ?'
result = self._con.execute(q, (jid, active)).fetchall()
if result:
return [row.device_id for row in result]
devices = [row.device_id for row in result]
state = 'Active' if active else 'Inactive'
log.info('Load %s Devices: %s, %s', state, jid, devices)
return devices
return []
def storeActiveDevices(self, jid, devices):
self.storeDevices(self, jid, devices, 1)
if not devices:
return
# python-omemo returns own device as active,
# dont store it in this table
if self._own_device_id in devices:
devices.remove(self._own_device_id)
log.info('Store Active Devices: %s, %s', jid, devices)
self.storeDevices(jid, devices, 1)
def storeInactiveDevices(self, jid, devices):
self.storeDevices(self, jid, devices, 0)
if not devices:
return
log.info('Store Inactive Devices: %s, %s', jid, devices)
self.storeDevices(jid, devices, 0)
def storeDevices(self, jid, devices, active):
for device_id in devices:
......@@ -152,25 +173,29 @@ class SQLiteDatabase(Storage, DeviceManager):
VALUES(?, ?, ?)'''
self._con.execute(insert, (jid, device_id, active))
self._con.commit()
except Exception:
log.exception('storeDevices()')
except sqlite3.IntegrityError:
update = '''UPDATE sessions SET active = ?
WHERE jid = ? AND device_id = ?'''
self._con.execute(update, (active, jid, device_id))
self._con.commit()
def getDevicesWithoutSession(self, jid):
log.info('Get Devices without Session')
q = '''SELECT device_id FROM sessions
WHERE jid = ? AND (session IS NULL OR session = "")'''
result = self._con.execute(q, (jid,)).fetchall()
if result:
return [row.device_id for row in result]
devices = [row.device_id for row in result]
log.info('Get Devices without Session: %s', devices)
return devices
log.info('Get Devices without Session: []')
return []
def getTrustedFingerprints(self, jid):
return True
def storeBundle(self, jid, device_id, fingerprint):
log.info('Store Bundle')
q = '''UPDATE sessions SET fingerprint = ?
WHERE jid = ? and device_id = ?'''
self._con.execute(q, (fingerprint, jid, device_id))
......
......@@ -33,7 +33,7 @@ from gajim.common.pep import SUPPORTED_PERSONAL_USER_EVENTS
from gajim.plugins import GajimPlugin
from gajim.groupchat_control import GroupchatControl
from omemo.xmpp import DevicelistPEP
from omemo2.xmpp import DevicelistPEP
CRYPTOGRAPHY_MISSING = 'You are missing Python-Cryptography'
AXOLOTL_MISSING = 'You are missing Python-Axolotl or use an outdated version'
......@@ -45,7 +45,7 @@ ERROR_MSG = ''
log = logging.getLogger('gajim.plugin_system.omemo')
try:
from omemo import file_crypto
from omemo2 import file_crypto
except Exception as error:
log.exception(error)
ERROR_MSG = CRYPTOGRAPHY_MISSING
......@@ -58,8 +58,8 @@ except Exception as error:
if not ERROR_MSG:
try:
from omemo.omemo_connection import OMEMOConnection
from omemo.ui import OMEMOConfigDialog, FingerprintWindow
from omemo2.omemo_connection import OMEMOConnection
from omemo2.ui import OMEMOConfigDialog, FingerprintWindow
except Exception as error:
log.error(error)
ERROR_MSG = 'Error: %s' % error
......
......@@ -26,7 +26,6 @@ import os
from enum import IntEnum, unique
from gi.repository import Gtk, GdkPixbuf, Gdk
from axolotl.state.sessionrecord import SessionRecord
log = logging.getLogger('gajim.plugin_system.omemo')
......
......@@ -33,7 +33,7 @@ from gajim.common.pep import AbstractPEP # pylint: disable=import-error
from gajim.plugins.helpers import log_calls # pylint: disable=import-error
from omemo.signal.x3dh import ExtendedPublicBundle
from omemo.wireformat import decodePublicKey
from omemo.signal.wireformat import decodePublicKey
NS_PUBSUB_EVENT = NS_PUBSUB + '#event'
......@@ -130,19 +130,20 @@ class BundleInformationAnnouncement(Iq):
prekey_pub_node = result.addChild(
'signedPreKeyPublic',
attrs={'signedPreKeyId': bundle.spk['id']})
prekey_pub_node.addData(bundle.spk['key'].decode('utf-8'))
prekey_pub_node.addData(b64encode(bundle.spk['key']).decode('utf-8'))
prekey_sig_node = result.addChild('signedPreKeySignature')
prekey_sig_node.addData(bundle.spk_signature.decode('utf-8'))
#prekey_sig_node.addData(b64encode(bundle.spk_signature).decode('utf-8'))
identity_key_node = result.addChild('identityKey')
identity_key_node.addData(bundle.ik.decode('utf-8'))
identity_key_node.addData(b64encode(bundle.ik).decode('utf-8'))
prekeys = result.addChild('prekeys')
for key in bundle.otpks:
prekeys.addChild('preKeyPublic',
attrs={'preKeyId': key['id']}) \
.addData(key['key'].decode('utf-8'))
.addData(b64encode(key['key']).decode('utf-8'))
return result
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment