changeset 10545d5cd4f3 in /home/hg/repos/gajim-plugins
author: Kjell Braden afflux.gajim@pentabarf.de branches: gtk3 details:gajim-plugins?cmd=changeset;node=10545d5cd4f3 description: gotr: update provided potr to 1.0.0beta7
diffstat:
gotr/potr/__init__.py | 2 +- gotr/potr/compatcrypto/common.py | 14 +- gotr/potr/compatcrypto/pycrypto.py | 25 +-- gotr/potr/context.py | 156 ++++++++++++++++++++--------- gotr/potr/crypt.py | 188 ++++++++++++++++++------------------ gotr/potr/proto.py | 170 +++++++++++++++++++++------------ gotr/potr/utils.py | 5 +- 7 files changed, 332 insertions(+), 228 deletions(-)
diffs (truncated from 1221 to 300 lines):
diff -r b08c72baa3af -r 10545d5cd4f3 gotr/potr/__init__.py --- a/gotr/potr/__init__.py Wed Sep 04 21:57:11 2013 +0400 +++ b/gotr/potr/__init__.py Sun Sep 22 17:05:00 2013 +0200 @@ -24,4 +24,4 @@
''' version is: (major, minor, patch, sub) with sub being one of 'alpha', 'beta', 'final' ''' -VERSION = (1, 0, 0, 'beta5') +VERSION = (1, 0, 0, 'beta7') diff -r b08c72baa3af -r 10545d5cd4f3 gotr/potr/compatcrypto/common.py --- a/gotr/potr/compatcrypto/common.py Wed Sep 04 21:57:11 2013 +0400 +++ b/gotr/potr/compatcrypto/common.py Sun Sep 22 17:05:00 2013 +0200 @@ -26,8 +26,8 @@ DEFAULT_KEYTYPE = 0x0000 pkTypes = {} def registerkeytype(cls): - if not hasattr(cls, 'parsePayload'): - raise TypeError('registered key types need parsePayload()') + if cls.keyType is None: + raise TypeError('registered key class needs a type value') pkTypes[cls.keyType] = cls return cls
@@ -35,12 +35,16 @@ return pkTypes[DEFAULT_KEYTYPE].generate()
class PK(object): - __slots__ = [] + keyType = None
@classmethod def generate(cls): raise NotImplementedError
+ @classmethod + def parsePayload(cls, data, private=False): + raise NotImplementedError + def sign(self, data): raise NotImplementedError def verify(self, data): @@ -80,13 +84,13 @@ @classmethod def parsePrivateKey(cls, data): implCls, data = cls.getImplementation(data) - logging.debug('Got privkey of type %r' % implCls) + logging.debug('Got privkey of type %r', implCls) return implCls.parsePayload(data, private=True)
@classmethod def parsePublicKey(cls, data): implCls, data = cls.getImplementation(data) - logging.debug('Got pubkey of type %r' % implCls) + logging.debug('Got pubkey of type %r', implCls) return implCls.parsePayload(data)
def __str__(self): diff -r b08c72baa3af -r 10545d5cd4f3 gotr/potr/compatcrypto/pycrypto.py --- a/gotr/potr/compatcrypto/pycrypto.py Wed Sep 04 21:57:11 2013 +0400 +++ b/gotr/potr/compatcrypto/pycrypto.py Sun Sep 22 17:05:00 2013 +0200 @@ -15,18 +15,16 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see http://www.gnu.org/licenses/.
-from Crypto import Cipher, Random +from Crypto import Cipher from Crypto.Hash import SHA256 as _SHA256 -from Crypto.Hash import SHA as _SHA1 +from Crypto.Hash import SHA as _SHA1 from Crypto.Hash import HMAC as _HMAC from Crypto.PublicKey import DSA +from Crypto.Random import random from numbers import Number
from potr.compatcrypto import common -from potr.utils import pack_mpi, read_mpi, bytes_to_long, long_to_bytes - -# XXX atfork? -RNG = Random.new() +from potr.utils import read_mpi, bytes_to_long, long_to_bytes
def SHA256(data): return _SHA256.new(data).digest() @@ -54,7 +52,6 @@ return Cipher.AES.new(key, Cipher.AES.MODE_CTR, counter=counter)
class Counter(object): - __slots__ = ['prefix', 'val'] def __init__(self, prefix): self.prefix = prefix self.val = 0 @@ -72,17 +69,15 @@ return '<Counter(p={p!r},v={v!r})>'.format(p=self.prefix, v=self.val)
def byteprefix(self): - return long_to_bytes(self.prefix).rjust(8, b'\0') + return long_to_bytes(self.prefix, 8)
def __call__(self): - val = long_to_bytes(self.val) - prefix = long_to_bytes(self.prefix) + bytesuffix = long_to_bytes(self.val, 8) self.val += 1 - return self.byteprefix() + val.rjust(8, b'\0') + return self.byteprefix() + bytesuffix
@common.registerkeytype class DSAKey(common.PK): - __slots__ = ['priv', 'pub'] keyType = 0x0000
def __init__(self, key=None, private=False): @@ -111,10 +106,10 @@ return SHA1(self.getSerializedPublicPayload())
def sign(self, data): - # 2 <= K <= q = 160bit = 20 byte - K = bytes_to_long(RNG.read(19)) + 2 + # 2 <= K <= q + K = random.randrange(2, self.priv.q) r, s = self.priv.sign(data, K) - return long_to_bytes(r) + long_to_bytes(s) + return long_to_bytes(r, 20) + long_to_bytes(s, 20)
def verify(self, data, sig): r, s = bytes_to_long(sig[:20]), bytes_to_long(sig[20:]) diff -r b08c72baa3af -r 10545d5cd4f3 gotr/potr/context.py --- a/gotr/potr/context.py Wed Sep 04 21:57:11 2013 +0400 +++ b/gotr/potr/context.py Sun Sep 22 17:05:00 2013 +0200 @@ -19,7 +19,7 @@ from __future__ import unicode_literals
try: - basestring = basestring + type(basestring) except NameError: # all strings are unicode in python3k basestring = str @@ -27,7 +27,7 @@
# callable is not available in python 3.0 and 3.1 try: - callable = callable + type(callable) except NameError: from collections import Callable def callable(x): @@ -42,6 +42,7 @@
from potr import crypt from potr import proto +from potr import compatcrypto
from time import time
@@ -62,16 +63,11 @@ OFFER_ACCEPTED = 3
class Context(object): - __slots__ = ['user', 'policy', 'crypto', 'tagOffer', 'lastSend', - 'lastMessage', 'mayRetransmit', 'fragment', 'fragmentInfo', 'state', - 'inject', 'trust', 'peer', 'trustName'] - def __init__(self, account, peername): self.user = account self.peer = peername self.policy = {} self.crypto = crypt.CryptEngine(self) - self.discardFragment() self.tagOffer = OFFER_NOTSENT self.mayRetransmit = 0 self.lastSend = 0 @@ -79,6 +75,10 @@ self.state = STATE_PLAINTEXT self.trustName = self.peer
+ self.fragmentInfo = None + self.fragment = None + self.discardFragment() + def getPolicy(self, key): raise NotImplementedError
@@ -100,13 +100,19 @@ params = message.split(b',') if len(params) < 5 or not params[1].isdigit() or not params[2].isdigit(): logger.warning('invalid formed fragmented message: %r', params) - return None + self.discardFragment() + return message
K, N = self.fragmentInfo + try: + k = int(params[1]) + n = int(params[2]) + except ValueError: + logger.warning('invalid formed fragmented message: %r', params) + self.discardFragment() + return message
- k = int(params[1]) - n = int(params[2]) fragData = params[3]
logger.debug(params) @@ -114,17 +120,17 @@ if n >= k == 1: # first fragment self.discardFragment() - self.fragmentInfo = (k,n) + self.fragmentInfo = (k, n) self.fragment.append(fragData) elif N == n >= k > 1 and k == K+1: # accumulate - self.fragmentInfo = (k,n) + self.fragmentInfo = (k, n) self.fragment.append(fragData) else: # bad, discard self.discardFragment() logger.warning('invalid fragmented message: %r', params) - return None + return message
if n == k > 0: assembled = b''.join(self.fragment) @@ -210,7 +216,7 @@ if self.state != STATE_ENCRYPTED: self.sendInternal(proto.Error( 'You sent encrypted to {user}, who wasn't expecting it.' - .format(user=self.user.name)), appdata=appdata) + .format(user=self.user.name).encode('utf-8')), appdata=appdata) if ignore: return IGN raise NotEncryptedError(EXC_UNREADABLE_MESSAGE) @@ -263,12 +269,13 @@ return msg
def processOutgoingMessage(self, msg, flags, tlvs=[]): - if isinstance(self.parse(msg), proto.Query): + isQuery = self.parseExplicitQuery(msg) is not None + if isQuery: return self.user.getDefaultQueryMessage(self.getPolicy)
if self.state == STATE_PLAINTEXT: if self.getPolicy('REQUIRE_ENCRYPTION'): - if not isinstance(self.parse(msg), proto.Query): + if not isQuery: self.lastMessage = msg self.lastSend = time() self.mayRetransmit = 2 @@ -277,8 +284,12 @@ return msg if self.getPolicy('SEND_TAG') and self.tagOffer != OFFER_REJECTED: self.tagOffer = OFFER_SENT - return proto.TaggedPlaintext(msg, self.getPolicy('ALLOW_V1'), - self.getPolicy('ALLOW_V2')) + versions = set() + if self.getPolicy('ALLOW_V1'): + versions.add(1) + if self.getPolicy('ALLOW_V2'): + versions.add(2) + return proto.TaggedPlaintext(msg, versions) return msg if self.state == STATE_ENCRYPTED: msg = self.crypto.createDataMessage(msg, flags, tlvs) @@ -304,9 +315,9 @@ def sendFragmented(self, msg, policy=FRAGMENT_SEND_ALL, appdata=None): mms = self.maxMessageSize(appdata) msgLen = len(msg) - if mms != 0 and len(msg) > mms: + if mms != 0 and msgLen > mms: fms = mms - 19 - fragments = [ msg[i:i+fms] for i in range(0, len(msg), fms) ] + fragments = [ msg[i:i+fms] for i in range(0, msgLen, fms) ]
fc = len(fragments)
@@ -375,9 +386,9 @@ self.crypto.smpSecret(secret, question=question, appdata=appdata)
def handleQuery(self, message, appdata=None): - if message.v2 and self.getPolicy('ALLOW_V2'): + if 2 in message.versions and self.getPolicy('ALLOW_V2'): self.authStartV2(appdata=appdata) - elif message.v1 and self.getPolicy('ALLOW_V1'): + elif 1 in message.versions and self.getPolicy('ALLOW_V1'): self.authStartV1(appdata=appdata)
def authStartV1(self, appdata=None): @@ -386,7 +397,33 @@ def authStartV2(self, appdata=None): self.crypto.startAKE(appdata=appdata)
- def parse(self, message): + def parseExplicitQuery(self, message): + otrTagPos = message.find(proto.OTRTAG) + + if otrTagPos == -1: