commit 09b9bcb469097fd42996695cf65a1ed5a981582c
parent 02e72893c2db9a182b9e82c5b02fd2a150ca43e0
Author: Jaromil <jaromil@dyne.org>
Date: Sun, 16 Nov 2014 16:45:28 +0100
actual tomber sourcecode inclusion
Diffstat:
6 files changed, 355 insertions(+), 0 deletions(-)
diff --git a/extras/tomber/tomber/__init__.py 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
Binary files differ.
diff --git a/extras/tomber/tomber/test.py 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
@@ -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 <reiven_at_gmail.com>
+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
diff --git a/extras/tomber/tomber/tools/parser.py 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