Skip to content

Commit

Permalink
Merge a5086cb into c9748b8
Browse files Browse the repository at this point in the history
  • Loading branch information
t184256 committed Dec 2, 2019
2 parents c9748b8 + a5086cb commit daf2b5b
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 26 deletions.
43 changes: 23 additions & 20 deletions tlslite/utils/openssl_tripledes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,36 @@ class OpenSSL_TripleDES(TripleDES):

def __init__(self, key, mode, IV):
TripleDES.__init__(self, key, mode, IV, "openssl")
self.key = key
self.IV = IV
self._IV, self._key = IV, key
self._context = None

def _createContext(self, encrypt):
context = m2.cipher_ctx_new()
def _init_context(self, encrypt=True):
cipherType = m2.des_ede3_cbc()
m2.cipher_init(context, cipherType, self.key, self.IV, encrypt)
return context
self._context = m2.cipher_ctx_new()
m2.cipher_init(self._context, cipherType, self._key, self._IV,
int(encrypt))
m2.cipher_set_padding(self._context, 0)
self._encrypt = encrypt

def encrypt(self, plaintext):
if self._context is None:
self._init_context(encrypt=True)
else:
assert self._encrypt, '.encrypt() not allowed after .decrypt()'
TripleDES.encrypt(self, plaintext)
context = self._createContext(1)
ciphertext = m2.cipher_update(context, plaintext)
m2.cipher_ctx_free(context)
self.IV = ciphertext[-self.block_size:]
ciphertext = m2.cipher_update(self._context, plaintext)
return bytearray(ciphertext)

def decrypt(self, ciphertext):
if self._context is None:
self._init_context(encrypt=False)
else:
assert not self._encrypt, \
'.decrypt() not allowed after .decrypt()'
TripleDES.decrypt(self, ciphertext)
context = self._createContext(0)
#I think M2Crypto has a bug - it fails to decrypt and return the last block passed in.
#To work around this, we append sixteen zeros to the string, below:
plaintext = m2.cipher_update(context, ciphertext+(b'\0'*16))

#If this bug is ever fixed, then plaintext will end up having a garbage
#plaintext block on the end. That's okay - the below code will ignore it.
plaintext = plaintext[:len(ciphertext)]
m2.cipher_ctx_free(context)
self.IV = ciphertext[-self.block_size:]
plaintext = m2.cipher_update(self._context, ciphertext)
return bytearray(plaintext)

def __del__(self):
if self._context is not None:
m2.cipher_ctx_free(self._context)
10 changes: 4 additions & 6 deletions tlslite/utils/python_tripledes.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,10 @@ def __init__(self, key, iv=None):
self.name = "3des"
self.implementation = "python"

self.__key1.iv = self.iv
self.__key2.iv = self.iv
self.__key3.iv = self.iv

def encrypt(self, data):
"""Encrypt data and return bytes.
Expand All @@ -437,9 +441,6 @@ def encrypt(self, data):
raise ValueError("Invalid data length, must be a multiple "
"of {0} bytes".format(self.block_size))

self.__key1.iv = self.iv
self.__key2.iv = self.iv
self.__key3.iv = self.iv
i = 0
result = []
while i < len(data):
Expand Down Expand Up @@ -473,9 +474,6 @@ def decrypt(self, data):
raise ValueError("Invalid data length, must be a multiple "
"of {0} bytes".format(self.block_size))

self.__key1.iv = self.iv
self.__key2.iv = self.iv
self.__key3.iv = self.iv
i = 0
result = []
while i < len(data):
Expand Down
81 changes: 81 additions & 0 deletions unit_tests/test_tlslite_utils_tripledes_split.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright (c) 2019, Alexander Sosedkin
#
# See the LICENSE file for legal information regarding use of this file.

# compatibility with Python 2.6, for that we need unittest2 package,
# which is not available on 3.3 or 3.4
try:
import unittest2 as unittest
except ImportError:
import unittest

import sys

from hypothesis import given, assume, settings
from hypothesis.strategies import binary, integers, tuples

from tlslite.utils import cryptomath

import tlslite.utils.python_tripledes
py_3des = tlslite.utils.python_tripledes.new


HYP_SETTINGS = {'deadline': None} if sys.version_info > (2, 7) else {}


class TestTripleDES(unittest.TestCase):
_given = given(binary(24, 24), # key
binary(8, 8), # iv
binary(13 * 8, 13 * 8), # plaintext
(tuples(integers(0, 13), integers(0, 13)) # split points
.filter(lambda split_pts: split_pts[0] <= split_pts[1])
.map(lambda lengths: [i * 8 for i in lengths])))

def split_test(self, key, iv, plaintext, split_points, make_impl=py_3des):
i, j = split_points

ciphertext = make_impl(key, iv).encrypt(plaintext)
self.assertEqual(make_impl(key, iv).decrypt(ciphertext), plaintext)

impl = make_impl(key, iv)
pl1, pl2, pl3 = plaintext[:i], plaintext[i:j], plaintext[j:]
ci1, ci2, ci3 = impl.encrypt(pl1), impl.encrypt(pl2), impl.encrypt(pl3)
self.assertEqual(ci1 + ci2 + ci3, ciphertext)

impl = make_impl(key, iv)
pl1, pl2, pl3 = impl.decrypt(ci1), impl.decrypt(ci2), impl.decrypt(ci3)
self.assertEqual(pl1 + pl2 + pl3, plaintext)

return ciphertext

@_given
@settings(**HYP_SETTINGS)
def test_python(self, key, iv, plaintext, split_points):
self.split_test(key, iv, plaintext, split_points)

@unittest.skipIf(not cryptomath.m2cryptoLoaded, "requires M2Crypto")
@_given
@settings(**HYP_SETTINGS)
def test_python_vs_mcrypto(self, key, iv, plaintext, split_points):
import tlslite.utils.openssl_tripledes
m2_3des = lambda k, iv: tlslite.utils.openssl_tripledes.new(k, 2, iv)

py_res = self.split_test(key, iv, plaintext, split_points, py_3des)
m2_res = self.split_test(key, iv, plaintext, split_points, m2_3des)
self.assertEqual(py_res, m2_res)

@unittest.skipIf(not cryptomath.pycryptoLoaded, "requires pycrypto")
@_given
@settings(deadline=None)
def test_python_vs_pycrypto(self, key, iv, plaintext, split_points):
import tlslite.utils.pycrypto_tripledes
pc_3des = lambda k, iv: tlslite.utils.pycrypto_tripledes.new(k, 2, iv)

try:
py_res = self.split_test(key, iv, plaintext, split_points, py_3des)
pc_res = self.split_test(key, iv, plaintext, split_points, pc_3des)
self.assertEqual(py_res, pc_res)
except ValueError as e:
# pycrypto deliberately rejects weak 3DES keys, skip such keys
assume(e.args != ('Triple DES key degenerates to single DES',))
raise

0 comments on commit daf2b5b

Please sign in to comment.