Changeset 65


Ignore:
Timestamp:
10/17/13 12:10:35 (11 years ago)
Author:
tmorgan
Message:

added result set object and HTML generator to chosenct probe routine

Python3 fixes and code reorganization

Location:
trunk/lib/bletchley
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/bletchley/blobtools.py

    r53 r65  
    2525import operator
    2626import functools
    27 import itertools
    2827from . import buffertools
    2928
     
    479478        """
    480479        return "".join(map(lambda y:str((x>>y)&1), range(bits-1, -1, -1)))
    481 
    482 
    483 #XXX: move this to buffertools
    484 def smartPermutateBlobs(blobs, block_size=8):
    485     """
    486     Intelligently permutates through blocks in blobs.
    487     If the same blob shows up in the same place for
    488     every blob, the resultant permutations will have
    489     this property as well.
    490     blobs should be an array containing blobs
    491     block_size should be an integer block_size or an
    492     array of block sizes.
    493     """
    494 
    495     if len(blobs) == 0:
    496         return
    497 
    498     if not isinstance(block_size, (int, long)):
    499         for size in block_size:
    500              for blob in smartPermutateBlobs(blobs, size):
    501                  yield blob
    502         return
    503 
    504     # First we find the indexes of the chunks that are different
    505     different = set()
    506     for combo in itertools.combinations(blobs, 2):
    507         different |= set(buffertools.blockWiseDiff(block_size, combo[0], combo[1]))
    508    
    509     # Next we form a set containing the chunks that are different
    510     different_chunks = []
    511     for blob in blobs:
    512         different_chunks.extend([blob[i * block_size:(i + 1) * block_size] for i in different])
    513     # Remove duplicates
    514     different_chunks = set(different_chunks)
    515    
    516     # We want to know which chunks are the same, too
    517     chunk_len = len(blobs[0]) / block_size
    518     same = set(range(0, chunk_len)) - different
    519 
    520     # Now let's mix and match the differnet blocks, for all possible lengths
    521     for i in range(1, chunk_len + 1):
    522         for mix in itertools.permutations(different_chunks, i):
    523             # We add back in the part that stays the same
    524             for j in same:
    525                 mix.insert(j, blobs[0][j * block_size:(j + 1) * block_size])
    526             mix = "".join(mix)
    527             if mix in blobs:
    528                 continue
    529             yield mix
  • trunk/lib/bletchley/buffertools.py

    r49 r65  
    2020import sys
    2121import zlib
     22import itertools
    2223
    2324# Computes the block-wise differences between two strings
     
    145146
    146147    return decrypted[0:0-length]
     148
     149
     150def smartPermutateBlobs(blobs, block_size=8):
     151    """
     152    Intelligently permutates through blocks in blobs.
     153    If the same blob shows up in the same place for
     154    every blob, the resultant permutations will have
     155    this property as well.
     156    blobs should be an array containing blobs
     157    block_size should be an integer block_size or an
     158    array of block sizes.
     159    """
     160
     161    if len(blobs) == 0:
     162        return
     163
     164    if not isinstance(block_size, int):
     165        for size in block_size:
     166             for blob in smartPermutateBlobs(blobs, size):
     167                 yield blob
     168        return
     169
     170    # First we find the indexes of the chunks that are different
     171    different = set()
     172    for combo in itertools.combinations(blobs, 2):
     173        different |= set(blockWiseDiff(block_size, combo[0], combo[1]))
     174   
     175    # Next we form a set containing the chunks that are different
     176    different_chunks = []
     177    for blob in blobs:
     178        different_chunks.extend([blob[i * block_size:(i + 1) * block_size] for i in different])
     179    # Remove duplicates
     180    different_chunks = set(different_chunks)
     181   
     182    # We want to know which chunks are the same, too
     183    chunk_len = len(blobs[0]) // block_size
     184    same = set(range(0, chunk_len)) - different
     185
     186    # Now let's mix and match the differnet blocks, for all possible lengths
     187    for i in range(1, chunk_len + 1):
     188        for mix in itertools.permutations(different_chunks, i):
     189            # We add back in the part that stays the same
     190            for j in same:
     191                mix.insert(j, blobs[0][j * block_size:(j + 1) * block_size])
     192            mix = b"".join(mix)
     193            if mix in blobs:
     194                continue
     195            yield mix
  • trunk/lib/bletchley/chosenct.py

    r50 r65  
    2323import struct
    2424import queue
     25import hashlib
     26
     27# Wish Python had a better function for this that escaped more characters
     28_html_escape_table = {
     29    "&": "&",
     30    '"': """,
     31    "'": "'",
     32    ">": ">",
     33    "<": "&lt;",
     34    "\n": "&#x0a",
     35    "\r": "&#x0d",
     36    }
     37
     38def _html_escape(text):
     39    return "".join(_html_escape_table.get(c,c) for c in text)
     40
     41
     42class ProbeResults:
     43    '''TODO
     44    '''
     45    _values = None
     46    _raw_table = None #indexes are byte offset, then XORed value
     47    _messages = None
     48    _html_header = """<head>
     49<script>
     50function displayMessage(id)
     51{
     52  alert(document.getElementById(id).value);
     53}
     54</script>
     55<style>
     56td
     57{
     58  border-style: solid;
     59  border-width: medium;
     60  border-color: #FFFFFF;
     61  border-spacing: 0px;
     62  min-width: 100px;
     63  max-width: 100px;
     64  word-wrap: break-word;
     65}
     66</style></head>"""
     67
     68   
     69    def __init__(self, ct_length, values):
     70        self._ct_length = ct_length
     71        self._values = values
     72        self._raw_table = {}
     73        self._messages = {}
     74        return
     75
     76    def _generate_colors(self, s):
     77        base=bytes(hashlib.md5(s).digest()[0:6])
     78        color1 = "#%.2X%.2X%.2X" % tuple(base[:3])
     79        color2 = "#%.2X%.2X%.2X" % tuple(base[3:])
     80
     81        return color1,color2
     82
     83
     84    def toHTML(self):
     85        maxlen = 20
     86        ret_val = self._html_header
     87        ret_val += '<table><tr><td>&nbsp;&nbsp;&nbsp;OFFSET<br /><br />VALUE</td>'
     88
     89        for offset in self._raw_table.keys():
     90            ret_val += '<td>%d<br /><br /></td>' % offset
     91        ret_val += '</tr>'
     92
     93        for v in self._values:
     94            ret_val += '<tr><td>0x%.2X</td>' % v
     95            for offset in range(0,self._ct_length):
     96                message = self._raw_table[offset][v]
     97                bg,fg = self._generate_colors(message)
     98                message = message.decode('utf-8')
     99
     100                truncated = message[0:maxlen]
     101                if len(message) > maxlen:
     102                    truncated += '...'
     103                msg_id = 'cell_%.2X_%.2X' % (offset, v)
     104                ret_val += ('''<td style="background-color:%s; border-color:%s" onclick="displayMessage('%s')">'''
     105                            '''<input type="hidden" id="%s" value="%s" />%s</td>\n''')\
     106                            % (bg,fg, msg_id, msg_id, _html_escape(message), _html_escape(truncated))
     107            ret_val += '</tr>'
     108           
     109        ret_val += '</table>'
     110
     111        return ret_val
     112
    25113
    26114def probe_bytes(checker, ciphertext, values, max_threads=1):
     
    29117    error message was generated.
    30118
    31     TODO
     119    Arguments:
     120    checker -- A function which sends a specified ciphertext to the targeted
     121               application and returns a string describing the kind of response
     122               that was encountered.  This function should be thread-safe when
     123               max_threads > 1.
     124
     125               This function should implement the prototype:
     126                 def myChecker(ciphertext): ...
     127
     128               The function should return strings that are relevant to
     129               the kind of overall response generated by the targeted
     130               system or application.  For instance, if detailed error
     131               messages are returned, then the important parts of those
     132               errors should be returned.  If error messages are not
     133               returned in some cases, then simple tokens that describe
     134               the behavior of the response should suffice.  For
     135               instance, if in some cases the application returns a
     136               generic HTTP 500 error, in other cases it drops the TCP
     137               connection, and still in other cases it doesn't return an
     138               error, then the checker function could return "500",
     139               "dropped", and "success" respectively for those cases.
     140
     141    ciphertext -- A ciphertext buffer (bytes/bytearray) that will be repeatedly
     142               modified and tested using the checker function.
     143
     144    values --  A sequence of integers in the range [0..255].  These values
     145               will be XORed with each byte in the ciphertext and tested, one
     146               after another.  To make a single change to each byte in the
     147               ciphertext, provide something like [1].  To flip every bit
     148               in the entire ciphertext individually, supply: [1,2,4,8,16,32,64,128]
     149
     150    max_threads -- The maximum number of threads to run in parallel while
     151               testing modified ciphertexts.
    32152    '''
    33153    if max_threads < 1:
     
    37157    values = bytearray(values)
    38158
    39     ret_val = {}
     159    # XXX: Improve threading model
     160    #      Instead of forking threads and joining them for each byte,
     161    #      Generate all ciphertext variants up front, putting them in
     162    #      a jobs queue, and then have persistent threads pull from
     163    #      the jobs queue  (or use a generator, rather than a queue)
     164    ret_val = ProbeResults(len(ciphertext), values)
    40165    num_threads = min(len(values),max_threads)
    41166    threads = []
     
    56181            t.join()
    57182
    58         ret_val[j] = {}
     183        # XXX: add functions to ProbeResults class to add results here,
     184        #      rather than accessing members directly.
     185        ret_val._raw_table[j] = {}
    59186        while not results.empty():
    60             ret_val[j].update(results.get())
     187            ret_val._raw_table[j].update(results.get())
    61188
    62189    return ret_val
Note: See TracChangeset for help on using the changeset viewer.