python-axolotl-0.1.7/0000777000000000000000000000000012521166655014473 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/0000777000000000000000000000000012521166655016155 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/duplicatemessagexception.py0000777000000000000000000000006412447324347023624 0ustar rootroot00000000000000class DuplicateMessageException(Exception): passpython-axolotl-0.1.7/axolotl/ecc/0000777000000000000000000000000012521166655016707 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/ecc/curve.py0000777000000000000000000000566212455435565020426 0ustar rootroot00000000000000import axolotl_curve25519 as _curve import os from .eckeypair import ECKeyPair from axolotl.invalidkeyexception import InvalidKeyException class Curve: DJB_TYPE = 5 # always DJB curve25519 keys @staticmethod def generatePrivateKey(): rand = os.urandom(32) return _curve.generatePrivateKey(rand) @staticmethod def generatePublicKey(privateKey): return _curve.generatePublicKey(privateKey) @staticmethod def generateKeyPair(): from axolotl.ecc import djbec privateKey = Curve.generatePrivateKey() publicKey = Curve.generatePublicKey(privateKey) return ECKeyPair(djbec.DjbECPublicKey(publicKey), djbec.DjbECPrivateKey(privateKey)) @staticmethod def decodePoint(_bytes, offset=0): from axolotl.ecc import djbec type = _bytes[0] # byte appears to be automatically converted to an integer?? if type == Curve.DJB_TYPE: type = _bytes[offset] & 0xFF if type != Curve.DJB_TYPE: raise InvalidKeyException("Unknown key type: %s " % type ) keyBytes = _bytes[offset+1:][:32] return djbec.DjbECPublicKey(bytes(keyBytes)) else: raise InvalidKeyException("Unknown key type: %s" % type ) @staticmethod def decodePrivatePoint(_bytes): from axolotl.ecc import djbec return djbec.DjbECPrivateKey(bytes(_bytes)) @staticmethod def calculateAgreement(publicKey, privateKey): """ :type publicKey: ECPublicKey :type privateKey: ECPrivateKey """ if publicKey.getType() != privateKey.getType(): raise InvalidKeyException("Public and private keys must be of the same type!") if publicKey.getType() == Curve.DJB_TYPE: return _curve.calculateAgreement(privateKey.getPrivateKey(), publicKey.getPublicKey()) else: raise InvalidKeyException("Unknown type: %s" % publicKey.getType()) @staticmethod def verifySignature(ecPublicSigningKey, message, signature): """ :type ecPublicSigningKey: ECPublicKey :type message: bytearray :type signature: bytearray """ if ecPublicSigningKey.getType() ==Curve.DJB_TYPE: result = _curve.verifySignature(ecPublicSigningKey.getPublicKey(), message, signature) return result == 0 else: raise InvalidKeyException("Unknown type: %s" % ecPublicSigningKey.getType()) @staticmethod def calculateSignature(privateSigningKey ,message): """ :type privateSigningKey: ECPrivateKey :type message: bytearray """ if privateSigningKey.getType() == Curve.DJB_TYPE: rand = os.urandom(64) res = _curve.calculateSignature(rand, privateSigningKey.getPrivateKey(), message) return res else: raise InvalidKeyException("Unknown type: %s" % privateSigningKey.getType()) python-axolotl-0.1.7/axolotl/ecc/djbec.py0000777000000000000000000000265412450012317020324 0ustar rootroot00000000000000import struct from .ec import ECPublicKey, ECPrivateKey from ..util.byteutil import ByteUtil from axolotl.ecc import curve import sys import binascii class DjbECPublicKey(ECPublicKey): def __init__(self, publicKey): self.publicKey = publicKey def serialize(self): combined = ByteUtil.combine([curve.Curve.DJB_TYPE], self.publicKey) return bytes(combined) def getType(self): return curve.Curve.DJB_TYPE def getPublicKey(self): return self.publicKey def __eq__(self, other): return self.publicKey == other.getPublicKey() def __lt__(self, other): myVal = int(binascii.hexlify(self.publicKey), 16) otherVal = int(binascii.hexlify(other.getPublicKey()), 16) return myVal < otherVal def __cmp__(self, other): myVal = int(binascii.hexlify(self.publicKey), 16) otherVal = int(binascii.hexlify(other.getPublicKey()), 16) if myVal < otherVal: return -1 elif myVal == otherVal: return 0 else: return 1 class DjbECPrivateKey(ECPrivateKey): def __init__(self, privateKey): self.privateKey = privateKey def getType(self): return curve.Curve.DJB_TYPE def getPrivateKey(self): return self.privateKey def serialize(self): return self.privateKey def __eq__(self, other): return self.privateKey == other.getPrivateKey() python-axolotl-0.1.7/axolotl/ecc/ec.py0000777000000000000000000000054612445610165017653 0ustar rootroot00000000000000import abc class ECPublicKey(object): __metaclass__ = abc.ABCMeta KEY_SIZE = 33 @abc.abstractmethod def serialize(self):pass @abc.abstractmethod def getType(self):pass class ECPrivateKey(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def serialize(self):pass @abc.abstractmethod def getType(self):passpython-axolotl-0.1.7/axolotl/ecc/eckeypair.py0000777000000000000000000000055012446112542021230 0ustar rootroot00000000000000class ECKeyPair(): def __init__(self, publicKey, privateKey): """ :type publicKey: ECPublicKey :type privateKey: ECPrivateKey """ self.publicKey = publicKey self.privateKey = privateKey def getPrivateKey(self): return self.privateKey def getPublicKey(self): return self.publicKey python-axolotl-0.1.7/axolotl/ecc/__init__.py0000777000000000000000000000000012454325127021005 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/groups/0000777000000000000000000000000012521166655017474 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/groups/groupcipher.py0000777000000000000000000001070112454114630022366 0ustar rootroot00000000000000import sys from axolotl.invalidkeyidexception import InvalidKeyIdException from axolotl.invalidkeyexception import InvalidKeyException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.duplicatemessagexception import DuplicateMessageException from axolotl.nosessionexception import NoSessionException from axolotl.groups.state.senderkeystore import SenderKeyStore from axolotl.protocol.senderkeymessage import SenderKeyMessage from axolotl.sessioncipher import AESCipher class GroupCipher: def __init__(self, senderKeyStore, senderKeyId): """ :type senderKeyStore: SenderKeyStore :type senderKeyId: str """ self.senderKeyStore = senderKeyStore self.senderKeyId = senderKeyId def encrypt(self, paddedPlaintext): """ :type paddedPlaintext: str """ paddedPlaintext = bytearray(paddedPlaintext.encode() if sys.version_info > (3,0) else paddedPlaintext) try: record = self.senderKeyStore.loadSenderKey(self.senderKeyId) senderKeyState = record.getSenderKeyState() senderKey = senderKeyState.getSenderChainKey().getSenderMessageKey() ciphertext = self.getCipherText(senderKey.getIv(), senderKey.getCipherKey(), paddedPlaintext) senderKeyMessage = SenderKeyMessage(senderKeyState.getKeyId(), senderKey.getIteration(), ciphertext, senderKeyState.getSigningKeyPrivate()) senderKeyState.setSenderChainKey(senderKeyState.getSenderChainKey().getNext()) self.senderKeyStore.storeSenderKey(self.senderKeyId, record) return senderKeyMessage.serialize() except InvalidKeyIdException as e: raise NoSessionException(e) def decrypt(self, senderKeyMessageBytes): """ :type senderKeyMessageBytes: bytearray """ try: record = self.senderKeyStore.loadSenderKey(self.senderKeyId) senderKeyMessage = SenderKeyMessage(serialized = bytes(senderKeyMessageBytes)) senderKeyState = record.getSenderKeyState(senderKeyMessage.getKeyId()) senderKeyMessage.verifySignature(senderKeyState.getSigningKeyPublic()) senderKey = self.getSenderKey(senderKeyState, senderKeyMessage.getIteration()) plaintext = self.getPlainText(senderKey.getIv(), senderKey.getCipherKey(), senderKeyMessage.getCipherText()) self.senderKeyStore.storeSenderKey(self.senderKeyId, record) return plaintext except (InvalidKeyException, InvalidKeyIdException) as e: raise InvalidMessageException(e) def getSenderKey(self, senderKeyState, iteration): senderChainKey = senderKeyState.getSenderChainKey() if senderChainKey.getIteration() > iteration: if senderKeyState.hasSenderMessageKey(iteration): return senderKeyState.removeSenderMessageKey(iteration) else: raise DuplicateMessageException("Received message with old counter: %s, %s" % (senderChainKey.getIteration(), iteration)) if senderChainKey.getIteration() - iteration > 2000: raise InvalidMessageException("Over 2000 messages into the future!") while senderChainKey.getIteration() < iteration: senderKeyState.addSenderMessageKey(senderChainKey.getSenderMessageKey()) senderChainKey = senderChainKey.getNext() senderKeyState.setSenderChainKey(senderChainKey.getNext()) return senderChainKey.getSenderMessageKey() def getPlainText(self, iv, key, ciphertext): """ :type iv: bytearray :type key: bytearray :type ciphertext: bytearray """ try: cipher = AESCipher(key, iv) plaintext = cipher.decrypt(ciphertext) if sys.version_info >= (3,0): return plaintext.decode() return plaintext except Exception as e: raise InvalidMessageException(e) def getCipherText(self, iv, key, plaintext): """ :type iv: bytearray :type key: bytearray :type plaintext: bytearray """ cipher = AESCipher(key, iv) return cipher.encrypt(bytes(plaintext)) python-axolotl-0.1.7/axolotl/groups/groupsessionbuilder.py0000777000000000000000000000264012454066776024172 0ustar rootroot00000000000000from axolotl.protocol.senderkeydistributionmessage import SenderKeyDistributionMessage class GroupSessionBuilder: def __init__(self, senderKeyStore): self.senderKeyStore = senderKeyStore def processSender(self, sender, senderKeyDistributionMessage): """ :type sender: str :type senderKeyDistributionMessage: SenderKeyDistributionMessage """ senderKeyRecord = self.senderKeyStore.loadSenderKey(sender) senderKeyRecord.addSenderKeyState(senderKeyDistributionMessage.getId(), senderKeyDistributionMessage.getIteration(), senderKeyDistributionMessage.getChainKey(), senderKeyDistributionMessage.getSignatureKey()) self.senderKeyStore.storeSenderKey(sender, senderKeyRecord) def process(self, groupId, keyId, iteration, chainKey, signatureKey): """ :type groupId: str :type keyId: int :type iteration: int :type chainKey: bytearray :type signatureKey: ECKeyPair """ senderKeyRecord = self.senderKeyStore.loadSenderKey(groupId) senderKeyRecord.setSenderKeyState(keyId, iteration, chainKey, signatureKey) self.senderKeyStore.storeSenderKey(groupId, senderKeyRecord) return SenderKeyDistributionMessage(keyId, iteration, chainKey, signatureKey.getPublicKey()) python-axolotl-0.1.7/axolotl/groups/ratchet/0000777000000000000000000000000012521166655021126 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/groups/ratchet/senderchainkey.py0000777000000000000000000000163612455652631024505 0ustar rootroot00000000000000from .sendermessagekey import SenderMessageKey import hashlib import hmac class SenderChainKey: MESSAGE_KEY_SEED = bytearray([0x01]) CHAIN_KEY_SEED = bytearray([0x02]) def __init__(self, iteration, chainKey): """ :type iteration: int :type chainKey: bytearray """ self.iteration = iteration self.chainKey = chainKey def getIteration(self): return self.iteration def getSenderMessageKey(self): return SenderMessageKey(self.iteration, self.getDerivative(self.__class__.MESSAGE_KEY_SEED, self.chainKey)) def getNext(self): return SenderChainKey(self.iteration + 1, self.getDerivative(self.__class__.CHAIN_KEY_SEED, self.chainKey)) def getSeed(self): return self.chainKey def getDerivative(self, seed, key): mac = hmac.new(bytes(key), bytes(seed), digestmod = hashlib.sha256) return mac.digest() python-axolotl-0.1.7/axolotl/groups/ratchet/sendermessagekey.py0000777000000000000000000000125612453411143025032 0ustar rootroot00000000000000from axolotl.kdf.hkdfv3 import HKDFv3 from axolotl.util.byteutil import ByteUtil class SenderMessageKey: def __init__(self, iteration, seed): """ :type iteration: int :type seed: bytearray """ derivative = HKDFv3().deriveSecrets(seed, "WhisperGroup".encode(), 48) parts = ByteUtil.split(derivative, 16, 32) self.iteration = iteration self.seed = seed self.iv = parts[0] self.cipherKey = parts[1] def getIteration(self): return self.iteration def getIv(self): return self.iv def getCipherKey(self): return self.iv def getSeed(self): return self.seed python-axolotl-0.1.7/axolotl/groups/ratchet/__init__.py0000777000000000000000000000000012454325147023226 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/groups/state/0000777000000000000000000000000012521166655020614 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/groups/state/senderkeyrecord.py0000777000000000000000000000374412454073464024371 0ustar rootroot00000000000000from axolotl.state.storageprotos import SenderKeyRecordStructure from axolotl.groups.state.senderkeystate import SenderKeyState from axolotl.invalidkeyidexception import InvalidKeyIdException class SenderKeyRecord: def __init__(self, serialized = None): self.senderKeyStates = [] if serialized: senderKeyRecordStructure = SenderKeyRecordStructure() senderKeyRecordStructure.ParseFromString(serialized) for structure in senderKeyRecordStructure.senderKeyStates: self.senderKeyStates.append(SenderKeyState(senderKeyStateStructure=structure)) def getSenderKeyState(self, keyId = None): if keyId is None: if len(self.senderKeyStates): return self.senderKeyStates[0] else: raise InvalidKeyIdException("No key state in record") else: for state in self.senderKeyStates: if state.getKeyId() == keyId: return state raise InvalidKeyIdException("No keys for: %s" % keyId) def addSenderKeyState(self, id, iteration, chainKey, signatureKey): """ :type id: int :type iteration: int :type chainKey: bytearray :type signatureKey: ECPublicKey """ self.senderKeyStates.append(SenderKeyState(id, iteration, chainKey, signatureKey)) def setSenderKeyState(self, id, iteration, chainKey, signatureKey): """ :type id: int :type iteration: int :type chainKey: bytearray :type signatureKey: ECKeyPair """ del self.senderKeyStates[:] self.senderKeyStates.append(SenderKeyState(id, iteration, chainKey, signatureKeyPair=signatureKey)) def serialize(self): recordStructure = SenderKeyRecordStructure() for senderKeyState in self.senderKeyStates: recordStructure.senderKeyStates.extend([senderKeyState.getStructure()]) return recordStructure.SerializeToString() python-axolotl-0.1.7/axolotl/groups/state/senderkeystate.py0000777000000000000000000000751712454307706024234 0ustar rootroot00000000000000from axolotl.state import storageprotos from axolotl.groups.ratchet.senderchainkey import SenderChainKey from axolotl.groups.ratchet.sendermessagekey import SenderMessageKey from axolotl.ecc.curve import Curve class SenderKeyState: def __init__(self, id = None, iteration = None, chainKey = None, signatureKeyPublic = None, signatureKeyPrivate = None , signatureKeyPair = None, senderKeyStateStructure = None): """ :type id: int :type iteration: int :type chainKey: bytearray :type signatureKeyPublic: ECPublicKey :type signatureKeyPrivate: ECPrivateKey :type signatureKeyPair: ECKeyPair :type senderKeyStateStructure: SenderKeyStateStructure """ assert (bool(id) and bool(iteration) and bool(chainKey)) or \ (bool(senderKeyStateStructure) ^ bool(signatureKeyPublic or signatureKeyPair)) or \ (bool(signatureKeyPublic) ^ bool(signatureKeyPair)), "Missing required arguments" if senderKeyStateStructure: self.senderKeyStateStructure = senderKeyStateStructure else: if signatureKeyPair: signatureKeyPublic = signatureKeyPair.getPublicKey() signatureKeyPrivate = signatureKeyPair.getPrivateKey() self.senderKeyStateStructure = storageprotos.SenderKeyStateStructure() senderChainKeyStructure = self.senderKeyStateStructure.SenderChainKey() senderChainKeyStructure.iteration = iteration senderChainKeyStructure.seed = chainKey signingKeyStructure = self.senderKeyStateStructure.SenderSigningKey() signingKeyStructure.public = signatureKeyPublic.serialize() if signatureKeyPrivate: signingKeyStructure.private = signatureKeyPrivate.serialize() self.senderKeyStateStructure.senderKeyId = id self.senderChainKey = senderChainKeyStructure self.senderKeyStateStructure.senderSigningKey.CopyFrom(signingKeyStructure) def getKeyId(self): return self.senderKeyStateStructure.senderKeyId def getSenderChainKey(self): return SenderChainKey(self.senderKeyStateStructure.senderChainKey.iteration, bytearray(self.senderKeyStateStructure.senderChainKey.seed)) def setSenderChainKey(self, chainKey): self.senderKeyStateStructure.senderChainKey.iteration = chainKey.getIteration() self.senderKeyStateStructure.senderChainKey.seed = chainKey.getSeed() def getSigningKeyPublic(self): return Curve.decodePoint(bytearray(self.senderKeyStateStructure.senderSigningKey.public), 0) def getSigningKeyPrivate(self): return Curve.decodePrivatePoint(self.senderKeyStateStructure.senderSigningKey.private) def hasSenderMessageKey(self, iteration): for senderMessageKey in self.senderKeyStateStructure.senderMessageKeys: if senderMessageKey.iteration == iteration: return True return False def addSenderMessageKey(self, senderMessageKey): smk = self.senderKeyStateStructure.SenderMessageKey() smk.iteration = senderMessageKey.iteration smk.seed = senderMessageKey.seed self.senderKeyStateStructure.senderMessageKeys.extend([smk]) def removeSenderMessageKey(self, iteration): keys = self.senderKeyStateStructure.senderMessageKeys result = None for i in range(0, len(keys)): senderMessageKey = keys[i] if senderMessageKey.iteration == iteration: result = senderMessageKey del keys[i] break if result is not None: return SenderMessageKey(result.iteration, bytearray(result.seed)) return None def getStructure(self): return self.senderKeyStateStructure python-axolotl-0.1.7/axolotl/groups/state/senderkeystore.py0000777000000000000000000000057512453422112024231 0ustar rootroot00000000000000import abc class SenderKeyStore(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def storeSenderKey(self, senderKeyId, senderKeyRecord): """ :type senderKeyId: str :type senderKeyRecord: SenderKeyRecord """ @abc.abstractmethod def loadSenderKey(self, senderKeyId): """ :type senderKeyId: str """python-axolotl-0.1.7/axolotl/groups/state/__init__.py0000777000000000000000000000000012454325147022714 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/groups/__init__.py0000777000000000000000000000000012454325147021574 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/identitykey.py0000777000000000000000000000114412447767026021102 0ustar rootroot00000000000000from .ecc.curve import Curve class IdentityKey: def __init__(self, ecPubKeyOrBytes, offset = None): if offset is None: self.publicKey = ecPubKeyOrBytes else: self.publicKey = Curve.decodePoint(bytearray(ecPubKeyOrBytes), offset) def getPublicKey(self): return self.publicKey def serialize(self): return self.publicKey.serialize() def get_fingerprint(self): raise Exception("IMPL ME") def __eq__(self, other): return self.publicKey == other.getPublicKey() def hashCode(self): raise Exception("IMPL ME") python-axolotl-0.1.7/axolotl/identitykeypair.py0000777000000000000000000000174512454325154021753 0ustar rootroot00000000000000from .state.storageprotos import IdentityKeyPairStructure from .identitykey import IdentityKey from .ecc.curve import Curve class IdentityKeyPair: def __init__(self, identityKeyPublicKey = None, ecPrivateKey = None, serialized = None): if serialized: structure = IdentityKeyPairStructure() structure.ParseFromString(serialized) self.publicKey = IdentityKey(bytearray(structure.publicKey), offset = 0) self.privateKey = Curve.decodePrivatePoint(bytearray(structure.privateKey)) else: self.publicKey = identityKeyPublicKey self.privateKey = ecPrivateKey def getPublicKey(self): return self.publicKey def getPrivateKey(self): return self.privateKey def serialize(self): structure = IdentityKeyPairStructure() structure.publicKey = self.publicKey.serialize() structure.privateKey = self.privateKey.serialize() return structure.SerializeToString()python-axolotl-0.1.7/axolotl/invalidkeyexception.py0000777000000000000000000000005612447253257022613 0ustar rootroot00000000000000class InvalidKeyException(Exception): passpython-axolotl-0.1.7/axolotl/invalidkeyidexception.py0000777000000000000000000000006012447320734023116 0ustar rootroot00000000000000class InvalidKeyIdException(Exception): passpython-axolotl-0.1.7/axolotl/invalidmessageexception.py0000777000000000000000000000035012447323654023443 0ustar rootroot00000000000000class InvalidMessageException(Exception): def __init__(self, message, exceptions = None): if exceptions: message = message + "%s" % exceptions[0] super(InvalidMessageException, self).__init__(message)python-axolotl-0.1.7/axolotl/invalidversionexception.py0000777000000000000000000000006212447254750023504 0ustar rootroot00000000000000class InvalidVersionException(Exception): passpython-axolotl-0.1.7/axolotl/kdf/0000777000000000000000000000000012521166655016721 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/kdf/derivedmessagesecrets.py0000777000000000000000000000115412445634540023655 0ustar rootroot00000000000000from ..util.byteutil import ByteUtil class DerivedMessageSecrets: SIZE = 80 CIPHER_KEY_LENGTH = 32 MAC_KEY_LENGTH = 32 IV_LENGTH = 16 def __init__(self, okm): keys = ByteUtil.split(okm, self.__class__.CIPHER_KEY_LENGTH, self.__class__.MAC_KEY_LENGTH, self.__class__.IV_LENGTH) self.cipherKey = keys[0] #AES self.macKey = keys[1] #sha256 self.iv = keys[2] def getCipherKey(self): return self.cipherKey def getMacKey(self): return self.macKey def getIv(self): return self.iv python-axolotl-0.1.7/axolotl/kdf/derivedrootsecrets.py0000777000000000000000000000050412445444064023212 0ustar rootroot00000000000000from ..util.byteutil import ByteUtil class DerivedRootSecrets: SIZE = 64 def __init__(self, okm): keys = ByteUtil.split(okm, 32, 32) self.rootKey = keys[0] self.chainKey = keys[1] def getRootKey(self): return self.rootKey def getChainKey(self): return self.chainKey python-axolotl-0.1.7/axolotl/kdf/hkdf.py0000777000000000000000000000340212455652532020211 0ustar rootroot00000000000000import abc import hmac import hashlib import math class HKDF(object): __metaclass__ = abc.ABCMeta HASH_OUTPUT_SIZE = 32 @staticmethod def createFor(messageVersion): from . import hkdfv2, hkdfv3 if messageVersion == 2: return hkdfv2.HKDFv2() elif messageVersion == 3: return hkdfv3.HKDFv3() else: raise AssertionError("Unknown version: %s " % messageVersion) def deriveSecrets(self, inputKeyMaterial, info, outputLength, salt = None): salt = salt or bytearray(self.__class__.HASH_OUTPUT_SIZE) prk = self.extract(salt, inputKeyMaterial) return self.expand(prk, info, outputLength) def extract(self, salt, inputKeyMaterial): mac = hmac.new(bytes(salt), digestmod=hashlib.sha256) mac.update(bytes(inputKeyMaterial)) return mac.digest() def expand(self, prk, info, outputSize): iterations = int(math.ceil(float(outputSize)/ float(self.__class__.HASH_OUTPUT_SIZE))) mixin = bytearray() results = bytearray() remainingBytes = outputSize for i in range(self.getIterationStartOffset(), iterations + self.getIterationStartOffset()): mac = hmac.new(prk, digestmod=hashlib.sha256) mac.update(bytes(mixin)) if info is not None: mac.update(bytes(info)) updateChr = chr(i % 256) mac.update(updateChr.encode()) stepResult = mac.digest() stepSize = min(remainingBytes, len(stepResult)) results.extend(stepResult[:stepSize]) mixin = stepResult remainingBytes -= stepSize return bytes(results) @abc.abstractmethod def getIterationStartOffset(self): return 0 python-axolotl-0.1.7/axolotl/kdf/hkdfv2.py0000777000000000000000000000014312450005125020441 0ustar rootroot00000000000000from . import hkdf class HKDFv2(hkdf.HKDF): def getIterationStartOffset(self): return 0python-axolotl-0.1.7/axolotl/kdf/hkdfv3.py0000777000000000000000000000014312450005141020440 0ustar rootroot00000000000000from .hkdf import HKDF class HKDFv3(HKDF): def getIterationStartOffset(self): return 1python-axolotl-0.1.7/axolotl/kdf/messagekeys.py0000777000000000000000000000062212445445675021625 0ustar rootroot00000000000000class MessageKeys: def __init__(self, cipherKey, macKey, iv, counter): self.cipherKey = cipherKey self.macKey = macKey self.iv = iv self.counter = counter def getCipherKey(self): return self.cipherKey def getMacKey(self): return self.macKey def getIv(self): return self.iv def getCounter(self): return self.counterpython-axolotl-0.1.7/axolotl/kdf/__init__.py0000777000000000000000000000002512454325154021026 0ustar rootroot00000000000000__author__ = 'tarek' python-axolotl-0.1.7/axolotl/legacymessageexception.py0000777000000000000000000000006112447255154023257 0ustar rootroot00000000000000class LegacyMessageException(Exception): passpython-axolotl-0.1.7/axolotl/nosessionexception.py0000777000000000000000000000005512447321557022472 0ustar rootroot00000000000000class NoSessionException(Exception): passpython-axolotl-0.1.7/axolotl/protocol/0000777000000000000000000000000012521166655020016 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/protocol/ciphertextmessage.py0000777000000000000000000000104312446173525024115 0ustar rootroot00000000000000import abc class CiphertextMessage(object): __metaclass__ = abc.ABCMeta UNSUPPORTED_VERSION = 1 CURRENT_VERSION = 3 WHISPER_TYPE = 2 PREKEY_TYPE = 3 SENDERKEY_TYPE = 4 SENDERKEY_DISTRIBUTION_TYPE = 5 #This should be the worst case (worse than V2). So not always accurate, but good enough for padding. ENCRYPTED_MESSAGE_OVERHEAD = 53 @abc.abstractmethod def serialize(self): return @abc.abstractmethod def getType(self): returnpython-axolotl-0.1.7/axolotl/protocol/keyexchangemessage.py0000777000000000000000000001115212450010556024220 0ustar rootroot00000000000000from .ciphertextmessage import CiphertextMessage from axolotl.util.byteutil import ByteUtil from axolotl.protocol import whisperprotos from axolotl.legacymessageexception import LegacyMessageException from axolotl.invalidversionexception import InvalidVersionException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.invalidkeyexception import InvalidKeyException from axolotl.ecc.curve import Curve from axolotl.identitykey import IdentityKey class KeyExchangeMessage: INITIATE_FLAG = 0x01 RESPONSE_FLAG = 0X02 SIMULTAENOUS_INITIATE_FLAG = 0x04 def __init__(self, messageVersion = None, sequence = None, flags=None, baseKey = None, baseKeySignature = None, ratchetKey = None, identityKey = None, serialized = None): """ :type messageVersion: int :type sequence: int :type flags:int :type baseKey: ECPublicKey :type baseKeySignature: bytearray :type ratchetKey: ECPublicKey :type identityKey: IdentityKey :type serialized: bytearray """ if serialized: try: parts = ByteUtil.split(serialized, 1, len(serialized)- 1) self.version = ByteUtil.highBitsToInt(parts[0][0]) self.supportedVersion = ByteUtil.lowBitsToInt(parts[0][0]) if self.version <= CiphertextMessage.UNSUPPORTED_VERSION: raise LegacyMessageException("Unsupportmessageed legacy version: %s" % self.version) if self.version > CiphertextMessage.CURRENT_VERSION: raise InvalidVersionException("Unkown version: %s" % self.version) message = whisperprotos.KeyExchangeMessage() message.ParseFromString(bytes(parts[1])) if not message.HasField("id") or not message.HasField("baseKey")\ or not message.HasField("ratchetKey") or not message.HasField("identityKey")\ or (self.version >= 3 and not message.HasField("baseKeySignature")): raise InvalidMessageException("Some required fields are missing!") self.sequence = message.id >> 5 self.flags = message.id & 0x1f self.serialized = serialized self.baseKey = Curve.decodePoint(bytearray(message.baseKey), 0) self.baseKeySignature = message.baseKeySignature self.ratchetKey = Curve.decodePoint(bytearray(message.ratchetKey), 0) self.identityKey = IdentityKey(message.identityKey, 0) except InvalidKeyException as e: raise InvalidMessageException(e) else: self.supportedVersion = CiphertextMessage.CURRENT_VERSION self.version = messageVersion self.sequence = sequence self.flags = flags self.baseKey = baseKey self.baseKeySignature = baseKeySignature self.ratchetKey = ratchetKey self.identityKey = identityKey version = [ByteUtil.intsToByteHighAndLow(self.version, self.supportedVersion)] keyExchangeMessage = whisperprotos.KeyExchangeMessage() keyExchangeMessage.id = (self.sequence << 5) | self.flags keyExchangeMessage.baseKey = baseKey.serialize() keyExchangeMessage.ratchetKey = ratchetKey.serialize() keyExchangeMessage.identityKey = identityKey.serialize() if messageVersion >= 3: keyExchangeMessage.baseKeySignature = baseKeySignature self.serialized = ByteUtil.combine(version, keyExchangeMessage.SerializeToString()) def getVersion(self): return self.version def getBaseKey(self): return self.baseKey def getBaseKeySignature(self): return self.baseKeySignature def getRatchetKey(self): return self.ratchetKey def getIdentityKey(self): return self.identityKey def hasIdentityKey(self): return True def getMaxVersion(self): return self.supportedVersion def isResponse(self): return ((self.flags & self.__class__.RESPONSE_FLAG) != 0) def isInitiate(self): return (self.flags & self.__class__.INITIATE_FLAG) != 0 def isResponseForSimultaneousInitiate(self): return (self.flags & self.__class__.SIMULTAENOUS_INITIATE_FLAG) != 0 def getFlags(self): return self.flags def getSequence(self): return self.sequence def serialize(self): return self.serialized python-axolotl-0.1.7/axolotl/protocol/prekeywhispermessage.py0000777000000000000000000000754012450124242024632 0ustar rootroot00000000000000from .ciphertextmessage import CiphertextMessage from ..util.byteutil import ByteUtil from ..ecc.curve import Curve from ..identitykey import IdentityKey from .whispermessage import WhisperMessage from axolotl.invalidversionexception import InvalidVersionException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.legacymessageexception import LegacyMessageException from axolotl.invalidkeyexception import InvalidKeyException from google.protobuf.message import DecodeError from . import whisperprotos class PreKeyWhisperMessage(CiphertextMessage): def __init__(self, messageVersion = None, registrationId = None, preKeyId = None, signedPreKeyId = None, ecPublicBaseKey = None, identityKey = None, whisperMessage = None, serialized = None): if serialized: try: self.version = ByteUtil.highBitsToInt(serialized[0]) if self.version > CiphertextMessage.CURRENT_VERSION: raise InvalidVersionException("Unknown version %s" % self.version) preKeyWhisperMessage = whisperprotos.PreKeyWhisperMessage() preKeyWhisperMessage.ParseFromString(serialized[1:]) if (self.version == 2 and preKeyWhisperMessage.preKeyId is None) or\ (self.version == 3 and preKeyWhisperMessage.signedPreKeyId is None) or\ not preKeyWhisperMessage.baseKey or\ not preKeyWhisperMessage.identityKey or \ not preKeyWhisperMessage.message: raise InvalidMessageException("Incomplete message") self.serialized = serialized self.registrationId = preKeyWhisperMessage.registrationId self.preKeyId = preKeyWhisperMessage.preKeyId self.signedPreKeyId = preKeyWhisperMessage.signedPreKeyId if preKeyWhisperMessage.signedPreKeyId is not None else -1 self.baseKey = Curve.decodePoint(bytearray(preKeyWhisperMessage.baseKey), 0) self.identityKey = IdentityKey(Curve.decodePoint(bytearray(preKeyWhisperMessage.identityKey), 0)) self.message = WhisperMessage(serialized = preKeyWhisperMessage.message) except (InvalidKeyException, LegacyMessageException, DecodeError) as e: raise InvalidMessageException(e) else: self.version = messageVersion self.registrationId = registrationId self.preKeyId = preKeyId self.signedPreKeyId = signedPreKeyId self.baseKey = ecPublicBaseKey self.identityKey = identityKey self.message = whisperMessage builder = whisperprotos.PreKeyWhisperMessage() builder.signedPreKeyId = signedPreKeyId builder.baseKey = ecPublicBaseKey.serialize() builder.identityKey = identityKey.serialize() builder.message = whisperMessage.serialize() builder.registrationId = registrationId if preKeyId is not None: builder.preKeyId = preKeyId versionBytes = ByteUtil.intsToByteHighAndLow(self.version, self.__class__.CURRENT_VERSION) messageBytes = builder.SerializeToString() self.serialized = bytes(ByteUtil.combine(versionBytes, messageBytes)) def getMessageVersion(self): return self.version def getIdentityKey(self): return self.identityKey def getRegistrationId(self): return self.registrationId def getPreKeyId(self): return self.preKeyId def getSignedPreKeyId(self): return self.signedPreKeyId def getBaseKey(self): return self.baseKey def getWhisperMessage(self): return self.message def serialize(self): return self.serialized def getType(self): return CiphertextMessage.PREKEY_TYPE python-axolotl-0.1.7/axolotl/protocol/senderkeydistributionmessage.py0000777000000000000000000000210612454065307026365 0ustar rootroot00000000000000from .ciphertextmessage import CiphertextMessage from . import whisperprotos class SenderKeyDistributionMessage(CiphertextMessage): def __init__(self, id, iteration, chainKey, signatureKey): """ :type id: int :type iteration: int :type chainKey: bytearray :type signatureKey: ECPublicKey """ self.id = id self.iteration = iteration self.chainKey = chainKey self.signatureKey = signatureKey self.serialized = whisperprotos.SenderKeyDistributionMessage() self.serialized.id = id self.serialized.iteration = iteration self.serialized.chainKey= chainKey self.serialized.signingKey = signatureKey.serialize() def serialize(self): return self.serialized def getType(self): return self.__class__.SENDERKEY_DISTRIBUTION_TYPE def getIteration(self): return self.iteration def getChainKey(self): return self.chainKey def getSignatureKey(self): return self.signatureKey def getId(self): return self.id python-axolotl-0.1.7/axolotl/protocol/senderkeymessage.py0000777000000000000000000000774612454114444023741 0ustar rootroot00000000000000from .ciphertextmessage import CiphertextMessage from axolotl.util.byteutil import ByteUtil from axolotl.legacymessageexception import LegacyMessageException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.invalidkeyexception import InvalidKeyException from axolotl.ecc.curve import Curve from . import whisperprotos class SenderKeyMessage(CiphertextMessage): SIGNATURE_LENGTH = 64 def __init__(self, keyId = None, iteration = None, ciphertext = None, signatureKey = None, serialized = None): assert bool(keyId is not None and iteration is not None and ciphertext is not None and signatureKey is not None)\ ^ bool(serialized),\ "Either pass arguments or serialized data" if serialized: try: messageParts = ByteUtil.split(serialized, 1, len(serialized)- 1 - self.__class__.SIGNATURE_LENGTH, self.__class__.SIGNATURE_LENGTH) version = messageParts[0][0] message = messageParts[1] signature = messageParts[2] if ByteUtil.highBitsToInt(version) < 3: raise LegacyMessageException("Legacy message: %s" % ByteUtil.highBitsToInt(version)) if ByteUtil.highBitsToInt(version) > self.__class__.CURRENT_VERSION: raise InvalidMessageException("Unknown version: %s" % ByteUtil.highBitsToInt(version)) senderKeyMessage = whisperprotos.SenderKeyMessage() senderKeyMessage.ParseFromString(message) if senderKeyMessage.id is None or senderKeyMessage.iteration is None\ or senderKeyMessage.ciphertext is None: raise InvalidMessageException("Incomplete message") self.serialized = serialized self.messageVersion = ByteUtil.highBitsToInt(version) self.keyId = senderKeyMessage.id self.iteration = senderKeyMessage.iteration self.ciphertext = senderKeyMessage.ciphertext except Exception as e: raise InvalidMessageException(e) else: version = [ByteUtil.intsToByteHighAndLow(self.__class__.CURRENT_VERSION, self.__class__.CURRENT_VERSION)] message = whisperprotos.SenderKeyMessage() message.id = keyId message.iteration = iteration message.ciphertext = ciphertext message = message.SerializeToString() signature = self.getSignature(signatureKey, bytes(ByteUtil.combine(version, message))) self.serialized = ByteUtil.combine(version, message, signature) self.messageVersion = self.__class__.CURRENT_VERSION self.keyId = keyId self.iteration = iteration self.ciphertext = ciphertext def getKeyId(self): return self.keyId def getIteration(self): return self.iteration def getCipherText(self): return self.ciphertext def verifySignature(self, signatureKey): """ :type signatureKey: ECPublicKey """ try: parts = ByteUtil.split(self.serialized, len(self.serialized)- self.__class__.SIGNATURE_LENGTH, self.__class__.SIGNATURE_LENGTH) if not Curve.verifySignature(signatureKey, parts[0], parts[1]): raise InvalidMessageException("Invalid signature!") except InvalidKeyException as e: raise InvalidMessageException(e) def getSignature(self, signatureKey, serialized): """ :type signatureKey: ECPirvateKey :type serialized: bytearray """ try: return Curve.calculateSignature(signatureKey, serialized) except InvalidKeyException as e: raise AssertionError(e) def serialize(self): return self.serialized def getType(self): return CiphertextMessage.SENDERKEY_TYPE python-axolotl-0.1.7/axolotl/protocol/whispermessage.py0000777000000000000000000001121412455652567023430 0ustar rootroot00000000000000from .ciphertextmessage import CiphertextMessage from ..util.byteutil import ByteUtil from ..ecc.curve import Curve from . import whisperprotos import hmac import hashlib from axolotl.legacymessageexception import LegacyMessageException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.invalidkeyexception import InvalidKeyException class WhisperMessage(CiphertextMessage): MAC_LENGTH = 8 def __init__(self, messageVersion = None, macKey = None, ECPublicKey_senderRatchetKey = None, counter = None, previousCounter = None, ciphertext = None, senderIdentityKey = None, receiverIdentityKey = None, serialized = None): self.serialized = "" if serialized: try: assert type(serialized) in (str, bytes), "Expected serialized %s, got %s" % (str, type(serialized)) messageParts = ByteUtil.split(serialized, 1, len(serialized) - 1 - WhisperMessage.MAC_LENGTH, WhisperMessage.MAC_LENGTH) version = messageParts[0][0] message = messageParts[1] mac = messageParts[2] if ByteUtil.highBitsToInt(version) <= self.__class__.UNSUPPORTED_VERSION: raise LegacyMessageException("Legacy message %s" % ByteUtil.highBitsToInt(version)) if ByteUtil.highBitsToInt(version) > self.__class__.CURRENT_VERSION: raise InvalidMessageException("Unknown version: %s" % ByteUtil.highBitsToInt(version)) whisperMessage = whisperprotos.WhisperMessage() whisperMessage.ParseFromString(message) if not whisperMessage.ciphertext or whisperMessage.counter is None or not whisperMessage.ratchetKey: raise InvalidMessageException("Incomplete message") self.serialized = serialized self.senderRatchetKey = Curve.decodePoint(bytearray(whisperMessage.ratchetKey), 0) self.messageVersion = ByteUtil.highBitsToInt(version) self.counter = whisperMessage.counter self.previousCounter = whisperMessage.previousCounter self.ciphertext = whisperMessage.ciphertext except InvalidKeyException as e: raise InvalidMessageException(e) else: version = ByteUtil.intsToByteHighAndLow(messageVersion, self.__class__.CURRENT_VERSION) message = whisperprotos.WhisperMessage() message.ratchetKey = ECPublicKey_senderRatchetKey.serialize() message.counter = counter message.previousCounter = previousCounter message.ciphertext = ciphertext message = message.SerializeToString() mac = self.getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey, ByteUtil.combine(version, message)) self.serialized = bytes(ByteUtil.combine(version, message, mac)) self.senderRatchetKey = ECPublicKey_senderRatchetKey self.counter = counter self.previousCounter = previousCounter self.ciphertext = ciphertext self.messageVersion = messageVersion def getSenderRatchetKey(self): return self.senderRatchetKey def getMessageVersion(self): return self.messageVersion def getCounter(self): return self.counter def getBody(self): return self.ciphertext def verifyMac(self, messageVersion, senderIdentityKey, receiverIdentityKey, macKey): parts = ByteUtil.split(self.serialized, len(self.serialized) - self.__class__.MAC_LENGTH, self.__class__.MAC_LENGTH) ourMac = self.getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey, parts[0]) theirMac = parts[1] if ourMac != theirMac: raise InvalidMessageException("Bad Mac!") def getMac(self, messageVersion, senderIdentityKey, receiverIdentityKey, macKey, serialized): mac = hmac.new(macKey, digestmod=hashlib.sha256) if messageVersion >= 3: mac.update(senderIdentityKey.getPublicKey().serialize()) mac.update(receiverIdentityKey.getPublicKey().serialize()) mac.update(bytes(serialized)) fullMac = mac.digest() return ByteUtil.trim(fullMac, self.__class__.MAC_LENGTH) def serialize(self): return self.serialized def getType(self): return CiphertextMessage.WHISPER_TYPE def isLegacy(self, message): return message is not None and len(message) >= 1 and ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION python-axolotl-0.1.7/axolotl/protocol/whisperprotos.py0000777000000000000000000003252112447773173023334 0ustar rootroot00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: WhisperTextProtocol.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='WhisperTextProtocol.proto', package='textsecure', serialized_pb=_b('\n\x19WhisperTextProtocol.proto\x12\ntextsecure\"b\n\x0eWhisperMessage\x12\x12\n\nratchetKey\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63ounter\x18\x02 \x01(\r\x12\x17\n\x0fpreviousCounter\x18\x03 \x01(\r\x12\x12\n\nciphertext\x18\x04 \x01(\x0c\"\x8f\x01\n\x14PreKeyWhisperMessage\x12\x16\n\x0eregistrationId\x18\x05 \x01(\r\x12\x10\n\x08preKeyId\x18\x01 \x01(\r\x12\x16\n\x0esignedPreKeyId\x18\x06 \x01(\r\x12\x0f\n\x07\x62\x61seKey\x18\x02 \x01(\x0c\x12\x13\n\x0bidentityKey\x18\x03 \x01(\x0c\x12\x0f\n\x07message\x18\x04 \x01(\x0c\"t\n\x12KeyExchangeMessage\x12\n\n\x02id\x18\x01 \x01(\r\x12\x0f\n\x07\x62\x61seKey\x18\x02 \x01(\x0c\x12\x12\n\nratchetKey\x18\x03 \x01(\x0c\x12\x13\n\x0bidentityKey\x18\x04 \x01(\x0c\x12\x18\n\x10\x62\x61seKeySignature\x18\x05 \x01(\x0c\"E\n\x10SenderKeyMessage\x12\n\n\x02id\x18\x01 \x01(\r\x12\x11\n\titeration\x18\x02 \x01(\r\x12\x12\n\nciphertext\x18\x03 \x01(\x0c\"c\n\x1cSenderKeyDistributionMessage\x12\n\n\x02id\x18\x01 \x01(\r\x12\x11\n\titeration\x18\x02 \x01(\r\x12\x10\n\x08\x63hainKey\x18\x03 \x01(\x0c\x12\x12\n\nsigningKey\x18\x04 \x01(\x0c\x42\x37\n&org.whispersystems.libaxolotl.protocolB\rWhisperProtos') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) _WHISPERMESSAGE = _descriptor.Descriptor( name='WhisperMessage', full_name='textsecure.WhisperMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='ratchetKey', full_name='textsecure.WhisperMessage.ratchetKey', index=0, number=1, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='counter', full_name='textsecure.WhisperMessage.counter', index=1, number=2, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='previousCounter', full_name='textsecure.WhisperMessage.previousCounter', index=2, number=3, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='ciphertext', full_name='textsecure.WhisperMessage.ciphertext', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=41, serialized_end=139, ) _PREKEYWHISPERMESSAGE = _descriptor.Descriptor( name='PreKeyWhisperMessage', full_name='textsecure.PreKeyWhisperMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='registrationId', full_name='textsecure.PreKeyWhisperMessage.registrationId', index=0, number=5, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='preKeyId', full_name='textsecure.PreKeyWhisperMessage.preKeyId', index=1, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='signedPreKeyId', full_name='textsecure.PreKeyWhisperMessage.signedPreKeyId', index=2, number=6, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='baseKey', full_name='textsecure.PreKeyWhisperMessage.baseKey', index=3, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='identityKey', full_name='textsecure.PreKeyWhisperMessage.identityKey', index=4, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='message', full_name='textsecure.PreKeyWhisperMessage.message', index=5, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=142, serialized_end=285, ) _KEYEXCHANGEMESSAGE = _descriptor.Descriptor( name='KeyExchangeMessage', full_name='textsecure.KeyExchangeMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='id', full_name='textsecure.KeyExchangeMessage.id', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='baseKey', full_name='textsecure.KeyExchangeMessage.baseKey', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='ratchetKey', full_name='textsecure.KeyExchangeMessage.ratchetKey', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='identityKey', full_name='textsecure.KeyExchangeMessage.identityKey', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='baseKeySignature', full_name='textsecure.KeyExchangeMessage.baseKeySignature', index=4, number=5, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=287, serialized_end=403, ) _SENDERKEYMESSAGE = _descriptor.Descriptor( name='SenderKeyMessage', full_name='textsecure.SenderKeyMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='id', full_name='textsecure.SenderKeyMessage.id', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='iteration', full_name='textsecure.SenderKeyMessage.iteration', index=1, number=2, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='ciphertext', full_name='textsecure.SenderKeyMessage.ciphertext', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=405, serialized_end=474, ) _SENDERKEYDISTRIBUTIONMESSAGE = _descriptor.Descriptor( name='SenderKeyDistributionMessage', full_name='textsecure.SenderKeyDistributionMessage', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='id', full_name='textsecure.SenderKeyDistributionMessage.id', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='iteration', full_name='textsecure.SenderKeyDistributionMessage.iteration', index=1, number=2, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='chainKey', full_name='textsecure.SenderKeyDistributionMessage.chainKey', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='signingKey', full_name='textsecure.SenderKeyDistributionMessage.signingKey', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=476, serialized_end=575, ) DESCRIPTOR.message_types_by_name['WhisperMessage'] = _WHISPERMESSAGE DESCRIPTOR.message_types_by_name['PreKeyWhisperMessage'] = _PREKEYWHISPERMESSAGE DESCRIPTOR.message_types_by_name['KeyExchangeMessage'] = _KEYEXCHANGEMESSAGE DESCRIPTOR.message_types_by_name['SenderKeyMessage'] = _SENDERKEYMESSAGE DESCRIPTOR.message_types_by_name['SenderKeyDistributionMessage'] = _SENDERKEYDISTRIBUTIONMESSAGE WhisperMessage = _reflection.GeneratedProtocolMessageType('WhisperMessage', (_message.Message,), dict( DESCRIPTOR = _WHISPERMESSAGE, __module__ = 'WhisperTextProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.WhisperMessage) )) _sym_db.RegisterMessage(WhisperMessage) PreKeyWhisperMessage = _reflection.GeneratedProtocolMessageType('PreKeyWhisperMessage', (_message.Message,), dict( DESCRIPTOR = _PREKEYWHISPERMESSAGE, __module__ = 'WhisperTextProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.PreKeyWhisperMessage) )) _sym_db.RegisterMessage(PreKeyWhisperMessage) KeyExchangeMessage = _reflection.GeneratedProtocolMessageType('KeyExchangeMessage', (_message.Message,), dict( DESCRIPTOR = _KEYEXCHANGEMESSAGE, __module__ = 'WhisperTextProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.KeyExchangeMessage) )) _sym_db.RegisterMessage(KeyExchangeMessage) SenderKeyMessage = _reflection.GeneratedProtocolMessageType('SenderKeyMessage', (_message.Message,), dict( DESCRIPTOR = _SENDERKEYMESSAGE, __module__ = 'WhisperTextProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyMessage) )) _sym_db.RegisterMessage(SenderKeyMessage) SenderKeyDistributionMessage = _reflection.GeneratedProtocolMessageType('SenderKeyDistributionMessage', (_message.Message,), dict( DESCRIPTOR = _SENDERKEYDISTRIBUTIONMESSAGE, __module__ = 'WhisperTextProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyDistributionMessage) )) _sym_db.RegisterMessage(SenderKeyDistributionMessage) DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n&org.whispersystems.libaxolotl.protocolB\rWhisperProtos')) # @@protoc_insertion_point(module_scope) python-axolotl-0.1.7/axolotl/protocol/__init__.py0000777000000000000000000000002512454325147022125 0ustar rootroot00000000000000__author__ = 'tarek' python-axolotl-0.1.7/axolotl/ratchet/0000777000000000000000000000000012521166655017607 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/ratchet/aliceaxolotlparameters.py0000777000000000000000000000540012447400277024725 0ustar rootroot00000000000000class AliceAxolotlParameters: def __init__(self,ourIdentityKey, ourBaseKey, theirIdentityKey, theirSignedPreKey, theirRatchetKey, theirOneTimePreKey): """ :type ourBaseKey: ECKeyPair :type theirSignedPreKey: ECKeyPair :type ourIdentityKey: IdentityKeyPair :type theirOneTimePreKey: ECPublicKey :type theirRatchetKey: ECKeyPair :type theirIdentityKey: IdentityKey """ self.ourBaseKey = ourBaseKey self.ourIdentityKey = ourIdentityKey self.theirSignedPreKey = theirSignedPreKey self.theirRatchetKey = theirRatchetKey self.theirIdentityKey = theirIdentityKey self.theirOneTimePreKey = theirOneTimePreKey if ourBaseKey is None or ourIdentityKey is None or theirSignedPreKey is None\ or theirRatchetKey is None or theirIdentityKey is None or theirSignedPreKey is None: raise ValueError("Null value!") def getOurIdentityKey(self): return self.ourIdentityKey def getOurBaseKey(self): return self.ourBaseKey def getTheirIdentityKey(self): return self.theirIdentityKey def getTheirSignedPreKey(self): return self.theirSignedPreKey def getTheirOneTimePreKey(self): return self.theirOneTimePreKey def getTheirRatchetKey(self): return self.theirRatchetKey @staticmethod def newBuilder(): return AliceAxolotlParameters.Builder() class Builder: def __init__(self): self.ourIdentityKey = None self.ourBaseKey = None self.theirIdentityKey = None self.theirSignedPreKey = None self.theirRatchetKey = None self.theirOneTimePreKey = None def setOurIdentityKey(self, ourIdentityKey): self.ourIdentityKey = ourIdentityKey return self def setOurBaseKey(self, ourBaseKey): self.ourBaseKey = ourBaseKey return self def setTheirRatchetKey(self, theirRatchetKey): self.theirRatchetKey = theirRatchetKey return self def setTheirIdentityKey(self, theirIdentityKey): self.theirIdentityKey = theirIdentityKey return self def setTheirSignedPreKey(self, theirSignedPreKey): self.theirSignedPreKey = theirSignedPreKey return self def setTheirOneTimePreKey(self, theirOneTimePreKey): self.theirOneTimePreKey = theirOneTimePreKey return self def create(self): return AliceAxolotlParameters(self.ourIdentityKey, self.ourBaseKey, self.theirIdentityKey, self.theirSignedPreKey, self.theirRatchetKey, self.theirOneTimePreKey)python-axolotl-0.1.7/axolotl/ratchet/bobaxolotlparamaters.py0000777000000000000000000000525112447400641024405 0ustar rootroot00000000000000class BobAxolotlParameters: def __init__(self, ourIdentityKey, ourSignedPreKey, ourRatchetKey, ourOneTimePreKey, theirIdentityKey, theirBaseKey): """ :type ourIdentityKey: IdentityKeyPair :type ourSignedPreKey: ECKeyPair :type ourRatchetKey: ECKeyPair :type ourOneTimePreKey: ECKeyPair :type theirIdentityKey: IdentityKey :type theirBaseKey: ECPublicKey """ self.ourIdentityKey = ourIdentityKey self.ourSignedPreKey = ourSignedPreKey self.ourRatchetKey = ourRatchetKey self.ourOneTimePreKey = ourOneTimePreKey self.theirIdentityKey = theirIdentityKey self.theirBaseKey = theirBaseKey if ourIdentityKey is None or ourSignedPreKey is None or ourRatchetKey is None\ or theirIdentityKey is None or theirBaseKey is None: raise ValueError("Null value!") def getOurIdentityKey(self): return self.ourIdentityKey def getOurSignedPreKey(self): return self.ourSignedPreKey def getOurOneTimePreKey(self): return self.ourOneTimePreKey def getTheirIdentityKey(self): return self.theirIdentityKey def getTheirBaseKey(self): return self.theirBaseKey def getOurRatchetKey(self): return self.ourRatchetKey @staticmethod def newBuilder(): return BobAxolotlParameters.Builder() class Builder: def __init__(self): self.ourIdentityKey = None self.ourSignedPreKey = None self.ourOneTimePreKey = None self.ourRatchetKey = None self.theirIdentityKey = None self.theirBaseKey = None def setOurIdentityKey(self, ourIdentityKey): self.ourIdentityKey = ourIdentityKey return self def setOurSignedPreKey(self, ourSignedPreKey): self.ourSignedPreKey = ourSignedPreKey return self def setOurOneTimePreKey(self, ourOneTimePreKey): self.ourOneTimePreKey = ourOneTimePreKey return self def setOurRatchetKey(self, ourRatchetKey): self.ourRatchetKey = ourRatchetKey return self def setTheirIdentityKey(self, theirIdentityKey): self.theirIdentityKey =theirIdentityKey return self def setTheirBaseKey(self, theirBaseKey): self.theirBaseKey = theirBaseKey return self def create(self): return BobAxolotlParameters(self.ourIdentityKey, self.ourSignedPreKey, self.ourRatchetKey, self.ourOneTimePreKey, self.theirIdentityKey, self.theirBaseKey) python-axolotl-0.1.7/axolotl/ratchet/chainkey.py0000777000000000000000000000227112455652610021756 0ustar rootroot00000000000000import hmac import hashlib from ..kdf.derivedmessagesecrets import DerivedMessageSecrets from ..kdf.messagekeys import MessageKeys class ChainKey: MESSAGE_KEY_SEED = bytearray([0x01]) CHAIN_KEY_SEED = bytearray([0x02]) def __init__(self, kdf, key, index): self.kdf = kdf self.key = key self.index = index def getKey(self): return self.key def getIndex(self): return self.index def getNextChainKey(self): nextKey = self.getBaseMaterial(self.__class__.CHAIN_KEY_SEED) return ChainKey(self.kdf, nextKey, self.index + 1) def getMessageKeys(self): inputKeyMaterial = self.getBaseMaterial(self.__class__.MESSAGE_KEY_SEED) keyMaterialBytes = self.kdf.deriveSecrets(inputKeyMaterial, bytearray("WhisperMessageKeys".encode()), DerivedMessageSecrets.SIZE) keyMaterial = DerivedMessageSecrets(keyMaterialBytes) return MessageKeys(keyMaterial.getCipherKey(), keyMaterial.getMacKey(), keyMaterial.getIv(), self.index) def getBaseMaterial(self, seedBytes): mac = hmac.new(bytes(self.key), digestmod=hashlib.sha256) mac.update(bytes(seedBytes)) return mac.digest() python-axolotl-0.1.7/axolotl/ratchet/ratchetingsession.py0000777000000000000000000001440112455652425023721 0ustar rootroot00000000000000from ..ecc.curve import Curve from .bobaxolotlparamaters import BobAxolotlParameters from .aliceaxolotlparameters import AliceAxolotlParameters from ..kdf.hkdf import HKDF from ..util.byteutil import ByteUtil from .rootkey import RootKey from .chainkey import ChainKey class RatchetingSession: @staticmethod def initializeSession(sessionState, sessionVersion, parameters): """ :type sessionState: SessionState :type sessionVersion: int :type parameters: SymmetricAxolotlParameters """ if RatchetingSession.isAlice(parameters.getOurBaseKey().getPublicKey(), parameters.getTheirBaseKey()): aliceParameters = AliceAxolotlParameters.newBuilder() aliceParameters.setOurBaseKey(parameters.getOurBaseKey())\ .setOurIdentityKey(parameters.getOurIdentityKey())\ .setTheirRatchetKey(parameters.getTheirRatchetKey())\ .setTheirIdentityKey(parameters.getTheirIdentityKey())\ .setTheirSignedPreKey(parameters.getTheirBaseKey())\ .setTheirOneTimePreKey(None) RatchetingSession.initializeSessionAsAlice(sessionState, sessionVersion, aliceParameters.create()) else: bobParameters = BobAxolotlParameters.newBuilder() bobParameters.setOurIdentityKey(parameters.getOurIdentityKey())\ .setOurRatchetKey(parameters.getOurRatchetKey())\ .setOurSignedPreKey(parameters.getOurBaseKey())\ .setOurOneTimePreKey(None)\ .setTheirBaseKey(parameters.getTheirBaseKey())\ .setTheirIdentityKey(parameters.getTheirIdentityKey()) RatchetingSession.initializeSessionAsBob(sessionState, sessionVersion, bobParameters.create()) @staticmethod def initializeSessionAsAlice(sessionState, sessionVersion, parameters): """ :type sessionState: SessionState :type sessionVersion: int :type parameters: AliceAxolotlParameters """ sessionState.setSessionVersion(sessionVersion) sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey()) sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey()) sendingRatchetKey = Curve.generateKeyPair() secrets = bytearray() if sessionVersion >= 3: secrets.extend(RatchetingSession.getDiscontinuityBytes()) secrets.extend(Curve.calculateAgreement(parameters.getTheirSignedPreKey(), parameters.getOurIdentityKey().getPrivateKey())) secrets.extend(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(), parameters.getOurBaseKey().getPrivateKey())) secrets.extend(Curve.calculateAgreement(parameters.getTheirSignedPreKey(), parameters.getOurBaseKey().getPrivateKey())) if sessionVersion >= 3 and parameters.getTheirOneTimePreKey() is not None: secrets.extend(Curve.calculateAgreement(parameters.getTheirOneTimePreKey(), parameters.getOurBaseKey().getPrivateKey())) derivedKeys = RatchetingSession.calculateDerivedKeys(sessionVersion, secrets) sendingChain = derivedKeys.getRootKey().createChain(parameters.getTheirRatchetKey(), sendingRatchetKey) sessionState.addReceiverChain(parameters.getTheirRatchetKey(), derivedKeys.getChainKey()) sessionState.setSenderChain(sendingRatchetKey, sendingChain[1]) sessionState.setRootKey(sendingChain[0]) @staticmethod def initializeSessionAsBob(sessionState, sessionVersion, parameters): """ :type sessionState: SessionState :type sessionVersion: int :type parameters: BobAxolotlParameters """ sessionState.setSessionVersion(sessionVersion) sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey()) sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey()) secrets = bytearray() if sessionVersion >= 3: secrets.extend(RatchetingSession.getDiscontinuityBytes()) secrets.extend(Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(), parameters.getOurSignedPreKey().getPrivateKey())) secrets.extend(Curve.calculateAgreement(parameters.getTheirBaseKey(), parameters.getOurIdentityKey().getPrivateKey())) secrets.extend(Curve.calculateAgreement(parameters.getTheirBaseKey(), parameters.getOurSignedPreKey().getPrivateKey())) if sessionVersion >= 3 and parameters.getOurOneTimePreKey() is not None: secrets.extend(Curve.calculateAgreement(parameters.getTheirBaseKey(), parameters.getOurOneTimePreKey().getPrivateKey())) derivedKeys = RatchetingSession.calculateDerivedKeys(sessionVersion, secrets) sessionState.setSenderChain(parameters.getOurRatchetKey(), derivedKeys.getChainKey()) sessionState.setRootKey(derivedKeys.getRootKey()) @staticmethod def getDiscontinuityBytes(): return bytearray([0xFF] * 32) @staticmethod def calculateDerivedKeys(sessionVersion, masterSecret): kdf = HKDF.createFor(sessionVersion) derivedSecretBytes = kdf.deriveSecrets(masterSecret, bytearray("WhisperText".encode()), 64) derivedSecrets = ByteUtil.split(derivedSecretBytes, 32, 32) return RatchetingSession.DerivedKeys(RootKey(kdf, derivedSecrets[0]), ChainKey(kdf, derivedSecrets[1], 0)) @staticmethod def isAlice(ourKey, theirKey): """ :type ourKey: ECPublicKey :type theirKey: ECPublicKey """ return ourKey < theirKey class DerivedKeys: def __init__(self, rootKey, chainKey): """ :type rootKey: RootKey :type chainKey: ChainKey """ self.rootKey = rootKey self.chainKey = chainKey def getRootKey(self): return self.rootKey def getChainKey(self): return self.chainKey python-axolotl-0.1.7/axolotl/ratchet/rootkey.py0000777000000000000000000000153112450013015021636 0ustar rootroot00000000000000from ..ecc.curve import Curve from ..kdf.derivedrootsecrets import DerivedRootSecrets from .chainkey import ChainKey class RootKey: def __init__(self, kdf, key): self.kdf = kdf self.key = key def getKeyBytes(self): return self.key def createChain(self, ECPublicKey_theirRatchetKey, ECKeyPair_ourRatchetKey): sharedSecret = Curve.calculateAgreement(ECPublicKey_theirRatchetKey, ECKeyPair_ourRatchetKey.getPrivateKey()) derivedSecretBytes = self.kdf.deriveSecrets(sharedSecret, bytearray("WhisperRatchet".encode()), DerivedRootSecrets.SIZE, salt = self.key) derivedSecrets = DerivedRootSecrets(derivedSecretBytes) newRootKey = RootKey(self.kdf, derivedSecrets.getRootKey()) newChainKey = ChainKey(self.kdf, derivedSecrets.getChainKey(), 0) return (newRootKey, newChainKey) python-axolotl-0.1.7/axolotl/ratchet/symmetricaxolotlparameters.py0000777000000000000000000000520712447400653025667 0ustar rootroot00000000000000class SymmetricAxolotlParameters: def __init__(self, ourBaseKey, ourRatchetKey, ourIdentityKey, theirBaseKey, theirRatchetKey, theirIdentityKey): """ :type ourBaseKey: ECKeyPair :type ourRatchetKey: ECKeyPair :type ourIdentityKey: IdentityKeyPair :type theirBaseKey: ECPublicKey :type theirRatchetKey: ECKeyPair :type theirIdentityKey: IdentityKey """ self.ourBaseKey = ourBaseKey self.ourIdentityKey = ourIdentityKey self.ourRatchetKey = ourRatchetKey self.theirRatchetKey = theirRatchetKey self.theirIdentityKey = theirIdentityKey self.theirBaseKey = theirBaseKey if ourBaseKey is None or ourIdentityKey is None or ourRatchetKey is None\ or theirRatchetKey is None or theirIdentityKey is None or theirBaseKey is None: raise ValueError("Null value!") def getOurBaseKey(self): return self.ourBaseKey def getOurIdentityKey(self): return self.ourIdentityKey def getTheirRatchetKey(self): return self.theirRatchetKey def getTheirIdentityKey(self): return self.theirIdentityKey def getTheirBaseKey(self): return self.theirBaseKey def getOurRatchetKey(self): return self.ourRatchetKey @staticmethod def newBuilder(): return SymmetricAxolotlParameters.Builder() class Builder: def __init__(self): self.ourIdentityKey = None self.ourBaseKey = None self.ourRatchetKey = None self.theirRatchetKey = None self.theirIdentityKey = None self.theirBaseKey = None def setOurIdentityKey(self, ourIdentityKey): self.ourIdentityKey = ourIdentityKey return self def setOurBaseKey(self, ourBaseKey): self.ourBaseKey = ourBaseKey return self def setOurRatchetKey(self, ourRatchetKey): self.ourRatchetKey = ourRatchetKey return self def setTheirRatchetKey(self, theirRatchetKey): self.theirRatchetKey = theirRatchetKey return self def setTheirIdentityKey(self, theirIdentityKey): self.theirIdentityKey = theirIdentityKey return self def setTheirBaseKey(self, theirBaseKey): self.theirBaseKey = theirBaseKey return self def create(self): return SymmetricAxolotlParameters(self.ourBaseKey, self.ourRatchetKey, self.ourIdentityKey, self.theirBaseKey, self.theirRatchetKey, self.theirIdentityKey)python-axolotl-0.1.7/axolotl/ratchet/__init__.py0000777000000000000000000000000012454325147021707 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/sessionbuilder.py0000777000000000000000000003433212447776374021605 0ustar rootroot00000000000000import logging from .ratchet.ratchetingsession import RatchetingSession from .ecc.curve import Curve from .util.medium import Medium from .ratchet.aliceaxolotlparameters import AliceAxolotlParameters from .ratchet.bobaxolotlparamaters import BobAxolotlParameters from axolotl.invalidkeyexception import InvalidKeyException from axolotl.invalidkeyidexception import InvalidKeyIdException from axolotl.untrustedidentityexception import UntrustedIdentityException from axolotl.protocol.keyexchangemessage import KeyExchangeMessage from axolotl.ratchet.symmetricaxolotlparameters import SymmetricAxolotlParameters from axolotl.protocol.ciphertextmessage import CiphertextMessage from axolotl.statekeyexchangeexception import StaleKeyExchangeException from axolotl.util.keyhelper import KeyHelper logger = logging.getLogger(__name__) class SessionBuilder: def __init__(self, sessionStore, preKeyStore, signedPreKeyStore, identityKeyStore, recepientId, deviceId): self.sessionStore = sessionStore self.preKeyStore = preKeyStore self.signedPreKeyStore = signedPreKeyStore self.identityKeyStore = identityKeyStore self.recipientId = recepientId self.deviceId = deviceId def process(self, sessionRecord, message): """ :param sessionRecord: :param message: :type message: PreKeyWhisperMessage """ messageVersion = message.getMessageVersion() theirIdentityKey = message.getIdentityKey() unsignedPreKeyId = None if not self.identityKeyStore.isTrustedIdentity(self.recipientId, theirIdentityKey): raise UntrustedIdentityException("Untrusted identity!!") if messageVersion == 2: unsignedPreKeyId = self.processV2(sessionRecord, message) elif messageVersion == 3: unsignedPreKeyId = self.processV3(sessionRecord, message) else: raise AssertionError("Unkown version %s" % messageVersion) self.identityKeyStore.saveIdentity(self.recipientId, theirIdentityKey) return unsignedPreKeyId def processV2(self, sessionRecord, message): """ :type sessionRecord: SessionRecord :type message: PreKeyWhisperMessage """ if message.getPreKeyId() is None: raise InvalidKeyIdException("V2 message requires one time prekey id!") if not self.preKeyStore.containsPreKey(message.getPreKeyId()) and\ self.sessionStore.containsSession(self.recipientId, self.deviceId): logging.warn("We've already processed the prekey part of this V2 session, letting bundled message fall through...") return None ourPreKey = self.preKeyStore.loadPreKey(message.getPreKeyId()).getKeyPair() parameters = BobAxolotlParameters.newBuilder() parameters.setOurIdentityKey(self.identityKeyStore.getIdentityKeyPair())\ .setOurSignedPreKey(ourPreKey)\ .setOurRatchetKey(ourPreKey)\ .setOurOneTimePreKey(None)\ .setTheirIdentityKey(message.getIdentityKey())\ .setTheirBaseKey(message.getBaseKey()) if not sessionRecord.isFresh(): sessionRecord.archiveCurrentState() RatchetingSession.initializeSessionAsBob(sessionRecord.getSessionState(), message.getMessageVersion(), parameters.create()) sessionRecord.getSessionState().setLocalRegistrationId(self.identityKeyStore.getLocalRegistrationId()) sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()) sessionRecord.getSessionState().setAliceBaseKey(message.getBaseKey().serialize()) if message.getPreKeyId() != Medium.MAX_VALUE: return message.getPreKeyId() else: return None def processV3(self, sessionRecord, message): """ :param sessionRecord: :param message: :type message: PreKeyWhisperMessage :return: """ if sessionRecord.hasSessionState(message.getMessageVersion(), message.getBaseKey().serialize()): logger.warn("We've already setup a session for this V3 message, letting bundled message fall through...") return None ourSignedPreKey = self.signedPreKeyStore.loadSignedPreKey(message.getSignedPreKeyId()).getKeyPair() parameters = BobAxolotlParameters.newBuilder() parameters.setTheirBaseKey(message.getBaseKey())\ .setTheirIdentityKey(message.getIdentityKey())\ .setOurIdentityKey(self.identityKeyStore.getIdentityKeyPair())\ .setOurSignedPreKey(ourSignedPreKey)\ .setOurRatchetKey(ourSignedPreKey) if message.getPreKeyId() is not None: parameters.setOurOneTimePreKey(self.preKeyStore.loadPreKey(message.getPreKeyId()).getKeyPair()) else: parameters.setOurOneTimePreKey(None) if not sessionRecord.isFresh(): sessionRecord.archiveCurrentState() RatchetingSession.initializeSessionAsBob(sessionRecord.getSessionState(), message.getMessageVersion(), parameters.create()) sessionRecord.getSessionState().setLocalRegistrationId(self.identityKeyStore.getLocalRegistrationId()) sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()) sessionRecord.getSessionState().setAliceBaseKey(message.getBaseKey().serialize()) if message.getPreKeyId() is not None and message.getPreKeyId() != Medium.MAX_VALUE: return message.getPreKeyId() else: return None def processPreKeyBundle(self, preKey): """ :type preKey: PreKeyBundle """ if not self.identityKeyStore.isTrustedIdentity(self.recipientId, preKey.getIdentityKey()): raise UntrustedIdentityException() if preKey.getSignedPreKey() is not None and\ not Curve.verifySignature(preKey.getIdentityKey().getPublicKey(), preKey.getSignedPreKey().serialize(), preKey.getSignedPreKeySignature()) : raise InvalidKeyException("Invalid signature on device key!") if preKey.getSignedPreKey() is None and preKey.getPreKey() is None: raise InvalidKeyException("Both signed and unsigned prekeys are absent!") supportsV3 = preKey.getSignedPreKey() is not None sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) ourBaseKey = Curve.generateKeyPair() theirSignedPreKey = preKey.getSignedPreKey() if supportsV3 else preKey.getPreKey() theirOneTimePreKey = preKey.getPreKey() theirOneTimePreKeyId = preKey.getPreKeyId() if theirOneTimePreKey is not None else None parameters = AliceAxolotlParameters.newBuilder() parameters.setOurBaseKey(ourBaseKey)\ .setOurIdentityKey(self.identityKeyStore.getIdentityKeyPair())\ .setTheirIdentityKey(preKey.getIdentityKey())\ .setTheirSignedPreKey(theirSignedPreKey)\ .setTheirRatchetKey(theirSignedPreKey)\ .setTheirOneTimePreKey(theirOneTimePreKey if supportsV3 else None) if not sessionRecord.isFresh(): sessionRecord.archiveCurrentState(); RatchetingSession.initializeSessionAsAlice(sessionRecord.getSessionState(), 3 if supportsV3 else 2, parameters.create()) sessionRecord.getSessionState().setUnacknowledgedPreKeyMessage(theirOneTimePreKeyId, preKey.getSignedPreKeyId(), ourBaseKey.getPublicKey()) sessionRecord.getSessionState().setLocalRegistrationId(self.identityKeyStore.getLocalRegistrationId()) sessionRecord.getSessionState().setRemoteRegistrationId(preKey.getRegistrationId()) sessionRecord.getSessionState().setAliceBaseKey(ourBaseKey.getPublicKey().serialize()) self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) self.identityKeyStore.saveIdentity(self.recipientId, preKey.getIdentityKey()) def processKeyExchangeMessage(self, keyExchangeMessage): if not self.identityKeyStore.isTrustedIdentity(self.recipientId, keyExchangeMessage.getIdentityKey()): raise UntrustedIdentityException() responseMessage = None if keyExchangeMessage.isInitiate(): responseMessage = self.processInitiate(keyExchangeMessage) else: self.processResponse(keyExchangeMessage) return responseMessage def processInitiate(self, keyExchangeMessage): flags = KeyExchangeMessage.RESPONSE_FLAG sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) if keyExchangeMessage.getVersion() >= 3 and not Curve.verifySignature( keyExchangeMessage.getIdentityKey().getPublicKey(), keyExchangeMessage.getBaseKey().serialize(), keyExchangeMessage.getBaseKeySignature()): raise InvalidKeyException("Bad signature!") builder = SymmetricAxolotlParameters.newBuilder() if not sessionRecord.getSessionState().hasPendingKeyExchange(): builder.setOurIdentityKey(self.identityKeyStore.getIdentityKeyPair())\ .setOurBaseKey(Curve.generateKeyPair())\ .setOurRatchetKey(Curve.generateKeyPair()) else: builder.setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())\ .setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())\ .setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey()) flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG builder.setTheirBaseKey(keyExchangeMessage.getBaseKey())\ .setTheirRatchetKey(keyExchangeMessage.getRatchetKey())\ .setTheirIdentityKey(keyExchangeMessage.getIdentityKey()) parameters = builder.create() if not sessionRecord.isFresh(): sessionRecord.archiveCurrentState() RatchetingSession.initializeSession(sessionRecord.getSessionState(), min(keyExchangeMessage.getMaxVersion(), CiphertextMessage.CURRENT_VERSION), parameters) self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) self.identityKeyStore.saveIdentity(self.recipientId, keyExchangeMessage.getIdentityKey()) baseKeySignature = Curve.calculateSignature(parameters.getOurIdentityKey().getPrivateKey(), parameters.getOurBaseKey().getPublicKey().serialize()) return KeyExchangeMessage(sessionRecord.getSessionState().getSessionVersion(), keyExchangeMessage.getSequence(), flags, parameters.getOurBaseKey().getPublicKey(), baseKeySignature, parameters.getOurRatchetKey().getPublicKey(), parameters.getOurIdentityKey().getPublicKey()) def processResponse(self, keyExchangeMessage): sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) sessionState = sessionRecord.getSessionState() hasPendingKeyExchange = sessionState.hasPendingKeyExchange() isSimultaneousInitiateResponse = keyExchangeMessage.isResponseForSimultaneousInitiate() if not hasPendingKeyExchange or sessionState.getPendingKeyExchangeSequence() != keyExchangeMessage.getSequence(): logger.warn("No matching sequence for response. Is simultaneous initiate response: %s" % isSimultaneousInitiateResponse) if not isSimultaneousInitiateResponse: raise StaleKeyExchangeException() else: return parameters = SymmetricAxolotlParameters.newBuilder() parameters.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())\ .setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey())\ .setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())\ .setTheirBaseKey(keyExchangeMessage.getBaseKey())\ .setTheirRatchetKey(keyExchangeMessage.getRatchetKey())\ .setTheirIdentityKey(keyExchangeMessage.getIdentityKey()) if not sessionRecord.isFresh(): sessionRecord.archiveCurrentState() RatchetingSession.initializeSession(sessionRecord.getSessionState(), min(keyExchangeMessage.getMaxVersion(), CiphertextMessage.CURRENT_VERSION), parameters.create()) if sessionRecord.getSessionState().getSessionVersion() >= 3 and not Curve.verifySignature( keyExchangeMessage.getIdentityKey().getPublicKey(), keyExchangeMessage.getBaseKey().serialize(), keyExchangeMessage.getBaseKeySignature()): raise InvalidKeyException("Base key signature doesn't match!") self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) self.identityKeyStore.saveIdentity(self.recipientId, keyExchangeMessage.getIdentityKey()) def processInitKeyExchangeMessage(self): try: sequence = KeyHelper.getRandomSequence(65534) + 1 flags = KeyExchangeMessage.INITIATE_FLAG baseKey = Curve.generateKeyPair() ratchetKey = Curve.generateKeyPair() identityKey = self.identityKeyStore.getIdentityKeyPair() baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize()) sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey) self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) return KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), baseKeySignature, ratchetKey.getPublicKey(), identityKey.getPublicKey()) except InvalidKeyException as e: raise AssertionError(e)python-axolotl-0.1.7/axolotl/sessioncipher.py0000777000000000000000000002627312470143452021413 0ustar rootroot00000000000000from .ecc.curve import Curve import Crypto.Cipher.AES as AES from Crypto.Util import Counter from .sessionbuilder import SessionBuilder from .util.byteutil import ByteUtil from .state.sessionstate import SessionState from .protocol.whispermessage import WhisperMessage from .protocol.prekeywhispermessage import PreKeyWhisperMessage from axolotl.nosessionexception import NoSessionException from axolotl.invalidmessageexception import InvalidMessageException from axolotl.duplicatemessagexception import DuplicateMessageException import binascii import sys if sys.version_info >= (3,0): unicode = str class SessionCipher: def __init__(self, sessionStore, preKeyStore, signedPreKeyStore, identityKeyStore, recepientId, deviceId): self.sessionStore = sessionStore self.preKeyStore = preKeyStore self.recipientId = recepientId self.deviceId = deviceId self.sessionBuilder = SessionBuilder(sessionStore, preKeyStore, signedPreKeyStore, identityKeyStore, recepientId, deviceId) def encrypt(self, paddedMessage): """ :type paddedMessage: str """ paddedMessage = bytearray(paddedMessage.encode() if (sys.version_info >= (3,0) and not type(paddedMessage) in (bytes, bytearray)) or type(paddedMessage) is unicode else paddedMessage) sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) sessionState = sessionRecord.getSessionState() chainKey = sessionState.getSenderChainKey() messageKeys = chainKey.getMessageKeys() senderEphemeral = sessionState.getSenderRatchetKey() previousCounter = sessionState.getPreviousCounter() sessionVersion = sessionState.getSessionVersion() ciphertextBody = self.getCiphertext(sessionVersion, messageKeys, paddedMessage) ciphertextMessage = WhisperMessage(sessionVersion, messageKeys.getMacKey(), senderEphemeral, chainKey.getIndex(), previousCounter, ciphertextBody, sessionState.getLocalIdentityKey(), sessionState.getRemoteIdentityKey()) # print(binascii.hexlify(ciphertextMessage.serialize())) if sessionState.hasUnacknowledgedPreKeyMessage(): items = sessionState.getUnacknowledgedPreKeyMessageItems() localRegistrationid = sessionState.getLocalRegistrationId() ciphertextMessage = PreKeyWhisperMessage(sessionVersion, localRegistrationid, items.getPreKeyId(), items.getSignedPreKeyId(), items.getBaseKey(), sessionState.getLocalIdentityKey(), ciphertextMessage) sessionState.setSenderChainKey(chainKey.getNextChainKey()) self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) return ciphertextMessage def decryptMsg(self, ciphertext): """ :type ciphertext: WhisperMessage """ if not self.sessionStore.containsSession(self.recipientId, self.deviceId): raise NoSessionException("No session for: %s, %s" % (self.recipientId, self.deviceId)) sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) plaintext = self.decryptWithSessionRecord(sessionRecord, ciphertext) self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) if sys.version_info >= (3,0): return plaintext.decode() return plaintext def decryptPkmsg(self, ciphertext): """ :type ciphertext: PreKeyWhisperMessage """ sessionRecord = self.sessionStore.loadSession(self.recipientId, self.deviceId) unsignedPreKeyId = self.sessionBuilder.process(sessionRecord, ciphertext) plaintext = self.decryptWithSessionRecord(sessionRecord, ciphertext.getWhisperMessage()) #callback.handlePlaintext(plaintext); self.sessionStore.storeSession(self.recipientId, self.deviceId, sessionRecord) if unsignedPreKeyId is not None: self.preKeyStore.removePreKey(unsignedPreKeyId) if sys.version_info >= (3, 0): return plaintext.decode() return plaintext def decryptWithSessionRecord(self, sessionRecord, cipherText): """ :type sessionRecord: SessionRecord :type cipherText: WhisperMessage """ previousStates = sessionRecord.getPreviousSessionStates() exceptions = [] try: sessionState = SessionState(sessionRecord.getSessionState()) plaintext = self.decryptWithSessionState(sessionState, cipherText) sessionRecord.setState(sessionState) return plaintext except InvalidMessageException as e: exceptions.append(e) for i in range(0, len(previousStates)): previousState = previousStates[i] try: promotedState = SessionState(previousState) plaintext = self.decryptWithSessionState(promotedState, cipherText) previousStates.pop(i) sessionRecord.promoteState(promotedState) return plaintext except InvalidMessageException as e: exceptions.append(e) raise InvalidMessageException("No valid sessions", exceptions) def decryptWithSessionState(self, sessionState, ciphertextMessage): if not sessionState.hasSenderChain(): raise InvalidMessageException("Uninitialized session!") if ciphertextMessage.getMessageVersion() != sessionState.getSessionVersion(): raise InvalidMessageException("Message version %s, but session version %s" % (ciphertextMessage.getMessageVersion, sessionState.getSessionVersion())) messageVersion = ciphertextMessage.getMessageVersion() theirEphemeral = ciphertextMessage.getSenderRatchetKey() counter = ciphertextMessage.getCounter() chainKey = self.getOrCreateChainKey(sessionState, theirEphemeral) messageKeys = self.getOrCreateMessageKeys(sessionState, theirEphemeral, chainKey, counter) ciphertextMessage.verifyMac(messageVersion, sessionState.getRemoteIdentityKey(), sessionState.getLocalIdentityKey(), messageKeys.getMacKey()) plaintext = self.getPlaintext(messageVersion, messageKeys, ciphertextMessage.getBody()) sessionState.clearUnacknowledgedPreKeyMessage() return plaintext def getOrCreateChainKey(self, sessionState, ECPublickKey_theirEphemeral): theirEphemeral = ECPublickKey_theirEphemeral if sessionState.hasReceiverChain(theirEphemeral): return sessionState.getReceiverChainKey(theirEphemeral) else: rootKey = sessionState.getRootKey() ourEphemeral = sessionState.getSenderRatchetKeyPair() receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral) ourNewEphemeral = Curve.generateKeyPair() senderChain = receiverChain[0].createChain(theirEphemeral, ourNewEphemeral) sessionState.setRootKey(senderChain[0]) sessionState.addReceiverChain(theirEphemeral, receiverChain[1]) sessionState.setPreviousCounter(max(sessionState.getSenderChainKey().getIndex() - 1, 0)) sessionState.setSenderChain(ourNewEphemeral, senderChain[1]) return receiverChain[1] def getOrCreateMessageKeys(self, sessionState, ECPublicKey_theirEphemeral, chainKey, counter): theirEphemeral = ECPublicKey_theirEphemeral if chainKey.getIndex() > counter: if sessionState.hasMessageKeys(theirEphemeral, counter): return sessionState.removeMessageKeys(theirEphemeral, counter) else: raise DuplicateMessageException("Received message " "with old counter: %s, %s" % (chainKey.getIndex(), counter)) if counter - chainKey.getIndex() > 2000: raise InvalidMessageException("Over 2000 messages into the future!") while chainKey.getIndex() < counter: messageKeys = chainKey.getMessageKeys() sessionState.setMessageKeys(theirEphemeral, messageKeys) chainKey = chainKey.getNextChainKey() sessionState.setReceiverChainKey(theirEphemeral, chainKey.getNextChainKey()) return chainKey.getMessageKeys() def getCiphertext(self, version, messageKeys, plainText): """ :type version: int :type messageKeys: MessageKeys :type plainText: bytearray """ cipher = None if version >= 3: cipher = self.getCipher(messageKeys.getCipherKey(), messageKeys.getIv()) else: cipher = self.getCipher_v2(messageKeys.getCipherKey(), messageKeys.getCounter()) return cipher.encrypt(bytes(plainText)) def getPlaintext(self, version, messageKeys, cipherText): cipher = None if version >= 3: cipher = self.getCipher(messageKeys.getCipherKey(), messageKeys.getIv()) else: cipher = self.getCipher_v2(messageKeys.getCipherKey(), messageKeys.getCounter()) return cipher.decrypt(cipherText) def getCipher(self, key, iv): #Cipher.getInstance("AES/CBC/PKCS5Padding"); #cipher = AES.new(key, AES.MODE_CBC, IV = iv) #return cipher return AESCipher(key, iv) def getCipher_v2(self, key, counter): #AES/CTR/NoPadding #counterbytes = struct.pack('>L', counter) + (b'\x00' * 12) #counterint = struct.unpack(">L", counterbytes)[0] #counterint = int.from_bytes(counterbytes, byteorder='big') ctr=Counter.new(128, initial_value= counter) #cipher = AES.new(key, AES.MODE_CTR, counter=ctr) ivBytes = bytearray(16) ByteUtil.intToByteArray(ivBytes, 0, counter) cipher = AES.new(key, AES.MODE_CTR, IV = bytes(ivBytes), counter=ctr) return cipher BS = 16 if sys.version_info >= (3,0): pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() unpad = lambda s : s[0:-s[-1]] else: pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) unpad = lambda s : s[0:-ord(s[-1])] class AESCipher: def __init__( self, key, iv): self.key = key self.iv = iv self.cipher = AES.new(key, AES.MODE_CBC, IV = iv) def encrypt( self, raw ): # if sys.version_info >= (3,0): # rawPadded = pad(raw.decode()).encode() # else: rawPadded = pad(raw) try: return self.cipher.encrypt(rawPadded) except ValueError: raise def decrypt(self, enc): return unpad(self.cipher.decrypt(enc)) python-axolotl-0.1.7/axolotl/state/0000777000000000000000000000000012521166655017275 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/state/axolotlstore.py0000777000000000000000000000045212445571541022411 0ustar rootroot00000000000000from .identitykeystore import IdentityKeyStore from .prekeystore import PreKeyStore from .sessionstore import SessionStore from .signedprekeystore import SignedPreKeyStore import abc class AxolotlStore(IdentityKeyStore, PreKeyStore, SignedPreKeyStore, SessionStore): __metaclass__ = abc.ABCMetapython-axolotl-0.1.7/axolotl/state/identitykeystore.py0000777000000000000000000000056712445571116023276 0ustar rootroot00000000000000import abc class IdentityKeyStore(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def getIdentityKeyPair(self):pass @abc.abstractmethod def getLocalRegistrationId(self):pass @abc.abstractmethod def saveIdentity(self, recepientId, identityKey):pass @abc.abstractmethod def isTrustedIdentity(self, recepientId, identityKey):passpython-axolotl-0.1.7/axolotl/state/prekeybundle.py0000777000000000000000000000214312445572125022341 0ustar rootroot00000000000000class PreKeyBundle: def __init__(self, registrationId, deviceId, preKeyId, ECPublicKey_preKeyPublic, signedPreKeyId, ECPublicKey_signedPreKeyPublic, signedPreKeySignature, identityKey): self.registrationId = registrationId self.deviceId = deviceId self.preKeyId = preKeyId self.preKeyPublic = ECPublicKey_preKeyPublic self.signedPreKeyId = signedPreKeyId self.signedPreKeyPublic = ECPublicKey_signedPreKeyPublic self.signedPreKeySignature = signedPreKeySignature self.identityKey = identityKey def getDeviceId(self): return self.deviceId def getPreKeyId(self): return self.preKeyId def getPreKey(self): return self.preKeyPublic def getSignedPreKeyId(self): return self.signedPreKeyId def getSignedPreKey(self): return self.signedPreKeyPublic def getSignedPreKeySignature(self): return self.signedPreKeySignature def getIdentityKey(self): return self.identityKey def getRegistrationId(self): return self.registrationIdpython-axolotl-0.1.7/axolotl/state/prekeyrecord.py0000777000000000000000000000161512446411447022351 0ustar rootroot00000000000000from .storageprotos import PreKeyRecordStructure from ..ecc.curve import Curve from ..ecc.eckeypair import ECKeyPair class PreKeyRecord: def __init__(self, _id = None, ecKeyPair = None, serialized = None): self.structure = PreKeyRecordStructure() if serialized: self.structure.ParseFromString(serialized) else: self.structure.id = _id self.structure.publicKey = ecKeyPair.getPublicKey().serialize() self.structure.privateKey = ecKeyPair.getPrivateKey().serialize() def getId(self): return self.structure.id def getKeyPair(self): publicKey = Curve.decodePoint(bytearray(self.structure.publicKey), 0) privateKey = Curve.decodePrivatePoint(bytearray(self.structure.privateKey)) return ECKeyPair(publicKey, privateKey) def serialize(self): return self.structure.SerializeToString() python-axolotl-0.1.7/axolotl/state/prekeystore.py0000777000000000000000000000053612445570464022234 0ustar rootroot00000000000000import abc class PreKeyStore(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def loadPreKey(self, preKeyId):pass @abc.abstractmethod def storePreKey(self, preKeyId, preKeyRecord):pass @abc.abstractmethod def containsPreKey(self, preKeyId):pass @abc.abstractmethod def removePreKey(self, preKeyId):passpython-axolotl-0.1.7/axolotl/state/sessionrecord.py0000777000000000000000000000425712454325147022542 0ustar rootroot00000000000000from . import storageprotos from .sessionstate import SessionState class SessionRecord: ARCHIVED_STATES_MAX_LENGTH = 40 def __init__(self, sessionState = None, serialized = None): """ :type sessionState: SessionState :type serialized: str """ self.previousStates = [] if sessionState: self.sessionState = sessionState self.fresh = False elif serialized: record = storageprotos.RecordStructure() record.ParseFromString(serialized) self.sessionState = SessionState(record.currentSession) self.fresh = False for previousStructure in record.previousSessions: self.previousStates.append(SessionState(previousStructure)) else: self.fresh = True self.sessionState = SessionState() def hasSessionState(self, version, aliceBaseKey): if self.sessionState.getSessionVersion() == version and aliceBaseKey == self.sessionState.getAliceBaseKey(): return True for state in self.previousStates: if state.getSessionVersion() == version and aliceBaseKey == state.getAliceBaseKey(): return True return False def getSessionState(self): return self.sessionState def getPreviousSessionStates(self): return self.previousStates def isFresh(self): return self.fresh def archiveCurrentState(self): self.promoteState(SessionState()) def promoteState(self, promotedState): self.previousStates.insert(0, self.sessionState) self.sessionState = promotedState if len(self.previousStates) > self.__class__.ARCHIVED_STATES_MAX_LENGTH: self.previousStates.pop() def setState(self, sessionState): self.sessionState = sessionState def serialize(self): previousStructures = [previousState.getStructure() for previousState in self.previousStates] record = storageprotos.RecordStructure() record.currentSession.MergeFrom(self.sessionState.getStructure()) record.previousSessions.extend(previousStructures) return record.SerializeToString() python-axolotl-0.1.7/axolotl/state/sessionstate.py0000777000000000000000000002757712454325147022416 0ustar rootroot00000000000000from . import storageprotos from ..identitykeypair import IdentityKey,IdentityKeyPair from ..ratchet.rootkey import RootKey from ..kdf.hkdf import HKDF from ..ecc.curve import Curve from ..ecc.eckeypair import ECKeyPair from ..ratchet.chainkey import ChainKey from ..kdf.messagekeys import MessageKeys class SessionState: def __init__(self, session = None): if session == None: self.sessionStructure = storageprotos.SessionStructure() elif session.__class__ == SessionState: self.sessionStructure = storageprotos.SessionStructure() self.sessionStructure.CopyFrom(session.sessionStructure) else: self.sessionStructure = session def getStructure(self): return self.sessionStructure def getAliceBaseKey(self): return self.sessionStructure.aliceBaseKey def setAliceBaseKey(self, aliceBaseKey): self.sessionStructure.aliceBaseKey = aliceBaseKey def setSessionVersion(self, version): self.sessionStructure.sessionVersion = version def getSessionVersion(self): sessionVersion = self.sessionStructure.sessionVersion return 2 if sessionVersion == 0 else sessionVersion def setRemoteIdentityKey(self, identityKey): self.sessionStructure.remoteIdentityPublic = identityKey.serialize() def setLocalIdentityKey(self, identityKey): self.sessionStructure.localIdentityPublic = identityKey.serialize() def getRemoteIdentityKey(self): if self.sessionStructure.remoteIdentityPublic is None: return None return IdentityKey(self.sessionStructure.remoteIdentityPublic, 0) def getLocalIdentityKey(self): return IdentityKey(self.sessionStructure.localIdentityPublic, 0) def getPreviousCounter(self): return self.sessionStructure.previousCounter def setPreviousCounter(self, previousCounter): self.sessionStructure.previousCounter = previousCounter def getRootKey(self): return RootKey(HKDF.createFor(self.getSessionVersion()), self.sessionStructure.rootKey) def setRootKey(self, rootKey): self.sessionStructure.rootKey = rootKey.getKeyBytes() def getSenderRatchetKey(self): return Curve.decodePoint(bytearray(self.sessionStructure.senderChain.senderRatchetKey), 0) def getSenderRatchetKeyPair(self): publicKey = self.getSenderRatchetKey() privateKey = Curve.decodePrivatePoint(self.sessionStructure.senderChain.senderRatchetKeyPrivate) return ECKeyPair(publicKey, privateKey) def hasReceiverChain(self, ECPublickKey_senderEphemeral): return self.getReceiverChain(ECPublickKey_senderEphemeral) is not None def hasSenderChain(self): return self.sessionStructure.HasField("senderChain") def getReceiverChain(self, ECPublickKey_senderEphemeral): receiverChains = self.sessionStructure.receiverChains index = 0 for receiverChain in receiverChains: chainSenderRatchetKey = Curve.decodePoint(bytearray(receiverChain.senderRatchetKey), 0) if chainSenderRatchetKey == ECPublickKey_senderEphemeral: return (receiverChain, index) index += 1 def getReceiverChainKey(self, ECPublicKey_senderEphemeral): receiverChainAndIndex = self.getReceiverChain(ECPublicKey_senderEphemeral) receiverChain = receiverChainAndIndex[0] if receiverChain is None: return None return ChainKey(HKDF.createFor(self.getSessionVersion()), receiverChain.chainKey.key, receiverChain.chainKey.index) def addReceiverChain(self, ECPublickKey_senderRatchetKey, chainKey): senderRatchetKey = ECPublickKey_senderRatchetKey chain = storageprotos.SessionStructure.Chain() chain.senderRatchetKey = senderRatchetKey.serialize() chain.chainKey.key = chainKey.getKey() chain.chainKey.index = chainKey.getIndex() self.sessionStructure.receiverChains.extend([chain]) if len(self.sessionStructure.receiverChains) > 5: del self.sessionStructure.receiverChains[0] def setSenderChain(self, ECKeyPair_senderRatchetKeyPair, chainKey): senderRatchetKeyPair = ECKeyPair_senderRatchetKeyPair senderChain = storageprotos.SessionStructure.Chain() self.sessionStructure.senderChain.senderRatchetKey = senderRatchetKeyPair.getPublicKey().serialize() self.sessionStructure.senderChain.senderRatchetKeyPrivate = senderRatchetKeyPair.getPrivateKey().serialize() self.sessionStructure.senderChain.chainKey.key = chainKey.key self.sessionStructure.senderChain.chainKey.index = chainKey.index def getSenderChainKey(self): chainKeyStructure = self.sessionStructure.senderChain.chainKey return ChainKey(HKDF.createFor(self.getSessionVersion()), chainKeyStructure.key, chainKeyStructure.index) def setSenderChainKey(self, ChainKey_nextChainKey): nextChainKey = ChainKey_nextChainKey self.sessionStructure.senderChain.chainKey.key = nextChainKey.getKey() self.sessionStructure.senderChain.chainKey.index = nextChainKey.getIndex() def hasMessageKeys(self, ECPublickKey_senderEphemeral, counter): senderEphemeral =ECPublickKey_senderEphemeral chainAndIndex = self.getReceiverChain(senderEphemeral) chain = chainAndIndex[0] if chain is None: return False messageKeyList = chain.messageKeys for messageKey in messageKeyList: if messageKey.index == counter: return True return False def removeMessageKeys(self, ECPublicKey_senderEphemeral, counter): senderEphemeral = ECPublicKey_senderEphemeral chainAndIndex = self.getReceiverChain(senderEphemeral) chain = chainAndIndex[0] if chain is None: return None messageKeyList = chain.messageKeys result = None for i in range(0, len(messageKeyList)): messageKey = messageKeyList[i] if messageKey.index == counter: result = MessageKeys(messageKey.cipherKey, messageKey.macKey, messageKey.iv, messageKey.index) del messageKeyList[i] break self.sessionStructure.receiverChains[chainAndIndex[1]].CopyFrom(chain) return result def setMessageKeys(self, ECPublicKey_senderEphemeral, messageKeys): senderEphemeral = ECPublicKey_senderEphemeral chainAndIndex = self.getReceiverChain(senderEphemeral) chain = chainAndIndex[0] messageKeyStructure = chain.messageKeys.add() #storageprotos.SessionStructure.Chain.MessageKey() messageKeyStructure.cipherKey = messageKeys.getCipherKey() messageKeyStructure.macKey = messageKeys.getMacKey() messageKeyStructure.index = messageKeys.getCounter() messageKeyStructure.iv = messageKeys.getIv() #chain.messageKeys.append(messageKeyStructure) self.sessionStructure.receiverChains[chainAndIndex[1]].CopyFrom(chain) def setReceiverChainKey(self, ECPublicKey_senderEphemeral, chainKey): senderEphemeral = ECPublicKey_senderEphemeral chainAndIndex = self.getReceiverChain(senderEphemeral) chain = chainAndIndex[0] chain.chainKey.key = chainKey.getKey() chain.chainKey.index = chainKey.getIndex() #self.sessionStructure.receiverChains[chainAndIndex[1]].ClearField() self.sessionStructure.receiverChains[chainAndIndex[1]].CopyFrom(chain) def setPendingKeyExchange(self, sequence, ourBaseKey, ourRatchetKey, ourIdentityKey): """ :type sequence: int :type ourBaseKey: ECKeyPair :type ourRatchetKey: ECKeyPair :type ourIdentityKey: IdentityKeyPair """ structure = self.sessionStructure.PendingKeyExchange() structure.sequence = sequence structure.localBaseKey = ourBaseKey.getPublicKey().serialize() structure.localBaseKeyPrivate = ourBaseKey.getPrivateKey().serialize() structure.localRatchetKey = ourRatchetKey.getPublicKey().serialize() structure.localRatchetKeyPrivate = ourRatchetKey.getPrivateKey().serialize() structure.localIdentityKey = ourIdentityKey.getPublicKey().serialize() structure.localIdentityKeyPrivate = ourIdentityKey.getPrivateKey().serialize() self.sessionStructure.pendingKeyExchange.MergeFrom(structure) def getPendingKeyExchangeSequence(self): return self.sessionStructure.pendingKeyExchange.sequence def getPendingKeyExchangeBaseKey(self): publicKey = Curve.decodePoint(bytearray(self.sessionStructure.pendingKeyExchange.localBaseKey), 0) privateKey = Curve.decodePrivatePoint(self.sessionStructure.pendingKeyExchange.localBaseKeyPrivate) return ECKeyPair(publicKey, privateKey) def getPendingKeyExchangeRatchetKey(self): publicKey = Curve.decodePoint(bytearray(self.sessionStructure.pendingKeyExchange.localRatchetKey), 0) privateKey = Curve.decodePrivatePoint(self.sessionStructure.pendingKeyExchange.localRatchetKeyPrivate) return ECKeyPair(publicKey, privateKey) def getPendingKeyExchangeIdentityKey(self): publicKey = IdentityKey(bytearray(self.sessionStructure.pendingKeyExchange\ .localIdentityKey), 0) privateKey = Curve.decodePrivatePoint(self.sessionStructure.pendingKeyExchange.localIdentityKeyPrivate) return IdentityKeyPair(publicKey, privateKey) def hasPendingKeyExchange(self): return self.sessionStructure.HasField("pendingKeyExchange") def setUnacknowledgedPreKeyMessage(self, preKeyId, signedPreKeyId, baseKey): """ :type preKeyId: int :type signedPreKeyId: int :type baseKey: ECPublicKey """ self.sessionStructure.pendingPreKey.signedPreKeyId = signedPreKeyId self.sessionStructure.pendingPreKey.baseKey = baseKey.serialize() if preKeyId is not None: self.sessionStructure.pendingPreKey.preKeyId = preKeyId def hasUnacknowledgedPreKeyMessage(self): return self.sessionStructure.HasField("pendingPreKey") def getUnacknowledgedPreKeyMessageItems(self): preKeyId = None if self.sessionStructure.pendingPreKey.HasField("preKeyId"): preKeyId = self.sessionStructure.pendingPreKey.preKeyId return SessionState.UnacknowledgedPreKeyMessageItems(preKeyId, self.sessionStructure.pendingPreKey.signedPreKeyId, Curve.decodePoint(bytearray(self.sessionStructure.pendingPreKey\ .baseKey), 0)) def clearUnacknowledgedPreKeyMessage(self): self.sessionStructure.ClearField("pendingPreKey") def setRemoteRegistrationId(self, registrationId): self.sessionStructure.remoteRegistrationId = registrationId def getRemoteRegistrationId(self, registrationId): return self.sessionStructure.remoteRegistrationId def setLocalRegistrationId(self, registrationId): self.sessionStructure.localRegistrationId = registrationId def getLocalRegistrationId(self): return self.sessionStructure.localRegistrationId def serialize(self): return self.sessionStructure.SerializeToString() class UnacknowledgedPreKeyMessageItems: def __init__(self, preKeyId, signedPreKeyId, baseKey): """ :type preKeyId: int :type signedPreKeyId: int :type baseKey: ECPublicKey """ self.preKeyId = preKeyId self.signedPreKeyId = signedPreKeyId self.baseKey = baseKey def getPreKeyId(self): return self.preKeyId def getSignedPreKeyId(self): return self.signedPreKeyId def getBaseKey(self): return self.baseKey python-axolotl-0.1.7/axolotl/state/sessionstore.py0000777000000000000000000000106512445570702022411 0ustar rootroot00000000000000import abc class SessionStore(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def loadSession(self, recepientId, deviceId):pass @abc.abstractmethod def getSubDeviceSessions(self, recepientId): pass @abc.abstractmethod def storeSession(self, recepientId, deviceId, sessionRecord):pass @abc.abstractmethod def containsSession(self, recepientId, deviceId): pass @abc.abstractmethod def deleteSession(self, recepientId, deviceId): pass @abc.abstractmethod def deleteAllSessions(self, recepientId): passpython-axolotl-0.1.7/axolotl/state/signedprekeyrecord.py0000777000000000000000000000226012447773471023551 0ustar rootroot00000000000000from .storageprotos import SignedPreKeyRecordStructure from ..ecc.curve import Curve from ..ecc.eckeypair import ECKeyPair class SignedPreKeyRecord: def __init__(self, _id = None, timestamp = None, ecKeyPair = None, signature = None, serialized = None): self.structure = SignedPreKeyRecordStructure() if serialized: self.structure.ParseFromString(serialized) else: self.structure.id = _id self.structure.publicKey = ecKeyPair.getPublicKey().serialize() self.structure.privateKey = ecKeyPair.getPrivateKey().serialize() self.structure.signature = signature self.structure.timestamp = timestamp def getId(self): return self.structure.id def getTimestamp(self): return self.structure.timestamp def getKeyPair(self): publicKey = Curve.decodePoint(bytearray(self.structure.publicKey), 0) privateKey = Curve.decodePrivatePoint(bytearray(self.structure.privateKey)) return ECKeyPair(publicKey, privateKey) def getSignature(self): return self.structure.signature def serialize(self): return self.structure.SerializeToString()python-axolotl-0.1.7/axolotl/state/signedprekeystore.py0000777000000000000000000000073312445571362023423 0ustar rootroot00000000000000import abc class SignedPreKeyStore(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def loadSignedPreKey(self, signedPreKeyId):pass @abc.abstractmethod def loadSignedPreKeys(self):pass @abc.abstractmethod def storeSignedPreKey(self, signedPreKeyId, signedPreKeyRecord): pass @abc.abstractmethod def containsSignedPreKey(self, signedPreKeyId): pass @abc.abstractmethod def removeSignedPreKey(self, signedPreKeyId): passpython-axolotl-0.1.7/axolotl/state/storageprotos.py0000777000000000000000000011323612447773374022604 0ustar rootroot00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: LocalStorageProtocol.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='LocalStorageProtocol.proto', package='textsecure', serialized_pb=_b('\n\x1aLocalStorageProtocol.proto\x12\ntextsecure\"\xd3\x08\n\x10SessionStructure\x12\x16\n\x0esessionVersion\x18\x01 \x01(\r\x12\x1b\n\x13localIdentityPublic\x18\x02 \x01(\x0c\x12\x1c\n\x14remoteIdentityPublic\x18\x03 \x01(\x0c\x12\x0f\n\x07rootKey\x18\x04 \x01(\x0c\x12\x17\n\x0fpreviousCounter\x18\x05 \x01(\r\x12\x37\n\x0bsenderChain\x18\x06 \x01(\x0b\x32\".textsecure.SessionStructure.Chain\x12:\n\x0ereceiverChains\x18\x07 \x03(\x0b\x32\".textsecure.SessionStructure.Chain\x12K\n\x12pendingKeyExchange\x18\x08 \x01(\x0b\x32/.textsecure.SessionStructure.PendingKeyExchange\x12\x41\n\rpendingPreKey\x18\t \x01(\x0b\x32*.textsecure.SessionStructure.PendingPreKey\x12\x1c\n\x14remoteRegistrationId\x18\n \x01(\r\x12\x1b\n\x13localRegistrationId\x18\x0b \x01(\r\x12\x14\n\x0cneedsRefresh\x18\x0c \x01(\x08\x12\x14\n\x0c\x61liceBaseKey\x18\r \x01(\x0c\x1a\xb9\x02\n\x05\x43hain\x12\x18\n\x10senderRatchetKey\x18\x01 \x01(\x0c\x12\x1f\n\x17senderRatchetKeyPrivate\x18\x02 \x01(\x0c\x12=\n\x08\x63hainKey\x18\x03 \x01(\x0b\x32+.textsecure.SessionStructure.Chain.ChainKey\x12\x42\n\x0bmessageKeys\x18\x04 \x03(\x0b\x32-.textsecure.SessionStructure.Chain.MessageKey\x1a&\n\x08\x43hainKey\x12\r\n\x05index\x18\x01 \x01(\r\x12\x0b\n\x03key\x18\x02 \x01(\x0c\x1aJ\n\nMessageKey\x12\r\n\x05index\x18\x01 \x01(\r\x12\x11\n\tcipherKey\x18\x02 \x01(\x0c\x12\x0e\n\x06macKey\x18\x03 \x01(\x0c\x12\n\n\x02iv\x18\x04 \x01(\x0c\x1a\xcd\x01\n\x12PendingKeyExchange\x12\x10\n\x08sequence\x18\x01 \x01(\r\x12\x14\n\x0clocalBaseKey\x18\x02 \x01(\x0c\x12\x1b\n\x13localBaseKeyPrivate\x18\x03 \x01(\x0c\x12\x17\n\x0flocalRatchetKey\x18\x04 \x01(\x0c\x12\x1e\n\x16localRatchetKeyPrivate\x18\x05 \x01(\x0c\x12\x18\n\x10localIdentityKey\x18\x07 \x01(\x0c\x12\x1f\n\x17localIdentityKeyPrivate\x18\x08 \x01(\x0c\x1aJ\n\rPendingPreKey\x12\x10\n\x08preKeyId\x18\x01 \x01(\r\x12\x16\n\x0esignedPreKeyId\x18\x03 \x01(\x05\x12\x0f\n\x07\x62\x61seKey\x18\x02 \x01(\x0c\"\x7f\n\x0fRecordStructure\x12\x34\n\x0e\x63urrentSession\x18\x01 \x01(\x0b\x32\x1c.textsecure.SessionStructure\x12\x36\n\x10previousSessions\x18\x02 \x03(\x0b\x32\x1c.textsecure.SessionStructure\"J\n\x15PreKeyRecordStructure\x12\n\n\x02id\x18\x01 \x01(\r\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\x12\x12\n\nprivateKey\x18\x03 \x01(\x0c\"v\n\x1bSignedPreKeyRecordStructure\x12\n\n\x02id\x18\x01 \x01(\r\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\x12\x12\n\nprivateKey\x18\x03 \x01(\x0c\x12\x11\n\tsignature\x18\x04 \x01(\x0c\x12\x11\n\ttimestamp\x18\x05 \x01(\x06\"A\n\x18IdentityKeyPairStructure\x12\x11\n\tpublicKey\x18\x01 \x01(\x0c\x12\x12\n\nprivateKey\x18\x02 \x01(\x0c\"\xb8\x03\n\x17SenderKeyStateStructure\x12\x13\n\x0bsenderKeyId\x18\x01 \x01(\r\x12J\n\x0esenderChainKey\x18\x02 \x01(\x0b\x32\x32.textsecure.SenderKeyStateStructure.SenderChainKey\x12N\n\x10senderSigningKey\x18\x03 \x01(\x0b\x32\x34.textsecure.SenderKeyStateStructure.SenderSigningKey\x12O\n\x11senderMessageKeys\x18\x04 \x03(\x0b\x32\x34.textsecure.SenderKeyStateStructure.SenderMessageKey\x1a\x31\n\x0eSenderChainKey\x12\x11\n\titeration\x18\x01 \x01(\r\x12\x0c\n\x04seed\x18\x02 \x01(\x0c\x1a\x33\n\x10SenderMessageKey\x12\x11\n\titeration\x18\x01 \x01(\r\x12\x0c\n\x04seed\x18\x02 \x01(\x0c\x1a\x33\n\x10SenderSigningKey\x12\x0e\n\x06public\x18\x01 \x01(\x0c\x12\x0f\n\x07private\x18\x02 \x01(\x0c\"X\n\x18SenderKeyRecordStructure\x12<\n\x0fsenderKeyStates\x18\x01 \x03(\x0b\x32#.textsecure.SenderKeyStateStructureB4\n#org.whispersystems.libaxolotl.stateB\rStorageProtos') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) _SESSIONSTRUCTURE_CHAIN_CHAINKEY = _descriptor.Descriptor( name='ChainKey', full_name='textsecure.SessionStructure.Chain.ChainKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='index', full_name='textsecure.SessionStructure.Chain.ChainKey.index', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='key', full_name='textsecure.SessionStructure.Chain.ChainKey.key', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=752, serialized_end=790, ) _SESSIONSTRUCTURE_CHAIN_MESSAGEKEY = _descriptor.Descriptor( name='MessageKey', full_name='textsecure.SessionStructure.Chain.MessageKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='index', full_name='textsecure.SessionStructure.Chain.MessageKey.index', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='cipherKey', full_name='textsecure.SessionStructure.Chain.MessageKey.cipherKey', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='macKey', full_name='textsecure.SessionStructure.Chain.MessageKey.macKey', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='iv', full_name='textsecure.SessionStructure.Chain.MessageKey.iv', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=792, serialized_end=866, ) _SESSIONSTRUCTURE_CHAIN = _descriptor.Descriptor( name='Chain', full_name='textsecure.SessionStructure.Chain', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='senderRatchetKey', full_name='textsecure.SessionStructure.Chain.senderRatchetKey', index=0, number=1, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='senderRatchetKeyPrivate', full_name='textsecure.SessionStructure.Chain.senderRatchetKeyPrivate', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='chainKey', full_name='textsecure.SessionStructure.Chain.chainKey', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='messageKeys', full_name='textsecure.SessionStructure.Chain.messageKeys', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[_SESSIONSTRUCTURE_CHAIN_CHAINKEY, _SESSIONSTRUCTURE_CHAIN_MESSAGEKEY, ], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=553, serialized_end=866, ) _SESSIONSTRUCTURE_PENDINGKEYEXCHANGE = _descriptor.Descriptor( name='PendingKeyExchange', full_name='textsecure.SessionStructure.PendingKeyExchange', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='sequence', full_name='textsecure.SessionStructure.PendingKeyExchange.sequence', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localBaseKey', full_name='textsecure.SessionStructure.PendingKeyExchange.localBaseKey', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localBaseKeyPrivate', full_name='textsecure.SessionStructure.PendingKeyExchange.localBaseKeyPrivate', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localRatchetKey', full_name='textsecure.SessionStructure.PendingKeyExchange.localRatchetKey', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localRatchetKeyPrivate', full_name='textsecure.SessionStructure.PendingKeyExchange.localRatchetKeyPrivate', index=4, number=5, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localIdentityKey', full_name='textsecure.SessionStructure.PendingKeyExchange.localIdentityKey', index=5, number=7, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localIdentityKeyPrivate', full_name='textsecure.SessionStructure.PendingKeyExchange.localIdentityKeyPrivate', index=6, number=8, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=869, serialized_end=1074, ) _SESSIONSTRUCTURE_PENDINGPREKEY = _descriptor.Descriptor( name='PendingPreKey', full_name='textsecure.SessionStructure.PendingPreKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='preKeyId', full_name='textsecure.SessionStructure.PendingPreKey.preKeyId', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='signedPreKeyId', full_name='textsecure.SessionStructure.PendingPreKey.signedPreKeyId', index=1, number=3, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='baseKey', full_name='textsecure.SessionStructure.PendingPreKey.baseKey', index=2, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1076, serialized_end=1150, ) _SESSIONSTRUCTURE = _descriptor.Descriptor( name='SessionStructure', full_name='textsecure.SessionStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='sessionVersion', full_name='textsecure.SessionStructure.sessionVersion', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localIdentityPublic', full_name='textsecure.SessionStructure.localIdentityPublic', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='remoteIdentityPublic', full_name='textsecure.SessionStructure.remoteIdentityPublic', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='rootKey', full_name='textsecure.SessionStructure.rootKey', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='previousCounter', full_name='textsecure.SessionStructure.previousCounter', index=4, number=5, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='senderChain', full_name='textsecure.SessionStructure.senderChain', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='receiverChains', full_name='textsecure.SessionStructure.receiverChains', index=6, number=7, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='pendingKeyExchange', full_name='textsecure.SessionStructure.pendingKeyExchange', index=7, number=8, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='pendingPreKey', full_name='textsecure.SessionStructure.pendingPreKey', index=8, number=9, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='remoteRegistrationId', full_name='textsecure.SessionStructure.remoteRegistrationId', index=9, number=10, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='localRegistrationId', full_name='textsecure.SessionStructure.localRegistrationId', index=10, number=11, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='needsRefresh', full_name='textsecure.SessionStructure.needsRefresh', index=11, number=12, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='aliceBaseKey', full_name='textsecure.SessionStructure.aliceBaseKey', index=12, number=13, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[_SESSIONSTRUCTURE_CHAIN, _SESSIONSTRUCTURE_PENDINGKEYEXCHANGE, _SESSIONSTRUCTURE_PENDINGPREKEY, ], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=43, serialized_end=1150, ) _RECORDSTRUCTURE = _descriptor.Descriptor( name='RecordStructure', full_name='textsecure.RecordStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='currentSession', full_name='textsecure.RecordStructure.currentSession', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='previousSessions', full_name='textsecure.RecordStructure.previousSessions', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1152, serialized_end=1279, ) _PREKEYRECORDSTRUCTURE = _descriptor.Descriptor( name='PreKeyRecordStructure', full_name='textsecure.PreKeyRecordStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='id', full_name='textsecure.PreKeyRecordStructure.id', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='publicKey', full_name='textsecure.PreKeyRecordStructure.publicKey', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='privateKey', full_name='textsecure.PreKeyRecordStructure.privateKey', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1281, serialized_end=1355, ) _SIGNEDPREKEYRECORDSTRUCTURE = _descriptor.Descriptor( name='SignedPreKeyRecordStructure', full_name='textsecure.SignedPreKeyRecordStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='id', full_name='textsecure.SignedPreKeyRecordStructure.id', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='publicKey', full_name='textsecure.SignedPreKeyRecordStructure.publicKey', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='privateKey', full_name='textsecure.SignedPreKeyRecordStructure.privateKey', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='signature', full_name='textsecure.SignedPreKeyRecordStructure.signature', index=3, number=4, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='timestamp', full_name='textsecure.SignedPreKeyRecordStructure.timestamp', index=4, number=5, type=6, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1357, serialized_end=1475, ) _IDENTITYKEYPAIRSTRUCTURE = _descriptor.Descriptor( name='IdentityKeyPairStructure', full_name='textsecure.IdentityKeyPairStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='publicKey', full_name='textsecure.IdentityKeyPairStructure.publicKey', index=0, number=1, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='privateKey', full_name='textsecure.IdentityKeyPairStructure.privateKey', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1477, serialized_end=1542, ) _SENDERKEYSTATESTRUCTURE_SENDERCHAINKEY = _descriptor.Descriptor( name='SenderChainKey', full_name='textsecure.SenderKeyStateStructure.SenderChainKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='iteration', full_name='textsecure.SenderKeyStateStructure.SenderChainKey.iteration', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='seed', full_name='textsecure.SenderKeyStateStructure.SenderChainKey.seed', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1830, serialized_end=1879, ) _SENDERKEYSTATESTRUCTURE_SENDERMESSAGEKEY = _descriptor.Descriptor( name='SenderMessageKey', full_name='textsecure.SenderKeyStateStructure.SenderMessageKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='iteration', full_name='textsecure.SenderKeyStateStructure.SenderMessageKey.iteration', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='seed', full_name='textsecure.SenderKeyStateStructure.SenderMessageKey.seed', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1881, serialized_end=1932, ) _SENDERKEYSTATESTRUCTURE_SENDERSIGNINGKEY = _descriptor.Descriptor( name='SenderSigningKey', full_name='textsecure.SenderKeyStateStructure.SenderSigningKey', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='public', full_name='textsecure.SenderKeyStateStructure.SenderSigningKey.public', index=0, number=1, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='private', full_name='textsecure.SenderKeyStateStructure.SenderSigningKey.private', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1934, serialized_end=1985, ) _SENDERKEYSTATESTRUCTURE = _descriptor.Descriptor( name='SenderKeyStateStructure', full_name='textsecure.SenderKeyStateStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='senderKeyId', full_name='textsecure.SenderKeyStateStructure.senderKeyId', index=0, number=1, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='senderChainKey', full_name='textsecure.SenderKeyStateStructure.senderChainKey', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='senderSigningKey', full_name='textsecure.SenderKeyStateStructure.senderSigningKey', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( name='senderMessageKeys', full_name='textsecure.SenderKeyStateStructure.senderMessageKeys', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[_SENDERKEYSTATESTRUCTURE_SENDERCHAINKEY, _SENDERKEYSTATESTRUCTURE_SENDERMESSAGEKEY, _SENDERKEYSTATESTRUCTURE_SENDERSIGNINGKEY, ], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1545, serialized_end=1985, ) _SENDERKEYRECORDSTRUCTURE = _descriptor.Descriptor( name='SenderKeyRecordStructure', full_name='textsecure.SenderKeyRecordStructure', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='senderKeyStates', full_name='textsecure.SenderKeyRecordStructure.senderKeyStates', index=0, number=1, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), ], extensions=[ ], nested_types=[], enum_types=[ ], options=None, is_extendable=False, extension_ranges=[], oneofs=[ ], serialized_start=1987, serialized_end=2075, ) _SESSIONSTRUCTURE_CHAIN_CHAINKEY.containing_type = _SESSIONSTRUCTURE_CHAIN _SESSIONSTRUCTURE_CHAIN_MESSAGEKEY.containing_type = _SESSIONSTRUCTURE_CHAIN _SESSIONSTRUCTURE_CHAIN.fields_by_name['chainKey'].message_type = _SESSIONSTRUCTURE_CHAIN_CHAINKEY _SESSIONSTRUCTURE_CHAIN.fields_by_name['messageKeys'].message_type = _SESSIONSTRUCTURE_CHAIN_MESSAGEKEY _SESSIONSTRUCTURE_CHAIN.containing_type = _SESSIONSTRUCTURE _SESSIONSTRUCTURE_PENDINGKEYEXCHANGE.containing_type = _SESSIONSTRUCTURE _SESSIONSTRUCTURE_PENDINGPREKEY.containing_type = _SESSIONSTRUCTURE _SESSIONSTRUCTURE.fields_by_name['senderChain'].message_type = _SESSIONSTRUCTURE_CHAIN _SESSIONSTRUCTURE.fields_by_name['receiverChains'].message_type = _SESSIONSTRUCTURE_CHAIN _SESSIONSTRUCTURE.fields_by_name['pendingKeyExchange'].message_type = _SESSIONSTRUCTURE_PENDINGKEYEXCHANGE _SESSIONSTRUCTURE.fields_by_name['pendingPreKey'].message_type = _SESSIONSTRUCTURE_PENDINGPREKEY _RECORDSTRUCTURE.fields_by_name['currentSession'].message_type = _SESSIONSTRUCTURE _RECORDSTRUCTURE.fields_by_name['previousSessions'].message_type = _SESSIONSTRUCTURE _SENDERKEYSTATESTRUCTURE_SENDERCHAINKEY.containing_type = _SENDERKEYSTATESTRUCTURE _SENDERKEYSTATESTRUCTURE_SENDERMESSAGEKEY.containing_type = _SENDERKEYSTATESTRUCTURE _SENDERKEYSTATESTRUCTURE_SENDERSIGNINGKEY.containing_type = _SENDERKEYSTATESTRUCTURE _SENDERKEYSTATESTRUCTURE.fields_by_name['senderChainKey'].message_type = _SENDERKEYSTATESTRUCTURE_SENDERCHAINKEY _SENDERKEYSTATESTRUCTURE.fields_by_name['senderSigningKey'].message_type = _SENDERKEYSTATESTRUCTURE_SENDERSIGNINGKEY _SENDERKEYSTATESTRUCTURE.fields_by_name['senderMessageKeys'].message_type = _SENDERKEYSTATESTRUCTURE_SENDERMESSAGEKEY _SENDERKEYRECORDSTRUCTURE.fields_by_name['senderKeyStates'].message_type = _SENDERKEYSTATESTRUCTURE DESCRIPTOR.message_types_by_name['SessionStructure'] = _SESSIONSTRUCTURE DESCRIPTOR.message_types_by_name['RecordStructure'] = _RECORDSTRUCTURE DESCRIPTOR.message_types_by_name['PreKeyRecordStructure'] = _PREKEYRECORDSTRUCTURE DESCRIPTOR.message_types_by_name['SignedPreKeyRecordStructure'] = _SIGNEDPREKEYRECORDSTRUCTURE DESCRIPTOR.message_types_by_name['IdentityKeyPairStructure'] = _IDENTITYKEYPAIRSTRUCTURE DESCRIPTOR.message_types_by_name['SenderKeyStateStructure'] = _SENDERKEYSTATESTRUCTURE DESCRIPTOR.message_types_by_name['SenderKeyRecordStructure'] = _SENDERKEYRECORDSTRUCTURE SessionStructure = _reflection.GeneratedProtocolMessageType('SessionStructure', (_message.Message,), dict( Chain = _reflection.GeneratedProtocolMessageType('Chain', (_message.Message,), dict( ChainKey = _reflection.GeneratedProtocolMessageType('ChainKey', (_message.Message,), dict( DESCRIPTOR = _SESSIONSTRUCTURE_CHAIN_CHAINKEY, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SessionStructure.Chain.ChainKey) )) , MessageKey = _reflection.GeneratedProtocolMessageType('MessageKey', (_message.Message,), dict( DESCRIPTOR = _SESSIONSTRUCTURE_CHAIN_MESSAGEKEY, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SessionStructure.Chain.MessageKey) )) , DESCRIPTOR = _SESSIONSTRUCTURE_CHAIN, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SessionStructure.Chain) )) , PendingKeyExchange = _reflection.GeneratedProtocolMessageType('PendingKeyExchange', (_message.Message,), dict( DESCRIPTOR = _SESSIONSTRUCTURE_PENDINGKEYEXCHANGE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SessionStructure.PendingKeyExchange) )) , PendingPreKey = _reflection.GeneratedProtocolMessageType('PendingPreKey', (_message.Message,), dict( DESCRIPTOR = _SESSIONSTRUCTURE_PENDINGPREKEY, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SessionStructure.PendingPreKey) )) , DESCRIPTOR = _SESSIONSTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SessionStructure) )) _sym_db.RegisterMessage(SessionStructure) _sym_db.RegisterMessage(SessionStructure.Chain) _sym_db.RegisterMessage(SessionStructure.Chain.ChainKey) _sym_db.RegisterMessage(SessionStructure.Chain.MessageKey) _sym_db.RegisterMessage(SessionStructure.PendingKeyExchange) _sym_db.RegisterMessage(SessionStructure.PendingPreKey) RecordStructure = _reflection.GeneratedProtocolMessageType('RecordStructure', (_message.Message,), dict( DESCRIPTOR = _RECORDSTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.RecordStructure) )) _sym_db.RegisterMessage(RecordStructure) PreKeyRecordStructure = _reflection.GeneratedProtocolMessageType('PreKeyRecordStructure', (_message.Message,), dict( DESCRIPTOR = _PREKEYRECORDSTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.PreKeyRecordStructure) )) _sym_db.RegisterMessage(PreKeyRecordStructure) SignedPreKeyRecordStructure = _reflection.GeneratedProtocolMessageType('SignedPreKeyRecordStructure', (_message.Message,), dict( DESCRIPTOR = _SIGNEDPREKEYRECORDSTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SignedPreKeyRecordStructure) )) _sym_db.RegisterMessage(SignedPreKeyRecordStructure) IdentityKeyPairStructure = _reflection.GeneratedProtocolMessageType('IdentityKeyPairStructure', (_message.Message,), dict( DESCRIPTOR = _IDENTITYKEYPAIRSTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.IdentityKeyPairStructure) )) _sym_db.RegisterMessage(IdentityKeyPairStructure) SenderKeyStateStructure = _reflection.GeneratedProtocolMessageType('SenderKeyStateStructure', (_message.Message,), dict( SenderChainKey = _reflection.GeneratedProtocolMessageType('SenderChainKey', (_message.Message,), dict( DESCRIPTOR = _SENDERKEYSTATESTRUCTURE_SENDERCHAINKEY, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyStateStructure.SenderChainKey) )) , SenderMessageKey = _reflection.GeneratedProtocolMessageType('SenderMessageKey', (_message.Message,), dict( DESCRIPTOR = _SENDERKEYSTATESTRUCTURE_SENDERMESSAGEKEY, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyStateStructure.SenderMessageKey) )) , SenderSigningKey = _reflection.GeneratedProtocolMessageType('SenderSigningKey', (_message.Message,), dict( DESCRIPTOR = _SENDERKEYSTATESTRUCTURE_SENDERSIGNINGKEY, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyStateStructure.SenderSigningKey) )) , DESCRIPTOR = _SENDERKEYSTATESTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyStateStructure) )) _sym_db.RegisterMessage(SenderKeyStateStructure) _sym_db.RegisterMessage(SenderKeyStateStructure.SenderChainKey) _sym_db.RegisterMessage(SenderKeyStateStructure.SenderMessageKey) _sym_db.RegisterMessage(SenderKeyStateStructure.SenderSigningKey) SenderKeyRecordStructure = _reflection.GeneratedProtocolMessageType('SenderKeyRecordStructure', (_message.Message,), dict( DESCRIPTOR = _SENDERKEYRECORDSTRUCTURE, __module__ = 'LocalStorageProtocol_pb2' # @@protoc_insertion_point(class_scope:textsecure.SenderKeyRecordStructure) )) _sym_db.RegisterMessage(SenderKeyRecordStructure) DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n#org.whispersystems.libaxolotl.stateB\rStorageProtos')) # @@protoc_insertion_point(module_scope) python-axolotl-0.1.7/axolotl/state/__init__.py0000777000000000000000000000000012454325147021375 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/statekeyexchangeexception.py0000777000000000000000000000006412447423010023771 0ustar rootroot00000000000000class StaleKeyExchangeException(Exception): passpython-axolotl-0.1.7/axolotl/tests/0000777000000000000000000000000012521166655017317 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/tests/groups/0000777000000000000000000000000012521166655020636 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/tests/groups/inmemorysenderkeystore.py0000777000000000000000000000102312454073424026031 0ustar rootroot00000000000000from axolotl.groups.state.senderkeystore import SenderKeyStore from axolotl.groups.state.senderkeyrecord import SenderKeyRecord class InMemorySenderKeyStore(SenderKeyStore): def __init__(self): self.store = {} def storeSenderKey(self, senderKeyId, senderKeyRecord): self.store[senderKeyId] = senderKeyRecord def loadSenderKey(self, senderKeyId): if senderKeyId in self.store: return SenderKeyRecord(serialized=self.store[senderKeyId].serialize()) return SenderKeyRecord() python-axolotl-0.1.7/axolotl/tests/groups/test_groupcipher.py0000777000000000000000000001150212454310070024563 0ustar rootroot00000000000000import unittest from axolotl.tests.groups.inmemorysenderkeystore import InMemorySenderKeyStore from axolotl.groups.groupsessionbuilder import GroupSessionBuilder from axolotl.util.keyhelper import KeyHelper from axolotl.groups.groupcipher import GroupCipher from axolotl.duplicatemessagexception import DuplicateMessageException from axolotl.nosessionexception import NoSessionException class GroupCipherTest(unittest.TestCase): def test_basicEncryptDecrypt(self): aliceStore = InMemorySenderKeyStore() bobStore = InMemorySenderKeyStore() aliceSessionBuilder = GroupSessionBuilder(aliceStore) bobSessionBuilder = GroupSessionBuilder(bobStore) aliceGroupCipher = GroupCipher(aliceStore, "groupWithBobInIt") bobGroupCipher = GroupCipher(bobStore, "groupWithBobInIt::aliceUserName") aliceSenderKey = KeyHelper.generateSenderKey() aliceSenderSigningKey = KeyHelper.generateSenderSigningKey() aliceSenderKeyId = KeyHelper.generateSenderKeyId() aliceDistributionMessage = aliceSessionBuilder.process("groupWithBobInIt", aliceSenderKeyId, 0, aliceSenderKey, aliceSenderSigningKey) bobSessionBuilder.processSender("groupWithBobInIt::aliceUserName", aliceDistributionMessage) ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert") plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice) self.assertEqual(plaintextFromAlice, "smert ze smert") def test_basicRatchet(self): aliceStore = InMemorySenderKeyStore() bobStore = InMemorySenderKeyStore() aliceSessionBuilder = GroupSessionBuilder(aliceStore) bobSessionBuilder = GroupSessionBuilder(bobStore) aliceGroupCipher = GroupCipher(aliceStore, "groupWithBobInIt") bobGroupCipher = GroupCipher(bobStore, "groupWithBobInIt::aliceUserName") aliceSenderKey = KeyHelper.generateSenderKey() aliceSenderSigningKey = KeyHelper.generateSenderSigningKey() aliceSenderKeyId = KeyHelper.generateSenderKeyId() aliceDistributionMessage = aliceSessionBuilder.process("groupWithBobInIt", aliceSenderKeyId, 0, aliceSenderKey, aliceSenderSigningKey) bobSessionBuilder.processSender("groupWithBobInIt::aliceUserName", aliceDistributionMessage) ciphertextFromAlice = aliceGroupCipher.encrypt("smert ze smert") ciphertextFromAlice2 = aliceGroupCipher.encrypt("smert ze smert2") ciphertextFromAlice3 = aliceGroupCipher.encrypt("smert ze smert3") plaintextFromAlice = bobGroupCipher.decrypt(ciphertextFromAlice) try: bobGroupCipher.decrypt(ciphertextFromAlice) raise AssertionError("Should have ratcheted forward!") except DuplicateMessageException as dme: # good pass plaintextFromAlice2 = bobGroupCipher.decrypt(ciphertextFromAlice2) plaintextFromAlice3 = bobGroupCipher.decrypt(ciphertextFromAlice3) self.assertEqual(plaintextFromAlice,"smert ze smert") self.assertEqual(plaintextFromAlice2, "smert ze smert2") self.assertEqual(plaintextFromAlice3, "smert ze smert3") def test_outOfOrder(self): aliceStore = InMemorySenderKeyStore() bobStore = InMemorySenderKeyStore() aliceSessionBuilder = GroupSessionBuilder(aliceStore) bobSessionBuilder = GroupSessionBuilder(bobStore) aliceGroupCipher = GroupCipher(aliceStore, "groupWithBobInIt") bobGroupCipher = GroupCipher(bobStore, "groupWithBobInIt::aliceUserName") aliceSenderKey = KeyHelper.generateSenderKey() aliceSenderSigningKey = KeyHelper.generateSenderSigningKey() aliceSenderKeyId = KeyHelper.generateSenderKeyId() aliceDistributionMessage = aliceSessionBuilder.process("groupWithBobInIt", aliceSenderKeyId, 0, aliceSenderKey, aliceSenderSigningKey) bobSessionBuilder.processSender("groupWithBobInIt::aliceUserName", aliceDistributionMessage) ciphertexts = [] for i in range(0, 100): ciphertexts.append(aliceGroupCipher.encrypt("up the punks")) while len(ciphertexts) > 0: index = KeyHelper.getRandomSequence(2147483647) % len(ciphertexts) ciphertext = ciphertexts.pop(index) plaintext = bobGroupCipher.decrypt(ciphertext) self.assertEqual(plaintext, "up the punks") def test_encryptNoSession(self): aliceStore = InMemorySenderKeyStore() aliceGroupCipher = GroupCipher(aliceStore, "groupWithBobInIt") try: aliceGroupCipher.encrypt("up the punks") raise AssertionError("Should have failed!") except NoSessionException as nse: # good pass python-axolotl-0.1.7/axolotl/tests/groups/__init__.py0000777000000000000000000000000012445444220022730 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/tests/inmemoryaxolotlstore.py0000777000000000000000000000537012454071626024216 0ustar rootroot00000000000000from axolotl.state.axolotlstore import AxolotlStore from axolotl.tests.inmemoryidentitykeystore import InMemoryIdentityKeyStore from axolotl.tests.inmemoryprekeystore import InMemoryPreKeyStore from axolotl.tests.inmemorysessionstore import InMemorySessionStore from axolotl.tests.inmemorysignedprekeystore import InMemorySignedPreKeyStore class InMemoryAxolotlStore(AxolotlStore): def __init__(self): self.identityKeyStore = InMemoryIdentityKeyStore() self.preKeyStore = InMemoryPreKeyStore() self.signedPreKeyStore = InMemorySignedPreKeyStore() self.sessionStore = InMemorySessionStore() def getIdentityKeyPair(self): return self.identityKeyStore.getIdentityKeyPair() def getLocalRegistrationId(self): return self.identityKeyStore.getLocalRegistrationId() def saveIdentity(self, recepientId, identityKey): self.identityKeyStore.saveIdentity(recepientId, identityKey) def isTrustedIdentity(self, recepientId, identityKey): return self.identityKeyStore.isTrustedIdentity(recepientId, identityKey) def loadPreKey(self, preKeyId): return self.preKeyStore.loadPreKey(preKeyId) def storePreKey(self, preKeyId, preKeyRecord): self.preKeyStore.storePreKey(preKeyId, preKeyRecord) def containsPreKey(self, preKeyId): return self.preKeyStore.containsPreKey(preKeyId) def removePreKey(self, preKeyId): self.preKeyStore.removePreKey(preKeyId) def loadSession(self, recepientId, deviceId): return self.sessionStore.loadSession(recepientId, deviceId) def getSubDeviceSessions(self, recepientId): return self.sessionStore.getSubDeviceSessions(recepientId) def storeSession(self, recepientId, deviceId, sessionRecord): self.sessionStore.storeSession(recepientId, deviceId, sessionRecord) def containsSession(self, recepientId, deviceId): return self.sessionStore.containsSession(recepientId, deviceId) def deleteSession(self, recepientId, deviceId): self.sessionStore.deleteSession(recepientId, deviceId) def deleteAllSessions(self, recepientId): self.sessionStore.deleteAllSessions(recepientId) def loadSignedPreKey(self, signedPreKeyId): return self.signedPreKeyStore.loadSignedPreKey(signedPreKeyId) def loadSignedPreKeys(self): return self.signedPreKeyStore.loadSignedPreKeys() def storeSignedPreKey(self, signedPreKeyId, signedPreKeyRecord): self.signedPreKeyStore.storeSignedPreKey(signedPreKeyId, signedPreKeyRecord) def containsSignedPreKey(self, signedPreKeyId): return self.signedPreKeyStore.containsSignedPreKey(signedPreKeyId) def removeSignedPreKey(self, signedPreKeyId): return self.signedPreKeyStore.containsSignedPreKey() python-axolotl-0.1.7/axolotl/tests/inmemoryidentitykeystore.py0000777000000000000000000000210512446525622025070 0ustar rootroot00000000000000from axolotl.state.identitykeystore import IdentityKeyStore from axolotl.ecc.curve import Curve from axolotl.identitykey import IdentityKey from axolotl.util.keyhelper import KeyHelper from axolotl.identitykeypair import IdentityKeyPair class InMemoryIdentityKeyStore(IdentityKeyStore): def __init__(self): self.trustedKeys = {} identityKeyPairKeys = Curve.generateKeyPair() self.identityKeyPair = IdentityKeyPair(IdentityKey(identityKeyPairKeys.getPublicKey()), identityKeyPairKeys.getPrivateKey()) self.localRegistrationId = KeyHelper.generateRegistrationId() def getIdentityKeyPair(self): return self.identityKeyPair def getLocalRegistrationId(self): return self.localRegistrationId def saveIdentity(self, recepientId, identityKey): self.trustedKeys[recepientId] = identityKey def isTrustedIdentity(self, recepientId, identityKey): if recepientId not in self.trustedKeys: return True return self.trustedKeys[recepientId] == identityKeypython-axolotl-0.1.7/axolotl/tests/inmemoryprekeystore.py0000777000000000000000000000136412447400730024024 0ustar rootroot00000000000000from axolotl.state.prekeystore import PreKeyStore from axolotl.state.prekeyrecord import PreKeyRecord from axolotl.invalidkeyidexception import InvalidKeyIdException class InMemoryPreKeyStore(PreKeyStore): def __init__(self): self.store = {} def loadPreKey(self, preKeyId): if preKeyId not in self.store: raise InvalidKeyIdException("No such prekeyRecord!") return PreKeyRecord(serialized = self.store[preKeyId]) def storePreKey(self, preKeyId, preKeyRecord): self.store[preKeyId] = preKeyRecord.serialize() def containsPreKey(self, preKeyId): return preKeyId in self.store def removePreKey(self, preKeyId): if preKeyId in self.store: del self.store[preKeyId]python-axolotl-0.1.7/axolotl/tests/inmemorysessionstore.py0000777000000000000000000000222412446411136024205 0ustar rootroot00000000000000from axolotl.state.sessionstore import SessionStore from axolotl.state.sessionrecord import SessionRecord class InMemorySessionStore(SessionStore): def __init__(self): self.sessions = {} def loadSession(self, recepientId, deviceId): if self.containsSession(recepientId, deviceId): return SessionRecord(serialized=self.sessions[(recepientId, deviceId)]) else: return SessionRecord() def getSubDeviceSessions(self, recepientId): deviceIds = [] for k in self.sessions.keys(): if k[0] == recepientId: deviceIds.append(k[1]) return deviceIds def storeSession(self, recepientId, deviceId, sessionRecord): self.sessions[(recepientId, deviceId)] = sessionRecord.serialize() def containsSession(self, recepientId, deviceId): return (recepientId, deviceId) in self.sessions def deleteSession(self, recepientId, deviceId): del self.sessions[(recepientId, deviceId)] def deleteAllSessions(self, recepientId): for k in self.sessions.keys(): if k[0] == recepientId: del self.sessions[k] python-axolotl-0.1.7/axolotl/tests/inmemorysignedprekeystore.py0000777000000000000000000000205612447404741025223 0ustar rootroot00000000000000from axolotl.state.signedprekeystore import SignedPreKeyStore from axolotl.state.signedprekeyrecord import SignedPreKeyRecord from axolotl.invalidkeyidexception import InvalidKeyIdException class InMemorySignedPreKeyStore(SignedPreKeyStore): def __init__(self): self.store = {} def loadSignedPreKey(self, signedPreKeyId): if not signedPreKeyId in self.store: raise InvalidKeyIdException("No such signedprekeyrecord! %s " % signedPreKeyId) return SignedPreKeyRecord(serialized=self.store[signedPreKeyId]) def loadSignedPreKeys(self): results = [] for serialized in self.store.values(): results.append(SignedPreKeyRecord(serialized=serialized)) return results def storeSignedPreKey(self, signedPreKeyId, signedPreKeyRecord): self.store[signedPreKeyId] = signedPreKeyRecord.serialize() def containsSignedPreKey(self, signedPreKeyId): return signedPreKeyId in self.store def removeSignedPreKey(self, signedPreKeyId): del self.store[signedPreKeyId]python-axolotl-0.1.7/axolotl/tests/kdf/0000777000000000000000000000000012521166655020063 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/tests/kdf/test_hkdf.py0000777000000000000000000001306412450010366022403 0ustar rootroot00000000000000import unittest from axolotl.kdf.hkdf import HKDF class HKDFTest(unittest.TestCase): def test_vectorV3(self): ikm = bytearray([0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b]) salt = bytearray([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c]) info = bytearray([0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9]) okm = bytearray([0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65]) actualOutput = HKDF.createFor(3).deriveSecrets(ikm, info, 42, salt = salt) self.assertEqual(okm, actualOutput) def test_vectorLongV3(self): ikm = bytearray([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f]) salt = bytearray([0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf]) info = bytearray([0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]) okm = bytearray([0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87]) actualOutput = HKDF.createFor(3).deriveSecrets(ikm, info, 82, salt = salt); self.assertEqual(okm, actualOutput) def test_vectorV3(self): ikm = bytearray([0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b]) salt = bytearray([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c]) info = bytearray([0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9]) okm = bytearray([0x6e, 0xc2, 0x55, 0x6d, 0x5d, 0x7b, 0x1d, 0x81, 0xde, 0xe4, 0x22, 0x2a, 0xd7, 0x48, 0x36, 0x95, 0xdd, 0xc9, 0x8f, 0x4f, 0x5f, 0xab, 0xc0, 0xe0, 0x20, 0x5d, 0xc2, 0xef, 0x87, 0x52, 0xd4, 0x1e, 0x04, 0xe2, 0xe2, 0x11, 0x01, 0xc6, 0x8f, 0xf0, 0x93, 0x94, 0xb8, 0xad, 0x0b, 0xdc, 0xb9, 0x60, 0x9c, 0xd4, 0xee, 0x82, 0xac, 0x13, 0x19, 0x9b, 0x4a, 0xa9, 0xfd, 0xa8, 0x99, 0xda, 0xeb, 0xec]) actualOutput = HKDF.createFor(2).deriveSecrets(ikm, info, 64, salt = salt) self.assertEqual(okm, actualOutput) python-axolotl-0.1.7/axolotl/tests/kdf/__init__.py0000777000000000000000000000002512445627012022166 0ustar rootroot00000000000000__author__ = 'tarek' python-axolotl-0.1.7/axolotl/tests/ratchet/0000777000000000000000000000000012521166655020751 5ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/tests/ratchet/test_chainkey.py0000777000000000000000000000443512446411227024160 0ustar rootroot00000000000000import unittest from axolotl.ratchet.chainkey import ChainKey from axolotl.kdf.hkdf import HKDF class ChainKeyTest(unittest.TestCase): def test_chainKeyDerivationV2(self): seed = bytearray([0x8a, 0xb7, 0x2d, 0x6f, 0x4c, 0xc5, 0xac, 0x0d, 0x38, 0x7e, 0xaf, 0x46, 0x33, 0x78, 0xdd, 0xb2, 0x8e, 0xdd, 0x07, 0x38, 0x5b, 0x1c, 0xb0, 0x12, 0x50, 0xc7, 0x15, 0x98, 0x2e, 0x7a, 0xd4, 0x8f]) messageKey = bytearray([0x02, 0xa9, 0xaa, 0x6c, 0x7d, 0xbd, 0x64, 0xf9, 0xd3, 0xaa, 0x92, 0xf9, 0x2a, 0x27, 0x7b, 0xf5, 0x46, 0x09, 0xda, 0xdf, 0x0b, 0x00, 0x82, 0x8a, 0xcf, 0xc6, 0x1e, 0x3c, 0x72, 0x4b, 0x84, 0xa7]) macKey = bytearray([0xbf, 0xbe, 0x5e, 0xfb, 0x60, 0x30, 0x30, 0x52, 0x67, 0x42, 0xe3, 0xee, 0x89, 0xc7, 0x02, 0x4e, 0x88, 0x4e, 0x44, 0x0f, 0x1f, 0xf3, 0x76, 0xbb, 0x23, 0x17, 0xb2, 0xd6, 0x4d, 0xeb, 0x7c, 0x83]) nextChainKey = bytearray([0x28, 0xe8, 0xf8, 0xfe, 0xe5, 0x4b, 0x80, 0x1e, 0xef, 0x7c, 0x5c, 0xfb, 0x2f, 0x17, 0xf3, 0x2c, 0x7b, 0x33, 0x44, 0x85, 0xbb, 0xb7, 0x0f, 0xac, 0x6e, 0xc1, 0x03, 0x42, 0xa2, 0x46, 0xd1, 0x5d]) chainKey = ChainKey(HKDF.createFor(2), seed, 0) self.assertEqual(chainKey.getKey(), seed) self.assertEqual(chainKey.getMessageKeys().getCipherKey(), messageKey) self.assertEqual(chainKey.getMessageKeys().getMacKey(), macKey) self.assertEqual(chainKey.getNextChainKey().getKey(), nextChainKey) self.assertEqual(chainKey.getIndex(), 0) self.assertEqual(chainKey.getMessageKeys().getCounter(), 0) self.assertEqual(chainKey.getNextChainKey().getIndex(), 1) self.assertEqual(chainKey.getNextChainKey().getMessageKeys().getCounter(), 1) python-axolotl-0.1.7/axolotl/tests/ratchet/test_ratchetingsession.py0000777000000000000000000001351012446411244026112 0ustar rootroot00000000000000import unittest from axolotl.identitykey import IdentityKey from axolotl.identitykeypair import IdentityKeyPair from axolotl.ecc.curve import Curve from axolotl.ecc.eckeypair import ECKeyPair from axolotl.ratchet.bobaxolotlparamaters import BobAxolotlParameters from axolotl.state.sessionstate import SessionState from axolotl.ratchet.ratchetingsession import RatchetingSession class RatchetingSessionTest(unittest.TestCase): def test_ratchetingSessionAsBob(self): bobPublic = bytearray([0x05, 0x2c, 0xb4, 0x97, 0x76, 0xb8, 0x77, 0x02, 0x05, 0x74, 0x5a, 0x3a, 0x6e, 0x24, 0xf5, 0x79, 0xcd, 0xb4, 0xba, 0x7a, 0x89, 0x04, 0x10, 0x05, 0x92, 0x8e, 0xbb, 0xad, 0xc9, 0xc0, 0x5a, 0xd4, 0x58]) bobPrivate = bytearray([0xa1, 0xca, 0xb4, 0x8f, 0x7c, 0x89, 0x3f, 0xaf, 0xa9, 0x88, 0x0a, 0x28, 0xc3, 0xb4, 0x99, 0x9d, 0x28, 0xd6, 0x32, 0x95, 0x62, 0xd2, 0x7a, 0x4e, 0xa4, 0xe2, 0x2e, 0x9f, 0xf1, 0xbd, 0xd6, 0x5a]) bobIdentityPublic = bytearray([0x05, 0xf1, 0xf4, 0x38, 0x74, 0xf6, 0x96, 0x69, 0x56, 0xc2, 0xdd, 0x47, 0x3f, 0x8f, 0xa1, 0x5a, 0xde, 0xb7, 0x1d, 0x1c, 0xb9, 0x91, 0xb2, 0x34, 0x16, 0x92, 0x32, 0x4c, 0xef, 0xb1, 0xc5, 0xe6, 0x26]) bobIdentityPrivate = bytearray([0x48, 0x75, 0xcc, 0x69, 0xdd, 0xf8, 0xea, 0x07, 0x19, 0xec, 0x94, 0x7d, 0x61, 0x08, 0x11, 0x35, 0x86, 0x8d, 0x5f, 0xd8, 0x01, 0xf0, 0x2c, 0x02, 0x25, 0xe5, 0x16, 0xdf, 0x21, 0x56, 0x60, 0x5e]) aliceBasePublic = bytearray([0x05, 0x47, 0x2d, 0x1f, 0xb1, 0xa9, 0x86, 0x2c, 0x3a, 0xf6, 0xbe, 0xac, 0xa8, 0x92, 0x02, 0x77, 0xe2, 0xb2, 0x6f, 0x4a, 0x79, 0x21, 0x3e, 0xc7, 0xc9, 0x06, 0xae, 0xb3, 0x5e, 0x03, 0xcf, 0x89, 0x50]) aliceEphemeralPublic = bytearray([0x05, 0x6c, 0x3e, 0x0d, 0x1f, 0x52, 0x02, 0x83, 0xef, 0xcc, 0x55, 0xfc, 0xa5, 0xe6, 0x70, 0x75, 0xb9, 0x04, 0x00, 0x7f, 0x18, 0x81, 0xd1, 0x51, 0xaf, 0x76, 0xdf, 0x18, 0xc5, 0x1d, 0x29, 0xd3, 0x4b]) aliceIdentityPublic = bytearray([0x05, 0xb4, 0xa8, 0x45, 0x56, 0x60, 0xad, 0xa6, 0x5b, 0x40, 0x10, 0x07, 0xf6, 0x15, 0xe6, 0x54, 0x04, 0x17, 0x46, 0x43, 0x2e, 0x33, 0x39, 0xc6, 0x87, 0x51, 0x49, 0xbc, 0xee, 0xfc, 0xb4, 0x2b, 0x4a]) senderChain = bytearray([0xd2, 0x2f, 0xd5, 0x6d, 0x3f, 0xec, 0x81, 0x9c, 0xf4, 0xc3, 0xd5, 0x0c, 0x56, 0xed, 0xfb, 0x1c, 0x28, 0x0a, 0x1b, 0x31, 0x96, 0x45, 0x37, 0xf1, 0xd1, 0x61, 0xe1, 0xc9, 0x31, 0x48, 0xe3, 0x6b]) bobIdentityKeyPublic = IdentityKey(bobIdentityPublic, 0) bobIdentityKeyPrivate = Curve.decodePrivatePoint(bobIdentityPrivate) bobIdentityKey = IdentityKeyPair(bobIdentityKeyPublic, bobIdentityKeyPrivate) bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0) bobEphemeralPrivateKey = Curve.decodePrivatePoint(bobPrivate) bobEphemeralKey = ECKeyPair(bobEphemeralPublicKey, bobEphemeralPrivateKey) bobBaseKey = bobEphemeralKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0) aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0) aliceIdentityPublicKey = IdentityKey(aliceIdentityPublic, 0) parameters = BobAxolotlParameters.newBuilder()\ .setOurIdentityKey(bobIdentityKey)\ .setOurSignedPreKey(bobBaseKey)\ .setOurRatchetKey(bobEphemeralKey)\ .setOurOneTimePreKey(None)\ .setTheirIdentityKey(aliceIdentityPublicKey)\ .setTheirBaseKey(aliceBasePublicKey)\ .create() session = SessionState() RatchetingSession.initializeSessionAsBob(session, 2, parameters) self.assertEqual(session.getLocalIdentityKey(), bobIdentityKey.getPublicKey()) self.assertEqual(session.getRemoteIdentityKey(), aliceIdentityPublicKey) self.assertEqual(session.getSenderChainKey().getKey(), senderChain) python-axolotl-0.1.7/axolotl/tests/ratchet/test_rootkey.py0000777000000000000000000000632612446411253024061 0ustar rootroot00000000000000import unittest from axolotl.ecc.curve import Curve from axolotl.ecc.eckeypair import ECKeyPair from axolotl.ratchet.rootkey import RootKey from axolotl.kdf.hkdf import HKDF class RootKeyTest(unittest.TestCase): def test_rootKeyDerivationV2(self): rootKeySeed = bytearray([0x7b, 0xa6, 0xde, 0xbc, 0x2b, 0xc1, 0xbb, 0xf9, 0x1a, 0xbb, 0xc1, 0x36, 0x74, 0x04, 0x17, 0x6c, 0xa6, 0x23, 0x09, 0x5b, 0x7e, 0xc6, 0x6b, 0x45, 0xf6, 0x02, 0xd9, 0x35, 0x38, 0x94, 0x2d, 0xcc]) alicePublic = bytearray([0x05, 0xee, 0x4f, 0xa6, 0xcd, 0xc0, 0x30, 0xdf, 0x49, 0xec, 0xd0, 0xba, 0x6c, 0xfc, 0xff, 0xb2, 0x33, 0xd3, 0x65, 0xa2, 0x7f, 0xad, 0xbe, 0xff, 0x77, 0xe9, 0x63, 0xfc, 0xb1, 0x62, 0x22, 0xe1, 0x3a]) alicePrivate = bytearray([0x21, 0x68, 0x22, 0xec, 0x67, 0xeb, 0x38, 0x04, 0x9e, 0xba, 0xe7, 0xb9, 0x39, 0xba, 0xea, 0xeb, 0xb1, 0x51, 0xbb, 0xb3, 0x2d, 0xb8, 0x0f, 0xd3, 0x89, 0x24, 0x5a, 0xc3, 0x7a, 0x94, 0x8e, 0x50]) bobPublic = bytearray([0x05, 0xab, 0xb8, 0xeb, 0x29, 0xcc, 0x80, 0xb4, 0x71, 0x09, 0xa2, 0x26, 0x5a, 0xbe, 0x97, 0x98, 0x48, 0x54, 0x06, 0xe3, 0x2d, 0xa2, 0x68, 0x93, 0x4a, 0x95, 0x55, 0xe8, 0x47, 0x57, 0x70, 0x8a, 0x30]) nextRoot = bytearray([0xb1, 0x14, 0xf5, 0xde, 0x28, 0x01, 0x19, 0x85, 0xe6, 0xeb, 0xa2, 0x5d, 0x50, 0xe7, 0xec, 0x41, 0xa9, 0xb0, 0x2f, 0x56, 0x93, 0xc5, 0xc7, 0x88, 0xa6, 0x3a, 0x06, 0xd2, 0x12, 0xa2, 0xf7, 0x31]) nextChain = bytearray([0x9d, 0x7d, 0x24, 0x69, 0xbc, 0x9a, 0xe5, 0x3e, 0xe9, 0x80, 0x5a, 0xa3, 0x26, 0x4d, 0x24, 0x99, 0xa3, 0xac, 0xe8, 0x0f, 0x4c, 0xca, 0xe2, 0xda, 0x13, 0x43, 0x0c, 0x5c, 0x55, 0xb5, 0xca, 0x5f]) alicePublicKey = Curve.decodePoint(alicePublic, 0) alicePrivateKey = Curve.decodePrivatePoint(alicePrivate) aliceKeyPair = ECKeyPair(alicePublicKey, alicePrivateKey) bobPublicKey = Curve.decodePoint(bobPublic, 0) rootKey = RootKey(HKDF.createFor(2), rootKeySeed) rootKeyChainKeyPair = rootKey.createChain(bobPublicKey, aliceKeyPair) nextRootKey = rootKeyChainKeyPair[0] nextChainKey = rootKeyChainKeyPair[1] self.assertEqual(rootKey.getKeyBytes(), rootKeySeed) self.assertEqual(nextRootKey.getKeyBytes(), nextRoot) self.assertEqual(nextChainKey.getKey(), nextChain) python-axolotl-0.1.7/axolotl/tests/ratchet/__init__.py0000777000000000000000000000002512445631357023063 0ustar rootroot00000000000000__author__ = 'tarek' python-axolotl-0.1.7/axolotl/tests/test_sessionbuilder.py0000777000000000000000000004347412450021613023762 0ustar rootroot00000000000000# coding=utf-8 import unittest import time from axolotl.sessionbuilder import SessionBuilder from axolotl.sessioncipher import SessionCipher from axolotl.ecc.curve import Curve from axolotl.protocol.ciphertextmessage import CiphertextMessage from axolotl.protocol.whispermessage import WhisperMessage from axolotl.protocol.prekeywhispermessage import PreKeyWhisperMessage from axolotl.state.prekeybundle import PreKeyBundle from axolotl.tests.inmemoryaxolotlstore import InMemoryAxolotlStore from axolotl.state.prekeyrecord import PreKeyRecord from axolotl.state.signedprekeyrecord import SignedPreKeyRecord from axolotl.tests.inmemoryidentitykeystore import InMemoryIdentityKeyStore from axolotl.protocol.keyexchangemessage import KeyExchangeMessage from axolotl.untrustedidentityexception import UntrustedIdentityException class SessionBuilderTest(unittest.TestCase): ALICE_RECIPIENT_ID = 5 BOB_RECIPIENT_ID = 2 def test_basicPreKeyV2(self): aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobStore = InMemoryAxolotlStore() bobPreKeyPair = Curve.generateKeyPair() bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 0, None, None, bobStore.getIdentityKeyPair().getPublicKey()) aliceSessionBuilder.processPreKeyBundle(bobPreKey) self.assertTrue(aliceStore.containsSession(self.__class__.BOB_RECIPIENT_ID, 1)) self.assertEqual(aliceStore.loadSession(self.__class__.BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion(), 2) originalMessage = "L'homme est condamné à être libre" aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) outgoingMessage = aliceSessionCipher.encrypt(originalMessage) self.assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE) incomingMessage = PreKeyWhisperMessage(serialized=outgoingMessage.serialize()) bobStore.storePreKey(31337, PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)) bobSessionCipher = SessionCipher(bobStore, bobStore, bobStore, bobStore, self.__class__.ALICE_RECIPIENT_ID, 1) plaintext = bobSessionCipher.decryptPkmsg(incomingMessage) self.assertTrue(bobStore.containsSession(self.__class__.ALICE_RECIPIENT_ID, 1)) self.assertTrue(bobStore.loadSession(self.__class__.ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 2) self.assertEqual(originalMessage, plaintext) bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage) self.assertTrue(bobOutgoingMessage.getType() == CiphertextMessage.WHISPER_TYPE) alicePlaintext = aliceSessionCipher.decryptMsg(bobOutgoingMessage) self.assertEqual(alicePlaintext, originalMessage) self.runInteraction(aliceStore, bobStore) aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobPreKeyPair = Curve.generateKeyPair() bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31338, bobPreKeyPair.getPublicKey(), 0, None, None, bobStore.getIdentityKeyPair().getPublicKey()) bobStore.storePreKey(31338, PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)) aliceSessionBuilder.processPreKeyBundle(bobPreKey) outgoingMessage = aliceSessionCipher.encrypt(originalMessage) try : bobSessionCipher.decryptPkmsg(PreKeyWhisperMessage(serialized=outgoingMessage.serialize())) raise AssertionError("shouldn't be trusted!") except Exception: bobStore.saveIdentity(self.__class__.ALICE_RECIPIENT_ID, PreKeyWhisperMessage(serialized=outgoingMessage.serialize()).getIdentityKey()) plaintext = bobSessionCipher.decryptPkmsg(PreKeyWhisperMessage(serialized=outgoingMessage.serialize())) self.assertEqual(plaintext, originalMessage) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31337, Curve.generateKeyPair().getPublicKey(), 0, None, None, aliceStore.getIdentityKeyPair().getPublicKey()) try: aliceSessionBuilder.processPreKeyBundle(bobPreKey) raise AssertionError("shouldn't be trusted") except Exception: #good pass return def test_basicPreKeyV3(self): aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobStore = InMemoryAxolotlStore() bobPreKeyPair = Curve.generateKeyPair() bobSignedPreKeyPair = Curve.generateKeyPair() bobSignedPreKeySignature = Curve.calculateSignature(bobStore.getIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize()) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, bobStore.getIdentityKeyPair().getPublicKey()) aliceSessionBuilder.processPreKeyBundle(bobPreKey) self.assertTrue(aliceStore.containsSession(self.__class__.BOB_RECIPIENT_ID, 1)) self.assertTrue(aliceStore.loadSession(self.__class__.BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3) originalMessage = "L'homme est condamné à être libre" aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) outgoingMessage = aliceSessionCipher.encrypt(originalMessage) self.assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE) incomingMessage = PreKeyWhisperMessage(serialized=outgoingMessage.serialize()) bobStore.storePreKey(31337, PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)) bobStore.storeSignedPreKey(22, SignedPreKeyRecord(22, int(time.time() * 1000), bobSignedPreKeyPair, bobSignedPreKeySignature)) bobSessionCipher = SessionCipher(bobStore, bobStore, bobStore, bobStore, self.__class__.ALICE_RECIPIENT_ID, 1) plaintext = bobSessionCipher.decryptPkmsg(incomingMessage) self.assertEqual(originalMessage, plaintext) # @@TODO: in callback assertion # self.assertFalse(bobStore.containsSession(self.__class__.ALICE_RECIPIENT_ID, 1)) self.assertTrue(bobStore.containsSession(self.__class__.ALICE_RECIPIENT_ID, 1)) self.assertTrue(bobStore.loadSession(self.__class__.ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3) self.assertTrue(bobStore.loadSession(self.__class__.ALICE_RECIPIENT_ID, 1).getSessionState().getAliceBaseKey() != None) self.assertEqual(originalMessage, plaintext) bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage) self.assertTrue(bobOutgoingMessage.getType() == CiphertextMessage.WHISPER_TYPE) alicePlaintext = aliceSessionCipher.decryptMsg(WhisperMessage(serialized=bobOutgoingMessage.serialize())) self.assertEqual(alicePlaintext, originalMessage) self.runInteraction(aliceStore, bobStore) aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobPreKeyPair = Curve.generateKeyPair() bobSignedPreKeyPair = Curve.generateKeyPair() bobSignedPreKeySignature = Curve.calculateSignature(bobStore.getIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize()) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31338, bobPreKeyPair.getPublicKey(), 23, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, bobStore.getIdentityKeyPair().getPublicKey()) bobStore.storePreKey(31338, PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)) bobStore.storeSignedPreKey(23, SignedPreKeyRecord(23, int(time.time() * 1000), bobSignedPreKeyPair, bobSignedPreKeySignature)) aliceSessionBuilder.processPreKeyBundle(bobPreKey) outgoingMessage = aliceSessionCipher.encrypt(originalMessage) try: plaintext = bobSessionCipher.decryptPkmsg(PreKeyWhisperMessage(serialized=outgoingMessage)) raise AssertionError("shouldn't be trusted!") except Exception: bobStore.saveIdentity(self.__class__.ALICE_RECIPIENT_ID, PreKeyWhisperMessage(serialized=outgoingMessage.serialize()).getIdentityKey()) plaintext = bobSessionCipher.decryptPkmsg(PreKeyWhisperMessage(serialized=outgoingMessage.serialize())) self.assertEqual(plaintext, originalMessage) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31337, Curve.generateKeyPair().getPublicKey(), 23, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, aliceStore.getIdentityKeyPair().getPublicKey()) try: aliceSessionBuilder.process(bobPreKey) raise AssertionError("shouldn't be trusted!") except Exception: #good pass def test_badSignedPreKeySignature(self): aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobIdentityKeyStore = InMemoryIdentityKeyStore() bobPreKeyPair = Curve.generateKeyPair() bobSignedPreKeyPair = Curve.generateKeyPair() bobSignedPreKeySignature = Curve.calculateSignature(bobIdentityKeyStore.getIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize()) for i in range(0, len(bobSignedPreKeySignature) * 8): modifiedSignature = bytearray(bobSignedPreKeySignature[:]) modifiedSignature[int(i/8)] ^= 0x01 << (i % 8) bobPreKey = PreKeyBundle(bobIdentityKeyStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 22, bobSignedPreKeyPair.getPublicKey(), modifiedSignature, bobIdentityKeyStore.getIdentityKeyPair().getPublicKey()) try: aliceSessionBuilder.processPreKeyBundle(bobPreKey) except Exception: pass #good bobPreKey = PreKeyBundle(bobIdentityKeyStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, bobIdentityKeyStore.getIdentityKeyPair().getPublicKey()) aliceSessionBuilder.processPreKeyBundle(bobPreKey) def test_basicKeyExchange(self): aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobStore = InMemoryAxolotlStore() bobSessionBuilder = SessionBuilder(bobStore, bobStore, bobStore, bobStore, self.__class__.ALICE_RECIPIENT_ID, 1) aliceKeyExchangeMessage = aliceSessionBuilder.processInitKeyExchangeMessage() self.assertTrue(aliceKeyExchangeMessage != None) aliceKeyExchangeMessageBytes = aliceKeyExchangeMessage.serialize() bobKeyExchangeMessage = bobSessionBuilder.processKeyExchangeMessage(KeyExchangeMessage(serialized=aliceKeyExchangeMessageBytes)) self.assertTrue(bobKeyExchangeMessage != None) bobKeyExchangeMessageBytes = bobKeyExchangeMessage.serialize() response = aliceSessionBuilder.processKeyExchangeMessage(KeyExchangeMessage(serialized=bobKeyExchangeMessageBytes)) self.assertTrue(response == None) self.assertTrue(aliceStore.containsSession(self.__class__.BOB_RECIPIENT_ID, 1)) self.assertTrue(bobStore.containsSession(self.__class__.ALICE_RECIPIENT_ID, 1)) self.runInteraction(aliceStore, bobStore) aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) aliceKeyExchangeMessage = aliceSessionBuilder.processInitKeyExchangeMessage() try: bobKeyExchangeMessage = bobSessionBuilder.processKeyExchangeMessage(aliceKeyExchangeMessage) raise AssertionError("This identity shouldn't be trusted!") except UntrustedIdentityException as uie: bobStore.saveIdentity(self.__class__.ALICE_RECIPIENT_ID, aliceKeyExchangeMessage.getIdentityKey()) bobKeyExchangeMessage = bobSessionBuilder.processKeyExchangeMessage(aliceKeyExchangeMessage) self.assertTrue(aliceSessionBuilder.processKeyExchangeMessage(bobKeyExchangeMessage) == None) self.runInteraction(aliceStore, bobStore) def runInteraction(self, aliceStore, bobStore): """ :type aliceStore: AxolotlStore :type bobStore: AxolotlStore """ aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobSessionCipher = SessionCipher(bobStore, bobStore, bobStore, bobStore, self.__class__.ALICE_RECIPIENT_ID, 1) originalMessage = "smert ze smert" aliceMessage = aliceSessionCipher.encrypt(originalMessage) self.assertTrue(aliceMessage.getType() == CiphertextMessage.WHISPER_TYPE) plaintext = bobSessionCipher.decryptMsg(WhisperMessage(serialized=aliceMessage.serialize())) self.assertEqual(plaintext, originalMessage) bobMessage = bobSessionCipher.encrypt(originalMessage) self.assertTrue(bobMessage.getType() == CiphertextMessage.WHISPER_TYPE) plaintext = aliceSessionCipher.decryptMsg(WhisperMessage(serialized=bobMessage.serialize())) self.assertEqual(plaintext, originalMessage) for i in range(0, 10): loopingMessage = "What do we mean by saying that existence precedes essence? " \ "We mean that man first of all exists, encounters himself, " \ "surges up in the world--and defines himself aftward. %s" % i aliceLoopingMessage = aliceSessionCipher.encrypt(loopingMessage) loopingPlaintext = bobSessionCipher.decryptMsg(WhisperMessage(serialized=aliceLoopingMessage.serialize())) self.assertEqual(loopingPlaintext, loopingMessage) for i in range(0, 10): loopingMessage = "What do we mean by saying that existence precedes essence? " \ "We mean that man first of all exists, encounters himself, " \ "surges up in the world--and defines himself aftward. %s" % i bobLoopingMessage = bobSessionCipher.encrypt(loopingMessage) loopingPlaintext = aliceSessionCipher.decryptMsg(WhisperMessage(serialized=bobLoopingMessage.serialize())) self.assertEqual(loopingPlaintext, loopingMessage) aliceOutOfOrderMessages = [] for i in range(0, 10): loopingMessage = "What do we mean by saying that existence precedes essence? " \ "We mean that man first of all exists, encounters himself, " \ "surges up in the world--and defines himself aftward. %s" % i aliceLoopingMessage = aliceSessionCipher.encrypt(loopingMessage) aliceOutOfOrderMessages.append((loopingMessage, aliceLoopingMessage)) for i in range(0, 10): loopingMessage = "What do we mean by saying that existence precedes essence? " \ "We mean that man first of all exists, encounters himself, " \ "surges up in the world--and defines himself aftward. %s" % i aliceLoopingMessage = aliceSessionCipher.encrypt(loopingMessage) loopingPlaintext = bobSessionCipher.decryptMsg(WhisperMessage(serialized=aliceLoopingMessage.serialize())) self.assertEqual(loopingPlaintext, loopingMessage) for i in range(0, 10): loopingMessage = "You can only desire based on what you know: %s" % i bobLoopingMessage = bobSessionCipher.encrypt(loopingMessage) loopingPlaintext = aliceSessionCipher.decryptMsg(WhisperMessage(serialized=bobLoopingMessage.serialize())) self.assertEqual(loopingPlaintext, loopingMessage) for aliceOutOfOrderMessage in aliceOutOfOrderMessages: outOfOrderPlaintext = bobSessionCipher.decryptMsg(WhisperMessage(serialized=aliceOutOfOrderMessage[1].serialize())) self.assertEqual(outOfOrderPlaintext, aliceOutOfOrderMessage[0]) python-axolotl-0.1.7/axolotl/tests/test_sessioncipher.py0000777000000000000000000001733112457621664023622 0ustar rootroot00000000000000# coding=utf-8 import unittest from axolotl.state.sessionrecord import SessionRecord from axolotl.ecc.curve import Curve from axolotl.identitykeypair import IdentityKeyPair, IdentityKey from axolotl.ratchet.aliceaxolotlparameters import AliceAxolotlParameters from axolotl.ratchet.bobaxolotlparamaters import BobAxolotlParameters from axolotl.ratchet.ratchetingsession import RatchetingSession from axolotl.tests.inmemoryaxolotlstore import InMemoryAxolotlStore from axolotl.sessioncipher import SessionCipher from axolotl.protocol.whispermessage import WhisperMessage import time from random import shuffle class SessionCipherTest(unittest.TestCase): def test_basicSessionV2(self): aliceSessionRecord = SessionRecord() bobSessionRecord = SessionRecord() self.initializeSessionsV2(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState()) self.runInteraction(aliceSessionRecord, bobSessionRecord) def test_basicSessionV3(self): aliceSessionRecord = SessionRecord() bobSessionRecord = SessionRecord() self.initializeSessionsV3(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState()) self.runInteraction(aliceSessionRecord, bobSessionRecord) def runInteraction(self, aliceSessionRecord, bobSessionRecord): aliceStore = InMemoryAxolotlStore() bobStore = InMemoryAxolotlStore() aliceStore.storeSession(2, 1, aliceSessionRecord) bobStore.storeSession(3, 1, bobSessionRecord) aliceCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, 2, 1) bobCipher = SessionCipher(bobStore, bobStore, bobStore, bobStore, 3, 1) alicePlaintext = "This is a plaintext message." message = aliceCipher.encrypt(alicePlaintext) bobPlaintext = bobCipher.decryptMsg(WhisperMessage(serialized=message.serialize())) self.assertEqual(alicePlaintext, bobPlaintext) bobReply = "This is a message from Bob." reply = bobCipher.encrypt(bobReply) receivedReply = aliceCipher.decryptMsg(WhisperMessage( serialized=reply.serialize())) self.assertEqual(bobReply, receivedReply) aliceCiphertextMessages = [] alicePlaintextMessages = [] for i in range(0, 50): alicePlaintextMessages.append("смерть за смерть %s" % i) aliceCiphertextMessages.append(aliceCipher.encrypt("смерть за смерть %s" % i)) #shuffle(aliceCiphertextMessages) #shuffle(alicePlaintextMessages) for i in range(0, int(len(aliceCiphertextMessages)/2)): receivedPlaintext = bobCipher.decryptMsg(WhisperMessage(serialized=aliceCiphertextMessages[i].serialize())) self.assertEqual(receivedPlaintext, alicePlaintextMessages[i]) """ List bobCiphertextMessages = new ArrayList<>(); List bobPlaintextMessages = new ArrayList<>(); for (int i=0;i<20;i++) { bobPlaintextMessages.add(("смерть за смерть " + i).getBytes()); bobCiphertextMessages.add(bobCipher.encrypt(("смерть за смерть " + i).getBytes())); } seed = System.currentTimeMillis(); Collections.shuffle(bobCiphertextMessages, new Random(seed)); Collections.shuffle(bobPlaintextMessages, new Random(seed)); for (int i=0;i> 4 @staticmethod def lowBitsToInt(value): return value & 0xF @staticmethod def intToByteArray(_bytes, offset, value): _bytes[offset + 3] = value % 256 _bytes[offset + 2] = (value >> 8) % 256 _bytes[offset + 1] = (value >> 16) % 256 _bytes[offset] = (value >> 24) % 256 return 4 python-axolotl-0.1.7/axolotl/util/hexutil.py0000777000000000000000000000054312457620214021165 0ustar rootroot00000000000000import codecs, sys decode_hex = codecs.getdecoder("hex_codec") class HexUtil: @staticmethod def decodeHex(hexString): hexString = hexString.encode() if type(hexString) is str else hexString result = decode_hex(hexString)[0] if sys.version_info >= (3,0): result = result.decode('latin-1') return result python-axolotl-0.1.7/axolotl/util/keyhelper.py0000777000000000000000000000562412455657675021523 0ustar rootroot00000000000000from ..ecc.curve import Curve from ..identitykey import IdentityKey from ..identitykeypair import IdentityKeyPair from ..state.prekeyrecord import PreKeyRecord from ..state.signedprekeyrecord import SignedPreKeyRecord from .medium import Medium import os import struct import time import binascii import math class KeyHelper: def __init__(self): pass """ Generate an identity key pair. Clients should only do this once, at install time. @return the generated IdentityKeyPair. """ @staticmethod def generateIdentityKeyPair(): keyPair = Curve.generateKeyPair() publicKey = IdentityKey(keyPair.getPublicKey()) serialized = '0a21056e8936e8367f768a7bba008ade7cf58407bdc7a6aae293e2cb7c06668dcd7d5e12205011524f0c15467100dd6' \ '03e0d6020f4d293edfbcd82129b14a88791ac81365c' serialized = binascii.unhexlify(serialized.encode()) identityKeyPair = IdentityKeyPair(publicKey, keyPair.getPrivateKey()) return identityKeyPair # return IdentityKeyPair(serialized=serialized) """ Generate a registration ID. Clients should only do this once, at install time. """ @staticmethod def generateRegistrationId(): regId = KeyHelper.getRandomSequence() return regId @staticmethod def getRandomSequence(max = 4294967296): size = int(math.log(max)/ math.log(2)) / 8 rand = os.urandom(int(size)) randh = binascii.hexlify(rand) return int(randh, 16) """ Generate a list of PreKeys. Clients should do this at install time, and subsequently any time the list of PreKeys stored on the server runs low. PreKey IDs are shorts, so they will eventually be repeated. Clients should store PreKeys in a circular buffer, so that they are repeated as infrequently as possible. @param start The starting PreKey ID, inclusive. @param count The number of PreKeys to generate. @return the list of generated PreKeyRecords. """ @staticmethod def generatePreKeys(start, count): results = [] start -= 1 for i in range(0, count): preKeyId = ((start + i) % (Medium.MAX_VALUE-1)) + 1 results.append(PreKeyRecord(preKeyId, Curve.generateKeyPair())) return results @staticmethod def generateSignedPreKey(identityKeyPair, signedPreKeyId): keyPair = Curve.generateKeyPair() signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize()) spk = SignedPreKeyRecord(signedPreKeyId, int(round(time.time() * 1000)), keyPair, signature) return spk @staticmethod def generateSenderSigningKey(): return Curve.generateKeyPair() @staticmethod def generateSenderKey(): return os.urandom(32) @staticmethod def generateSenderKeyId(): return KeyHelper.getRandomSequence(2147483647)python-axolotl-0.1.7/axolotl/util/medium.py0000777000000000000000000000004612445373151020763 0ustar rootroot00000000000000class Medium: MAX_VALUE = 0xFFFFFFpython-axolotl-0.1.7/axolotl/util/__init__.py0000777000000000000000000000000012445373151021230 0ustar rootroot00000000000000python-axolotl-0.1.7/axolotl/__init__.py0000777000000000000000000000006112521166563020264 0ustar rootroot00000000000000__version__ = "0.1.7" __author__ = "Tarek Galal" python-axolotl-0.1.7/PKG-INFO0000777000000000000000000000042212521166655015571 0ustar rootroot00000000000000Metadata-Version: 1.0 Name: python-axolotl Version: 0.1.7 Summary: Python port of libaxolotl-android, originally written by Moxie Marlinspik Home-page: UNKNOWN Author: Tarek Galal Author-email: tare2.galal@gmail.com License: GPLv3 License Description: UNKNOWN Platform: any python-axolotl-0.1.7/python_axolotl.egg-info/0000777000000000000000000000000012521166655021250 5ustar rootroot00000000000000python-axolotl-0.1.7/python_axolotl.egg-info/dependency_links.txt0000777000000000000000000000000112521166653025317 0ustar rootroot00000000000000 python-axolotl-0.1.7/python_axolotl.egg-info/PKG-INFO0000777000000000000000000000042212521166653022344 0ustar rootroot00000000000000Metadata-Version: 1.0 Name: python-axolotl Version: 0.1.7 Summary: Python port of libaxolotl-android, originally written by Moxie Marlinspik Home-page: UNKNOWN Author: Tarek Galal Author-email: tare2.galal@gmail.com License: GPLv3 License Description: UNKNOWN Platform: any python-axolotl-0.1.7/python_axolotl.egg-info/requires.txt0000777000000000000000000000010012521166653023640 0ustar rootroot00000000000000protobuf>=2.6,<3.0.0-alpha-2 pycrypto python-axolotl-curve25519 python-axolotl-0.1.7/python_axolotl.egg-info/SOURCES.txt0000777000000000000000000000602412521166654023140 0ustar rootroot00000000000000setup.py axolotl/__init__.py axolotl/duplicatemessagexception.py axolotl/identitykey.py axolotl/identitykeypair.py axolotl/invalidkeyexception.py axolotl/invalidkeyidexception.py axolotl/invalidmessageexception.py axolotl/invalidversionexception.py axolotl/legacymessageexception.py axolotl/nosessionexception.py axolotl/sessionbuilder.py axolotl/sessioncipher.py axolotl/statekeyexchangeexception.py axolotl/untrustedidentityexception.py axolotl/ecc/__init__.py axolotl/ecc/curve.py axolotl/ecc/djbec.py axolotl/ecc/ec.py axolotl/ecc/eckeypair.py axolotl/groups/__init__.py axolotl/groups/groupcipher.py axolotl/groups/groupsessionbuilder.py axolotl/groups/ratchet/__init__.py axolotl/groups/ratchet/senderchainkey.py axolotl/groups/ratchet/sendermessagekey.py axolotl/groups/state/__init__.py axolotl/groups/state/senderkeyrecord.py axolotl/groups/state/senderkeystate.py axolotl/groups/state/senderkeystore.py axolotl/kdf/__init__.py axolotl/kdf/derivedmessagesecrets.py axolotl/kdf/derivedrootsecrets.py axolotl/kdf/hkdf.py axolotl/kdf/hkdfv2.py axolotl/kdf/hkdfv3.py axolotl/kdf/messagekeys.py axolotl/protocol/__init__.py axolotl/protocol/ciphertextmessage.py axolotl/protocol/keyexchangemessage.py axolotl/protocol/prekeywhispermessage.py axolotl/protocol/senderkeydistributionmessage.py axolotl/protocol/senderkeymessage.py axolotl/protocol/whispermessage.py axolotl/protocol/whisperprotos.py axolotl/ratchet/__init__.py axolotl/ratchet/aliceaxolotlparameters.py axolotl/ratchet/bobaxolotlparamaters.py axolotl/ratchet/chainkey.py axolotl/ratchet/ratchetingsession.py axolotl/ratchet/rootkey.py axolotl/ratchet/symmetricaxolotlparameters.py axolotl/state/__init__.py axolotl/state/axolotlstore.py axolotl/state/identitykeystore.py axolotl/state/prekeybundle.py axolotl/state/prekeyrecord.py axolotl/state/prekeystore.py axolotl/state/sessionrecord.py axolotl/state/sessionstate.py axolotl/state/sessionstore.py axolotl/state/signedprekeyrecord.py axolotl/state/signedprekeystore.py axolotl/state/storageprotos.py axolotl/tests/__init__.py axolotl/tests/inmemoryaxolotlstore.py axolotl/tests/inmemoryidentitykeystore.py axolotl/tests/inmemoryprekeystore.py axolotl/tests/inmemorysessionstore.py axolotl/tests/inmemorysignedprekeystore.py axolotl/tests/test_sessionbuilder.py axolotl/tests/test_sessioncipher.py axolotl/tests/test_sigs.py axolotl/tests/test_stuff.py axolotl/tests/groups/__init__.py axolotl/tests/groups/inmemorysenderkeystore.py axolotl/tests/groups/test_groupcipher.py axolotl/tests/kdf/__init__.py axolotl/tests/kdf/test_hkdf.py axolotl/tests/ratchet/__init__.py axolotl/tests/ratchet/test_chainkey.py axolotl/tests/ratchet/test_ratchetingsession.py axolotl/tests/ratchet/test_rootkey.py axolotl/tests/util/__init__.py axolotl/tests/util/test_byteutil.py axolotl/util/__init__.py axolotl/util/byteutil.py axolotl/util/hexutil.py axolotl/util/keyhelper.py axolotl/util/medium.py python_axolotl.egg-info/PKG-INFO python_axolotl.egg-info/SOURCES.txt python_axolotl.egg-info/dependency_links.txt python_axolotl.egg-info/requires.txt python_axolotl.egg-info/top_level.txtpython-axolotl-0.1.7/python_axolotl.egg-info/top_level.txt0000777000000000000000000000001012521166653023772 0ustar rootroot00000000000000axolotl python-axolotl-0.1.7/setup.cfg0000777000000000000000000000007312521166655016317 0ustar rootroot00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 python-axolotl-0.1.7/setup.py0000777000000000000000000000101012521165757016202 0ustar rootroot00000000000000from __future__ import print_function from setuptools import setup, find_packages import axolotl deps = ["protobuf>=2.6,<3.0.0-alpha-2", "pycrypto", "python-axolotl-curve25519"] setup( name='python-axolotl', version=axolotl.__version__ , packages= find_packages(), install_requires = deps, license='GPLv3 License', author='Tarek Galal', author_email='tare2.galal@gmail.com', description="Python port of libaxolotl-android, originally written by Moxie Marlinspik", platforms='any' )