Changeset 65
- Timestamp:
- 10/17/13 12:10:35 (11 years ago)
- Location:
- trunk/lib/bletchley
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/bletchley/blobtools.py
r53 r65 25 25 import operator 26 26 import functools 27 import itertools28 27 from . import buffertools 29 28 … … 479 478 """ 480 479 return "".join(map(lambda y:str((x>>y)&1), range(bits-1, -1, -1))) 481 482 483 #XXX: move this to buffertools484 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 for488 every blob, the resultant permutations will have489 this property as well.490 blobs should be an array containing blobs491 block_size should be an integer block_size or an492 array of block sizes.493 """494 495 if len(blobs) == 0:496 return497 498 if not isinstance(block_size, (int, long)):499 for size in block_size:500 for blob in smartPermutateBlobs(blobs, size):501 yield blob502 return503 504 # First we find the indexes of the chunks that are different505 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 different510 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 duplicates514 different_chunks = set(different_chunks)515 516 # We want to know which chunks are the same, too517 chunk_len = len(blobs[0]) / block_size518 same = set(range(0, chunk_len)) - different519 520 # Now let's mix and match the differnet blocks, for all possible lengths521 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 same524 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 continue529 yield mix -
trunk/lib/bletchley/buffertools.py
r49 r65 20 20 import sys 21 21 import zlib 22 import itertools 22 23 23 24 # Computes the block-wise differences between two strings … … 145 146 146 147 return decrypted[0:0-length] 148 149 150 def 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 23 23 import struct 24 24 import queue 25 import hashlib 26 27 # Wish Python had a better function for this that escaped more characters 28 _html_escape_table = { 29 "&": "&", 30 '"': """, 31 "'": "'", 32 ">": ">", 33 "<": "<", 34 "\n": "
", 35 "\r": "
", 36 } 37 38 def _html_escape(text): 39 return "".join(_html_escape_table.get(c,c) for c in text) 40 41 42 class 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> 50 function displayMessage(id) 51 { 52 alert(document.getElementById(id).value); 53 } 54 </script> 55 <style> 56 td 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> 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 25 113 26 114 def probe_bytes(checker, ciphertext, values, max_threads=1): … … 29 117 error message was generated. 30 118 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. 32 152 ''' 33 153 if max_threads < 1: … … 37 157 values = bytearray(values) 38 158 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) 40 165 num_threads = min(len(values),max_threads) 41 166 threads = [] … … 56 181 t.join() 57 182 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] = {} 59 186 while not results.empty(): 60 ret_val [j].update(results.get())187 ret_val._raw_table[j].update(results.get()) 61 188 62 189 return ret_val
Note: See TracChangeset
for help on using the changeset viewer.