From f47352751d5a30d143e3d40a2839135499ee1ed6 Mon Sep 17 00:00:00 2001 From: Bohdan Horbeshko Date: Sat, 15 Oct 2022 03:14:51 +0300 Subject: [PATCH] Merge https://github.com/python-otr/pure-python-otr/pull/80/ [WIP] --- potr/__init__.py | 2 +- potr/compatcrypto/pycrypto.py | 57 +++++++++++------------------------ potr/crypt.py | 14 ++++----- 3 files changed, 26 insertions(+), 47 deletions(-) diff --git a/potr/__init__.py b/potr/__init__.py index acea2db..d212d9e 100644 --- a/potr/__init__.py +++ b/potr/__init__.py @@ -25,4 +25,4 @@ from gajim_otrplugin.potr.utils import human_hash ''' version is: (major, minor, patch, sub) with sub being one of 'alpha', 'beta', 'final' ''' -VERSION = (1, 0, 0, 'final') +VERSION = (1, 0, 3, 'alpha') diff --git a/potr/compatcrypto/pycrypto.py b/potr/compatcrypto/pycrypto.py index 9d5baa0..bb003b8 100644 --- a/potr/compatcrypto/pycrypto.py +++ b/potr/compatcrypto/pycrypto.py @@ -16,17 +16,16 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see . -try: - import Cryptodome -except ImportError: - import crypto as Crypto from Cryptodome import Cipher +from Cryptodome.Hash import HMAC as _HMAC from Cryptodome.Hash import SHA256 as _SHA256 from Cryptodome.Hash import SHA as _SHA1 -from Cryptodome.Hash import HMAC as _HMAC from Cryptodome.PublicKey import DSA -import Cryptodome.Random.random +from Cryptodome.Random import random +from Cryptodome.Signature import DSS +from Cryptodome.Util import Counter + from numbers import Number from gajim_otrplugin.potr.compatcrypto import common @@ -46,36 +45,14 @@ def SHA256HMAC(key, data): def AESCTR(key, counter=0): if isinstance(counter, Number): - counter = Counter(counter) - if not isinstance(counter, Counter): + counter = Counter.new(nbits=64, prefix=long_to_bytes(counter, 8), initial_value=0) + # in pycrypto Counter used to be an object, + # in pycryptodome it's now only a dict. + # This tries to validate its "type" so we don't feed anything as a counter + if set(counter) != set(Counter.new(64)): raise TypeError return Cipher.AES.new(key, Cipher.AES.MODE_CTR, counter=counter) -class Counter(object): - def __init__(self, prefix): - self.prefix = prefix - self.val = 0 - - def inc(self): - self.prefix += 1 - self.val = 0 - - def __setattr__(self, attr, val): - if attr == 'prefix': - self.val = 0 - super(Counter, self).__setattr__(attr, val) - - def __repr__(self): - return ''.format(p=self.prefix, v=self.val) - - def byteprefix(self): - return long_to_bytes(self.prefix, 8) - - def __call__(self): - bytesuffix = long_to_bytes(self.val, 8) - self.val += 1 - return self.byteprefix() + bytesuffix - @common.registerkeytype class DSAKey(common.PK): keyType = 0x0000 @@ -108,12 +85,14 @@ class DSAKey(common.PK): def sign(self, data): # 2 <= K <= q K = randrange(2, self.priv.q) - r, s = self.priv.sign(data, K) + M = bytes_to_long(data) + r, s = self.priv._sign(M, K) 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:]) - return self.pub.verify(data, (r, s)) + M = bytes_to_long(data) + return self.pub._verify(M, (r, s)) def __hash__(self): return bytes_to_long(self.fingerprint()) @@ -129,8 +108,8 @@ class DSAKey(common.PK): @classmethod def generate(cls): privkey = DSA.generate(1024) - return cls((privkey.key.y, privkey.key.g, privkey.key.p, privkey.key.q, - privkey.key.x), private=True) + return cls((privkey.y, privkey.g, privkey.p, privkey.q, + privkey.x), private=True) @classmethod def parsePayload(cls, data, private=False): @@ -144,7 +123,7 @@ class DSAKey(common.PK): return cls((y, g, p, q), private=False), data def getrandbits(k): - return Cryptodome.Random.random.getrandbits(k) + return random.getrandbits(k) def randrange(start, stop): - return Cryptodome.Random.random.randrange(start, stop) + return random.randrange(start, stop) diff --git a/potr/crypt.py b/potr/crypt.py index 4d47595..92997bf 100644 --- a/potr/crypt.py +++ b/potr/crypt.py @@ -24,7 +24,7 @@ import struct from gajim_otrplugin.potr.compatcrypto import SHA256, SHA1, SHA1HMAC, SHA256HMAC, \ - Counter, AESCTR, PK, getrandbits, randrange + AESCTR, PK, getrandbits, randrange from gajim_otrplugin.potr.utils import bytes_to_long, long_to_bytes, pack_mpi, read_mpi from gajim_otrplugin.potr import proto @@ -70,8 +70,8 @@ class DHSession(object): self.sendmac = sendmac self.rcvenc = rcvenc self.rcvmac = rcvmac - self.sendctr = Counter(0) - self.rcvctr = Counter(0) + self.sendctr = 0 + self.rcvctr = 0 self.sendmacused = False self.rcvmacused = False @@ -178,12 +178,12 @@ class CryptEngine(object): sesskey.rcvmacused = True newCtrPrefix = bytes_to_long(msg.ctr) - if newCtrPrefix <= sesskey.rcvctr.prefix: + if newCtrPrefix <= sesskey.rcvctr: logger.error('CTR must increase (old %r, new %r)', sesskey.rcvctr.prefix, newCtrPrefix) raise InvalidParameterError - sesskey.rcvctr.prefix = newCtrPrefix + sesskey.rcvctr = newCtrPrefix logger.debug('handle: enc={0!r} mac={1!r} ctr={2!r}' \ .format(sesskey.rcvenc, sesskey.rcvmac, sesskey.rcvctr)) @@ -233,7 +233,7 @@ class CryptEngine(object): tlvs = [] sess = self.sessionkeys[1][0] - sess.sendctr.inc() + sess.sendctr += 1 logger.debug('create: enc={0!r} mac={1!r} ctr={2!r}' \ .format(sess.sendenc, sess.sendmac, sess.sendctr)) @@ -243,7 +243,7 @@ class CryptEngine(object): encmsg = AESCTR(sess.sendenc, sess.sendctr).encrypt(plainBuf) msg = proto.DataMessage(flags, self.ourKeyid-1, self.theirKeyid, - long_to_bytes(self.ourDHKey.pub), sess.sendctr.byteprefix(), + long_to_bytes(self.ourDHKey.pub), long_to_bytes(sess.sendctr, 8), encmsg, b'', b''.join(self.savedMacKeys)) self.savedMacKeys = []