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