2017-06-26 23:50:51 +02:00
|
|
|
from twisted.trial import unittest
|
|
|
|
from twisted.internet import defer
|
|
|
|
from lbrynet.cryptstream import CryptBlob
|
2017-09-25 18:12:40 +02:00
|
|
|
from lbrynet.blob.blob_file import MAX_BLOB_SIZE
|
2017-06-26 23:50:51 +02:00
|
|
|
|
2018-07-06 22:16:58 +02:00
|
|
|
from tests.mocks import mock_conf_settings
|
2017-06-26 23:50:51 +02:00
|
|
|
|
2018-05-05 03:12:43 +02:00
|
|
|
from cryptography.hazmat.primitives.ciphers.algorithms import AES
|
2017-06-26 23:50:51 +02:00
|
|
|
import random
|
|
|
|
import string
|
2018-07-12 21:35:59 +02:00
|
|
|
from six import BytesIO
|
2018-05-05 03:12:43 +02:00
|
|
|
import os
|
|
|
|
|
2018-07-12 21:35:59 +02:00
|
|
|
AES_BLOCK_SIZE_BYTES = int(AES.block_size / 8)
|
2017-06-26 23:50:51 +02:00
|
|
|
|
|
|
|
class MocBlob(object):
|
|
|
|
def __init__(self):
|
2018-07-12 21:35:59 +02:00
|
|
|
self.data = b''
|
2017-06-26 23:50:51 +02:00
|
|
|
|
|
|
|
def read(self, write_func):
|
|
|
|
data = self.data
|
|
|
|
write_func(data)
|
|
|
|
return defer.succeed(True)
|
|
|
|
|
2017-09-29 20:43:29 +02:00
|
|
|
def open_for_reading(self):
|
2018-07-12 21:35:59 +02:00
|
|
|
return BytesIO(self.data)
|
2017-09-29 20:43:29 +02:00
|
|
|
|
2017-06-26 23:50:51 +02:00
|
|
|
def write(self, data):
|
2018-07-12 21:35:59 +02:00
|
|
|
if not isinstance(data, bytes):
|
|
|
|
data = data.encode()
|
2017-06-26 23:50:51 +02:00
|
|
|
self.data += data
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
return defer.succeed(True)
|
|
|
|
|
|
|
|
|
|
|
|
def random_string(length):
|
2018-07-12 21:35:59 +02:00
|
|
|
return ''.join(random.choice(string.ascii_lowercase) for i in range(length))
|
2017-06-26 23:50:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TestCryptBlob(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
|
|
mock_conf_settings(self)
|
|
|
|
|
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
|
|
|
def _test_encrypt_decrypt(self, size_of_data):
|
|
|
|
# max blob size is 2*2**20 -1 ( -1 due to required padding in the end )
|
|
|
|
blob = MocBlob()
|
|
|
|
blob_num = 0
|
2018-05-05 03:12:43 +02:00
|
|
|
key = os.urandom(AES_BLOCK_SIZE_BYTES)
|
|
|
|
iv = os.urandom(AES_BLOCK_SIZE_BYTES)
|
2017-06-26 23:50:51 +02:00
|
|
|
maker = CryptBlob.CryptStreamBlobMaker(key, iv, blob_num, blob)
|
|
|
|
write_size = size_of_data
|
2018-07-12 21:35:59 +02:00
|
|
|
string_to_encrypt = random_string(size_of_data).encode()
|
2017-06-26 23:50:51 +02:00
|
|
|
|
|
|
|
# encrypt string
|
2017-09-29 12:44:22 +02:00
|
|
|
done, num_bytes = maker.write(string_to_encrypt)
|
2017-06-26 23:50:51 +02:00
|
|
|
yield maker.close()
|
2017-09-29 12:44:22 +02:00
|
|
|
self.assertEqual(size_of_data, num_bytes)
|
2018-07-12 21:35:59 +02:00
|
|
|
expected_encrypted_blob_size = int((size_of_data / AES_BLOCK_SIZE_BYTES) + 1) * AES_BLOCK_SIZE_BYTES
|
2017-06-26 23:50:51 +02:00
|
|
|
self.assertEqual(expected_encrypted_blob_size, len(blob.data))
|
|
|
|
|
2017-09-25 18:12:40 +02:00
|
|
|
if size_of_data < MAX_BLOB_SIZE-1:
|
2017-06-26 23:50:51 +02:00
|
|
|
self.assertFalse(done)
|
|
|
|
else:
|
|
|
|
self.assertTrue(done)
|
2018-07-12 21:35:59 +02:00
|
|
|
self.data_buf = b''
|
2017-06-26 23:50:51 +02:00
|
|
|
|
|
|
|
def write_func(data):
|
|
|
|
self.data_buf += data
|
|
|
|
|
|
|
|
# decrypt string
|
|
|
|
decryptor = CryptBlob.StreamBlobDecryptor(blob, key, iv, size_of_data)
|
2017-09-29 20:43:29 +02:00
|
|
|
yield decryptor.decrypt(write_func)
|
2017-09-29 12:44:22 +02:00
|
|
|
self.assertEqual(self.data_buf, string_to_encrypt)
|
2017-06-26 23:50:51 +02:00
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
|
|
|
def test_encrypt_decrypt(self):
|
|
|
|
yield self._test_encrypt_decrypt(1)
|
|
|
|
yield self._test_encrypt_decrypt(16*2)
|
|
|
|
yield self._test_encrypt_decrypt(2000)
|
|
|
|
yield self._test_encrypt_decrypt(2*2**20-1)
|