From 09b9bcb469097fd42996695cf65a1ed5a981582c Mon Sep 17 00:00:00 2001 From: Jaromil Date: Sun, 16 Nov 2014 16:45:28 +0100 Subject: [PATCH] actual tomber sourcecode inclusion --- extras/tomber/tomber/__init__.py | 2 + extras/tomber/tomber/test.jpg | Bin 0 -> 51703 bytes extras/tomber/tomber/test.py | 104 ++++++++++++ extras/tomber/tomber/tomber.py | 214 +++++++++++++++++++++++++ extras/tomber/tomber/tools/__init__.py | 0 extras/tomber/tomber/tools/parser.py | 33 ++++ 6 files changed, 353 insertions(+) create mode 100644 extras/tomber/tomber/__init__.py create mode 100644 extras/tomber/tomber/test.jpg create mode 100644 extras/tomber/tomber/test.py create mode 100644 extras/tomber/tomber/tomber.py create mode 100644 extras/tomber/tomber/tools/__init__.py create mode 100644 extras/tomber/tomber/tools/parser.py diff --git a/extras/tomber/tomber/__init__.py b/extras/tomber/tomber/__init__.py new file mode 100644 index 0000000..6f7cfbe --- /dev/null +++ b/extras/tomber/tomber/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from tomber import * \ No newline at end of file diff --git a/extras/tomber/tomber/test.jpg b/extras/tomber/tomber/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a92dd32488c3118dc4d794b62cfcf82c2f72ad39 GIT binary patch literal 51703 zcmeIwNlesG9DwonrtP$y86q791TqLSfPf)HhEc$12%sq3z}*|Tdjl8L#6)oShP&Rt z6>q4xokVfH;R<*WcRhg{%4O_;(ZrK__4~iPUi#AXYk!g6$TJaJRZ&?Xq!dEhOGKWE za$z`~x>GZBT{lg`3Id=Q1l_vG)<4&lNb||7z+3Up}(HUHDMXLy%ZS~4ofPQjC6}s`#m)|I^xGj zhoWju-7sBl`#@)`a7aaQsEVeks(pHkeP5`S<_+YRI^(Kq^_Jb0&qSOf4)bo>o3{R>kZ&l~r@+&0nx^(c&dbmn~nha@FcJ zYuByc(718a=55<|?A*0`&)$9e4;(yn_{h;?ZO2cXJazg^``L5nFLYkKbot8F>o>Y@ z-nxC~?!EgD9zJ^fq_?ks;Q5P}uU@}-`|kbFhmW5=e;NMzZ6w+yg))|9U&q3J>$2=F zhpH;79_^BjMtdukss-|$-qLElwmvQxYBGFfEv+40W_m%*V0>Lek1HV~JdimQO&cxy zv#{oWD*GAstE*pl6lwoF#S$fAcqF@RtBcJyzyJm?fB_6(00S7n00uCC0SsUO0~o*n z1~7mD3}65Q7{CAqFn|FJU;qOczyJm?fB_6(00S7n00uCC0SsUO0~o*n1~7mD3}65Q z7{CAqFn|FJU;qOczyJm?fB_6(00S7n00uCC0SsUO0~o*n1~7mD3}65Q7{CAqFn|FJ zU;qOczyJm?fB_6(00S7n00uCC0SsUO0~o*n1~7mD3}65Q7{CAqFn|FJU;qOczyJm? zfB_6(00S7n00uCC0SsUO0~o*n1~7mD3}65Q7{CAqFn|FJU;qOczyJm?fB_6(00S7n v00uCC0SsUO0~o*n1~7mD3}65Q7{CAqFn|FJU;qOczyJm?@Lw7ziS&I3(a8`D literal 0 HcmV?d00001 diff --git a/extras/tomber/tomber/test.py b/extras/tomber/tomber/test.py new file mode 100644 index 0000000..90e2081 --- /dev/null +++ b/extras/tomber/tomber/test.py @@ -0,0 +1,104 @@ +import os +import unittest +from tomber import * +from random import randrange +from shutil import rmtree, copyfile + + +class tomberTester(unittest.TestCase): + + @classmethod + def setUpClass(self): + self.pid = str(os.getpid()) + self.tombfile = '.'.join([self.pid, 'tomb']) + self.keyfile = '.'.join([self.pid, 'key']) + self.keyfile2 = '.'.join([self.pid, '2ndkey']) + self.exhumedkey = '.'.join([self.pid, 'exhumed']) + self.mountpath = './tmptomb' + # generate a passphrase with spaces + self.passphrase = str(randrange(2 ** 64)).replace("", " ")[1:-1] + self.passphrase2 = str(randrange(2 ** 64)) + self.imagefile = '.'.join([self.pid, 'jpg']) + copyfile( + '/'.join([os.path.dirname(__file__), 'test.jpg']), + self.imagefile) + + @classmethod + def tearDownClass(self): + os.unlink(self.tombfile) + os.unlink(self.keyfile) + os.unlink(self.keyfile2) + os.unlink(self.imagefile) + os.unlink(self.exhumedkey) + rmtree(self.mountpath) + + def test_01_dig(self): + """ Dig a tomb of 10mb""" + self.assertTrue(tdig(self.tombfile, 10)[0]) + + def test_02_forge(self): + """ Forge a keyfile and set a passphrase """ + self.assertTrue(tforge(self.keyfile, self.passphrase)[0]) + + def test_03_lock(self): + """ Lock created tomb with forged keyfile """ + self.assertTrue(tlock(self.tombfile, self.keyfile, self.passphrase)[0]) + + def test_04_open(self): + """ Open the created tomb with forged keyfile and passhrase """ + self.assertTrue(topen( + self.tombfile, self.keyfile, self.passphrase, self.mountpath + )[0] + ) + + def test_05_close(self): + """ Close the created tomb """ + self.assertTrue(tclose(self.tombfile.split('.')[0])[0]) + + def test_06_resize(self): + """ Resize created tomb to 12mb """ + self.assertTrue(tresize( + self.tombfile, self.keyfile, self.passphrase, 12 + )[0] + ) + + def test_07_passwd(self): + """ Change password in keyfile """ + self.assertTrue(tpasswd( + self.keyfile, self.passphrase2, self.passphrase + )[0] + ) + + def test_08_bury(self): + """ Bury keyfile in a image file """ + self.assertTrue(tbury( + self.keyfile, self.passphrase2, self.imagefile + )[0] + ) + + def test_09_exhume(self): + """ Exhume a key from an image """ + self.assertTrue(texhume( + self.exhumedkey, self.passphrase2, self.imagefile + )[0] + ) + + def test_10_setkey(self): + """ Forge a new key and and set different keyfile to created tomb """ + tforge(self.keyfile2, self.passphrase) + self.assertTrue(tsetkey( + self.keyfile, + self.tombfile, + self.keyfile2, + self.passphrase, + self.passphrase2 + )[0] + ) + + def test_11_slam(self): + """ Slam open tombs """ + topen(self.tombfile, self.keyfile, self.passphrase2, self.mountpath) + self.assertTrue(tslam()[0]) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/extras/tomber/tomber/tomber.py b/extras/tomber/tomber/tomber.py new file mode 100644 index 0000000..e790cfe --- /dev/null +++ b/extras/tomber/tomber/tomber.py @@ -0,0 +1,214 @@ +# -*- coding: utf8 -*- + +""" + +tomber - a python Tomb (the Crypto Undertaker) wrapper +To use tomber you need to install Tomb (https://github.com/dyne/Tomb) +Copyright © 2014, Federico reiven +Licensed under BSD License. +See also LICENSE file + +""" + + +from subprocess import Popen, PIPE +from tools import parser + + +def get_message(stderr, type): + """ + Helper to return exit messages from command execution + """ + response = [] + for line in stderr.split('\n'): + ret = parser.parse_line(line) + if ret and ret['type'] == type: + if not 'swaps' in ret['content']: + response.append(ret['content']) + return response + + +def execute(cmd): + """ + Execute given cmd. return boolean based on exit status and error string + """ + p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) + stdout, stderr = p.communicate() + p_status = p.wait() + if p_status == 0: + return True, get_message(stderr, 'success') + else: + return False, get_message(stderr, 'error') + + +def sanitize_passphrase(passphrase): + """ + Used to avoid errors with passphrases which include spaces + """ + return ''.join(['"', passphrase, '"']) + + +def tdig(tombfile, size, force=False): + """ + Dig a tomb of given size + """ + cmd = ' '.join(['tomb', 'dig', tombfile, '-s', str(size), '--no-color']) + if force: + cmd += " -f" + return execute(cmd) + + +def tforge(keyfile, passphrase, force=False): + """ + Forge a key with given passphrase + """ + cmd = ' '.join(['tomb', + 'forge', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(passphrase), + '--no-color']) + if force: + cmd += " -f" + return execute(cmd) + + +def tlock(tombfile, keyfile, passphrase): + """ + Lock a tomb file with given key and passphrase. + """ + cmd = ' '.join(['tomb', + 'lock', + tombfile, + '-k', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(passphrase), + '--no-color']) + return execute(cmd) + + +def topen(tombfile, keyfile, passphrase, mountpath=False): + """ + Open (mount) a tomb. + Keyfile and passphrase are needed, mountpoint is optional + """ + if not mountpath: + mountpath = '' + cmd = ' '.join(['tomb', + 'open', + tombfile, + '-k', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(passphrase), + '--no-color', + mountpath]) + return execute(cmd) + + +def tclose(tombfile): + """ + Close (umount) a tomb + """ + cmd = ' '.join(['tomb', 'close', tombfile, '--no-color']) + return execute(cmd) + + +def tresize(tombfile, keyfile, passphrase, newsize): + """ + Resize a tomb. + Keyfile, passphrase and new size are needed. + """ + cmd = ' '.join(['tomb', + 'resize', + tombfile, + '-k', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(passphrase), + '-s', + str(newsize), + '--no-color']) + return execute(cmd) + + +def tbury(keyfile, passphrase, imagefile): + """ + Bury a key inside a jpg file + """ + cmd = ' '.join(['tomb', + 'bury', + '-k', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(passphrase), + imagefile, + '--no-color']) + return execute(cmd) + + +def texhume(keyfile, passphrase, imagefile): + """ + Exhume (recover) key from jpg file. Passphrase for key is needed + """ + cmd = ' '.join(['tomb', + 'exhume', + '-k', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(passphrase), + imagefile, + '--no-color']) + return execute(cmd) + + +def tpasswd(keyfile, newpassphrase, oldpassphrase): + """ + Change current passphrase from keyfile + """ + cmd = ' '.join(['tomb', + 'passwd', + '-k', + keyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(newpassphrase), + '--tomb-old-pwd', + sanitize_passphrase(oldpassphrase), + '--no-color']) + return execute(cmd) + + +def tsetkey(oldkeyfile, tombfile, newkeyfile, newpassphrase, oldpassphrase): + """ + Change lock key for a tomb + The old key+passphrase and new key+passphrase are needed + """ + cmd = ' '.join(['tomb', + 'setkey', + oldkeyfile, + tombfile, + '-k', + newkeyfile, + '--unsecure-dev-mode', + '--tomb-pwd', + sanitize_passphrase(newpassphrase), + '--tomb-old-pwd', + sanitize_passphrase(oldpassphrase), + '--no-color']) + return execute(cmd) + + +def tslam(): + """ + Slam tombs, killing all programs using it + """ + cmd = ' '.join(['tomb', 'slam']) + return execute(cmd) diff --git a/extras/tomber/tomber/tools/__init__.py b/extras/tomber/tomber/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extras/tomber/tomber/tools/parser.py b/extras/tomber/tomber/tools/parser.py new file mode 100644 index 0000000..bfeed49 --- /dev/null +++ b/extras/tomber/tomber/tools/parser.py @@ -0,0 +1,33 @@ +''' +Utilities to analyze tomb output +''' +import re + +#found: [m] followed by some ID (usually "found") inside square brackets, then +#something else, then a space, then the content +_found_regex = re.compile(r'^\[m\]\[([^]]+)\] +(([^:]+)://(.+))$') +#generic: programname, then some identifiers in square (or round) brackets, +#then maybe something else, then a space, then the context +_generic_regex = re.compile(r'^[a-z-]+ [[(]([^]]+)[\])] +(.+)$') +types = {'E': 'error', 'W': 'warning', 'D': 'debug', '*': 'success'} + + +def parse_line(line): + '''Analyze a single line. + Return None if no standard format is detected, a dict otherwise. + The fields 'type' and 'content' are always in the dict; 'content' may be + empty + 'type' can be 'error', 'progress' + ''' + + match = _found_regex.match(line) + if match: + return {'type': types.get(match.group(1)) or match.group(1), + 'content': match.group(2), 'scheme': match.group(3), + 'path': match.group(4)} + match = _generic_regex.search(line) + if match: + return {'type': types.get(match.group(1)) or match.group(1), + 'content': match.group(2)} + + return None