From: Philipp Gesang Date: Tue, 18 Apr 2017 13:04:07 +0000 (+0200) Subject: rework encryption unittests X-Git-Tag: v2.2~7^2~161 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=fbfda3d4dfdb30f5c8b430a3e8df0ede82453dd9;p=python-delta-tar rework encryption unittests --- diff --git a/deltatar/crypto.py b/deltatar/crypto.py index 5460dec..5fa4048 100755 --- a/deltatar/crypto.py +++ b/deltatar/crypto.py @@ -676,7 +676,7 @@ class Decrypt (Crypto): # this won’t catch malformed specs though raise InvalidParameter ("next: wrong type of parameter hdr: " "expected bytes or spec, got %s" - % type (tag)) + % type (hdr)) try: paramversion = hdr ["paramversion"] nacl = hdr ["nacl"] diff --git a/testing/__init__.py b/testing/__init__.py index 527c751..1553324 100644 --- a/testing/__init__.py +++ b/testing/__init__.py @@ -18,12 +18,22 @@ import os, unittest, hashlib, string import random -def new_volume_handler(tarobj, base_name, volume_number): +import sys + +def new_volume_handler(tarobj, base_name, volume_number, encryption=None): ''' Handles the new volumes ''' volume_path = "%s.%d" % (base_name, volume_number) - tarobj.open_volume(volume_path) + tarobj.open_volume(volume_path, encryption=encryption) + +def make_new_encryption_volume_handler(encryption): + ''' + Handles the new volumes using the right crypto context. + ''' + return lambda tarobj, base_name, volume_number: \ + new_volume_handler (tarobj, base_name, volume_number, + encryption=encryption) def closing_new_volume_handler(tarobj, base_name, volume_number): ''' diff --git a/testing/test_encryption.py b/testing/test_encryption.py index 432acdf..5088ab2 100644 --- a/testing/test_encryption.py +++ b/testing/test_encryption.py @@ -17,54 +17,75 @@ import os +from deltatar import crypto from deltatar.tarfile import TarFile, GNU_FORMAT import filesplit from . import BaseTest -from . import new_volume_handler +from . import new_volume_handler, make_new_encryption_volume_handler +DELTATAR_HEADER_VERSION = 1 +DELTATAR_PARAMETER_VERSION = 1 class EncryptionTest(BaseTest): """ Test encryption after compression in tarfiles """ - def test_openssl_decrypt(self): + def test_cli_decrypt(self): """ Create a tar file with only one file inside, using concat - compression and encryption mode. Then decrypt with openssl, + compression and encryption mode. Then decrypt with crypto.py, decompress it with zcat and untar it with gnu tar. + + Note that in an earlier implementation of the Deltatar crypto + layer, files could be decrypted directly using OpenSSL command + line tools. With the version 1 parameters this is no longer + possible since OpenSSL does not ship with a command line tool + that understands GCM and even if it did, it would be very + unlikely that it could be made with the raw pdtcrypt format. + + Thus, we rely on the functionality of our encryption library + ``crypto.py`` to decrypt on the command line; the rest of the + data pipeline (→ gzip → tar → files) remains the same. """ # create the content of the file to compress and hash it hash = self.create_file("big", 50000) + # create the encryption handler + encryptor = crypto.Encrypt (password="key", + version=DELTATAR_HEADER_VERSION, + paramversion=DELTATAR_PARAMETER_VERSION) + # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="w#gz.aes128", + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="w#gz", format=GNU_FORMAT, concat_compression=True, - password='key') + encryption=encryptor) tarobj.add("big") tarobj.close() os.unlink("big") - # extract with normal tar and check output - filesplit.split_file(b'Salted__', "sample.tar.gz.aes.", "sample.tar.gz.aes128") + #filesplit.split_file(b'Salted__', "sample.tar.gz.aes.", "sample.tar.gz.aes128") - assert os.path.exists("sample.tar.gz.aes.0") # beginning of the tar file - assert os.path.exists("sample.tar.gz.aes.1") # first file + # decrypt outer archive layer with crypto.py + assert os.path.exists("sample.tar.gz.pdtcrypt") + ret = os.system("python3 -s ./deltatar/crypto.py key sample.tar.gz") + assert ret == 0 + assert os.path.exists("sample.tar.gz") - os.system("openssl aes-128-cbc -nopad -k 'key' -d -in sample.tar.gz.aes.1 -out sample.tar.gz") + # extract with normal tar and check output os.system("zcat sample.tar.gz 2>/dev/null > sample.tar") os.system("tar xf sample.tar") assert os.path.exists("big") assert hash == self.md5sum("big") - def test_openssl_multiple_files_decrypt(self): + def test_cli_multiple_files_decrypt(self): """ Create a tar file with multiple files inside, using concat - compression and encryption mode. Then decrypt with openssl, + compression and encryption mode. Then decrypt with ``crypto.py``, decompress it with zcat and untar it with gnu tar. """ @@ -74,12 +95,17 @@ class EncryptionTest(BaseTest): hash["small"] = self.create_file("small", 100) hash["small2"] = self.create_file("small2", 354) + # create the encryption handler + encryptor = crypto.Encrypt (password="key", + version=DELTATAR_HEADER_VERSION, + paramversion=DELTATAR_PARAMETER_VERSION) + # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="w#gz.aes128", + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="w#gz", format=GNU_FORMAT, concat_compression=True, - password='key') + encryption=encryptor) for k in hash: tarobj.add(k) @@ -88,26 +114,18 @@ class EncryptionTest(BaseTest): for k in hash: os.unlink(k) - # extract with normal tar and check output - filesplit.split_file(b'Salted__', "sample.tar.gz.aes.", "sample.tar.gz.aes128") - - assert os.path.exists("sample.tar.gz.aes.0") # beginning of the tar file - assert os.path.exists("sample.tar.gz.aes.1") # first file - assert os.path.exists("sample.tar.gz.aes.2") # second file - assert os.path.exists("sample.tar.gz.aes.3") # third file - assert not os.path.exists("sample.tar.gz.aes.4") # nothing else - - # extract and check output - for i in range(1, 4): - fname = "sample.tar.gz.aes.%d" % i - os.system("openssl aes-128-cbc -nopad -k 'key' -d -in %s -out sample.tar.gz" % fname) - os.system("zcat sample.tar.gz 2>/dev/null > sample.tar") - os.system("tar xf sample.tar") + assert os.path.exists("sample.tar.gz.pdtcrypt") + ret = os.system("python3 -s ./deltatar/crypto.py key sample.tar.gz") + assert ret == 0 + assert os.path.exists("sample.tar.gz") + os.system("zcat sample.tar.gz 2>/dev/null > sample.tar") + os.system("tar xf sample.tar") for key, value in hash.items(): assert os.path.exists(key) assert value == self.md5sum(key) + def test_decrypt(self): """ Create a tar file with only one file inside, using concat @@ -117,20 +135,26 @@ class EncryptionTest(BaseTest): # create the content of the file to compress and hash it hash = self.create_file("big", 50000) + # encryption handling + encryptor = crypto.Encrypt (password="key", + version=DELTATAR_HEADER_VERSION, + paramversion=DELTATAR_PARAMETER_VERSION) + decryptor = crypto.Decrypt (password="key") + # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="w#gz.aes128", + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="w#gz", format=GNU_FORMAT, concat_compression=True, - password='key') + encryption=encryptor) tarobj.add("big") tarobj.close() os.unlink("big") - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="r#gz.aes128", + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="r#gz", format=GNU_FORMAT, - password='key') + encryption = decryptor) tarobj.extractall() tarobj.close() assert os.path.exists("big") @@ -149,12 +173,16 @@ class EncryptionTest(BaseTest): hash["small"] = self.create_file("small", 100) hash["small2"] = self.create_file("small2", 354) + encryptor = crypto.Encrypt (password="key", + version=DELTATAR_HEADER_VERSION, + paramversion=DELTATAR_PARAMETER_VERSION) + # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="w#gz.aes128", + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="w#gz", format=GNU_FORMAT, concat_compression=True, - password='key') + encryption=encryptor) for k in hash: tarobj.add(k) @@ -163,10 +191,12 @@ class EncryptionTest(BaseTest): for k in hash: os.unlink(k) - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="r#gz.aes128", + decryptor = crypto.Decrypt (password="key") + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="r#gz", format=GNU_FORMAT, - password='key') + encryption=decryptor) + tarobj.extractall() tarobj.close() @@ -174,6 +204,7 @@ class EncryptionTest(BaseTest): assert os.path.exists(key) assert value == self.md5sum(key) + def test_multivol_file_decrypt(self): ''' Test multivol tarball with encryption. @@ -186,68 +217,44 @@ class EncryptionTest(BaseTest): hash["small"] = self.create_file("small", 100) hash["small2"] = self.create_file("small2", 354) - # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="w#gz.aes128", - password='key', - concat_compression=True, - max_volume_size=20000, - new_volume_handler=new_volume_handler) - - for k in hash: - tarobj.add(k) - tarobj.close() - - assert os.path.exists("sample.tar.gz.aes128") - for k in hash: - os.unlink(k) - - # extract - tarobj = TarFile.open("sample.tar.gz.aes128", - mode="r#gz.aes128", - password="key", - new_volume_handler=new_volume_handler) - tarobj.extractall() - tarobj.close() - - # check output - for key, value in hash.items(): - assert os.path.exists(key) - assert value == self.md5sum(key) - - def test_multivol_file_decrypt_aes256(self): - ''' - Test multivol tarball with encryption aes256 - ''' + # encryption handler + encryptor = crypto.Encrypt (password="key", + version=DELTATAR_HEADER_VERSION, + paramversion=DELTATAR_PARAMETER_VERSION) - # create sample data - hash = dict() - hash["big"] = self.create_file("big", 50000) - hash["big2"] = self.create_file("big2", 10200) - hash["small"] = self.create_file("small", 100) - hash["small2"] = self.create_file("small2", 354) + # plug the encryption context into the volume handler + encrypt_volume = make_new_encryption_volume_handler (encryptor) - # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes256", - mode="w#gz.aes256", - password='key', + # create the tar file with volumes; we need to use a low compression + # level to force volume split because the test data has too little + # entropy + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="w#gz", concat_compression=True, max_volume_size=20000, - new_volume_handler=new_volume_handler) + compresslevel=0, + new_volume_handler=encrypt_volume, + encryption=encryptor) for k in hash: tarobj.add(k) tarobj.close() - assert os.path.exists("sample.tar.gz.aes256") + assert os.path.exists("sample.tar.gz.pdtcrypt") for k in hash: os.unlink(k) + # decrypt + decryptor = crypto.Decrypt (password="key") + + # plug the encryption context into the volume handler + decrypt_volume = make_new_encryption_volume_handler (decryptor) + # extract - tarobj = TarFile.open("sample.tar.gz.aes256", - mode="r#gz.aes256", - password="key", - new_volume_handler=new_volume_handler) + tarobj = TarFile.open("sample.tar.gz.pdtcrypt", + mode="r#gz", + new_volume_handler=decrypt_volume, + encryption=decryptor) tarobj.extractall() tarobj.close() @@ -256,36 +263,3 @@ class EncryptionTest(BaseTest): assert os.path.exists(key) assert value == self.md5sum(key) - def test_openssl_decrypt_256(self): - """ - Create a tar file with only one file inside, using concat - compression and encryption mode. Then decrypt with openssl, - decompress it with zcat and untar it with gnu tar. - - Using aes 256. - """ - - # create the content of the file to compress and hash it - hash = self.create_file("big", 50000) - - # create the tar file with volumes - tarobj = TarFile.open("sample.tar.gz.aes256", - mode="w#gz.aes256", - format=GNU_FORMAT, - concat_compression=True, - password='key') - tarobj.add("big") - tarobj.close() - os.unlink("big") - - # extract with normal tar and check output - filesplit.split_file(b'Salted__', "sample.tar.gz.aes.", "sample.tar.gz.aes256") - - assert os.path.exists("sample.tar.gz.aes.0") # beginning of the tar file - assert os.path.exists("sample.tar.gz.aes.1") # first file - - os.system("openssl aes-256-cbc -nopad -k 'key' -d -in sample.tar.gz.aes.1 -out sample.tar.gz") - os.system("zcat sample.tar.gz 2>/dev/null > sample.tar") - os.system("tar xf sample.tar") - assert os.path.exists("big") - assert hash == self.md5sum("big")