This commit is contained in:
Bohdan Horbeshko 2022-10-15 03:14:51 +03:00
parent 2e58741ce6
commit f47352751d
3 changed files with 26 additions and 47 deletions

View file

@ -25,4 +25,4 @@ from gajim_otrplugin.potr.utils import human_hash
''' version is: (major, minor, patch, sub) with sub being one of 'alpha', ''' version is: (major, minor, patch, sub) with sub being one of 'alpha',
'beta', 'final' ''' 'beta', 'final' '''
VERSION = (1, 0, 0, 'final') VERSION = (1, 0, 3, 'alpha')

View file

@ -16,17 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License # 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/>. # along with this library. If not, see <http://www.gnu.org/licenses/>.
try:
import Cryptodome
except ImportError:
import crypto as Crypto
from Cryptodome import Cipher from Cryptodome import Cipher
from Cryptodome.Hash import HMAC as _HMAC
from Cryptodome.Hash import SHA256 as _SHA256 from Cryptodome.Hash import SHA256 as _SHA256
from Cryptodome.Hash import SHA as _SHA1 from Cryptodome.Hash import SHA as _SHA1
from Cryptodome.Hash import HMAC as _HMAC
from Cryptodome.PublicKey import DSA 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 numbers import Number
from gajim_otrplugin.potr.compatcrypto import common from gajim_otrplugin.potr.compatcrypto import common
@ -46,36 +45,14 @@ def SHA256HMAC(key, data):
def AESCTR(key, counter=0): def AESCTR(key, counter=0):
if isinstance(counter, Number): if isinstance(counter, Number):
counter = Counter(counter) counter = Counter.new(nbits=64, prefix=long_to_bytes(counter, 8), initial_value=0)
if not isinstance(counter, Counter): # 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 raise TypeError
return Cipher.AES.new(key, Cipher.AES.MODE_CTR, counter=counter) 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 '<Counter(p={p!r},v={v!r})>'.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 @common.registerkeytype
class DSAKey(common.PK): class DSAKey(common.PK):
keyType = 0x0000 keyType = 0x0000
@ -108,12 +85,14 @@ class DSAKey(common.PK):
def sign(self, data): def sign(self, data):
# 2 <= K <= q # 2 <= K <= q
K = randrange(2, self.priv.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) return long_to_bytes(r, 20) + long_to_bytes(s, 20)
def verify(self, data, sig): def verify(self, data, sig):
r, s = bytes_to_long(sig[:20]), bytes_to_long(sig[20:]) 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): def __hash__(self):
return bytes_to_long(self.fingerprint()) return bytes_to_long(self.fingerprint())
@ -129,8 +108,8 @@ class DSAKey(common.PK):
@classmethod @classmethod
def generate(cls): def generate(cls):
privkey = DSA.generate(1024) privkey = DSA.generate(1024)
return cls((privkey.key.y, privkey.key.g, privkey.key.p, privkey.key.q, return cls((privkey.y, privkey.g, privkey.p, privkey.q,
privkey.key.x), private=True) privkey.x), private=True)
@classmethod @classmethod
def parsePayload(cls, data, private=False): def parsePayload(cls, data, private=False):
@ -144,7 +123,7 @@ class DSAKey(common.PK):
return cls((y, g, p, q), private=False), data return cls((y, g, p, q), private=False), data
def getrandbits(k): def getrandbits(k):
return Cryptodome.Random.random.getrandbits(k) return random.getrandbits(k)
def randrange(start, stop): def randrange(start, stop):
return Cryptodome.Random.random.randrange(start, stop) return random.randrange(start, stop)

View file

@ -24,7 +24,7 @@ import struct
from gajim_otrplugin.potr.compatcrypto import SHA256, SHA1, SHA1HMAC, SHA256HMAC, \ 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.utils import bytes_to_long, long_to_bytes, pack_mpi, read_mpi
from gajim_otrplugin.potr import proto from gajim_otrplugin.potr import proto
@ -70,8 +70,8 @@ class DHSession(object):
self.sendmac = sendmac self.sendmac = sendmac
self.rcvenc = rcvenc self.rcvenc = rcvenc
self.rcvmac = rcvmac self.rcvmac = rcvmac
self.sendctr = Counter(0) self.sendctr = 0
self.rcvctr = Counter(0) self.rcvctr = 0
self.sendmacused = False self.sendmacused = False
self.rcvmacused = False self.rcvmacused = False
@ -178,12 +178,12 @@ class CryptEngine(object):
sesskey.rcvmacused = True sesskey.rcvmacused = True
newCtrPrefix = bytes_to_long(msg.ctr) newCtrPrefix = bytes_to_long(msg.ctr)
if newCtrPrefix <= sesskey.rcvctr.prefix: if newCtrPrefix <= sesskey.rcvctr:
logger.error('CTR must increase (old %r, new %r)', logger.error('CTR must increase (old %r, new %r)',
sesskey.rcvctr.prefix, newCtrPrefix) sesskey.rcvctr.prefix, newCtrPrefix)
raise InvalidParameterError raise InvalidParameterError
sesskey.rcvctr.prefix = newCtrPrefix sesskey.rcvctr = newCtrPrefix
logger.debug('handle: enc={0!r} mac={1!r} ctr={2!r}' \ logger.debug('handle: enc={0!r} mac={1!r} ctr={2!r}' \
.format(sesskey.rcvenc, sesskey.rcvmac, sesskey.rcvctr)) .format(sesskey.rcvenc, sesskey.rcvmac, sesskey.rcvctr))
@ -233,7 +233,7 @@ class CryptEngine(object):
tlvs = [] tlvs = []
sess = self.sessionkeys[1][0] sess = self.sessionkeys[1][0]
sess.sendctr.inc() sess.sendctr += 1
logger.debug('create: enc={0!r} mac={1!r} ctr={2!r}' \ logger.debug('create: enc={0!r} mac={1!r} ctr={2!r}' \
.format(sess.sendenc, sess.sendmac, sess.sendctr)) .format(sess.sendenc, sess.sendmac, sess.sendctr))
@ -243,7 +243,7 @@ class CryptEngine(object):
encmsg = AESCTR(sess.sendenc, sess.sendctr).encrypt(plainBuf) encmsg = AESCTR(sess.sendenc, sess.sendctr).encrypt(plainBuf)
msg = proto.DataMessage(flags, self.ourKeyid-1, self.theirKeyid, 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)) encmsg, b'', b''.join(self.savedMacKeys))
self.savedMacKeys = [] self.savedMacKeys = []