Changeset 20


Ignore:
Timestamp:
12/06/12 18:35:28 (12 years ago)
Author:
tmorgan
Message:

added simple encode/decode command line tools

fixed problem with percent encoding by allowing for a third result of tests

implemented (untested) resumption of decryption for POA

more POA documentation and logging

Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • doc/TODO

    r19 r20  
    33
    44* PaddingOracle
    5   - change print statements to configurable debug statements
    6 
    7 * New tools for easy scripted encoding/decoding at command line
     5  - Enable resumption of decryption in case of failure
    86
    97
  • lib/bletchley/CBC/__init__.py

    r18 r20  
    3535      WTLS" by Serge Vaudenay (2002)
    3636
    37     POA objects are not thread-safe.  If multiple threads need to work
     37    POA objects are not caller thread-safe.  If multiple threads need to work
    3838    simultaneously on the same ciphertext and oracle, create a
    39     separate instance.
     39    separate instance. POA objects can execute tasks internally using
     40    multiple threads, however.
    4041
    4142    """
     
    6364         results in a correct padding upon decryption and False
    6465         otherwise.  This function should implement the prototype:
    65            def myOracle(ciphertext, iv)
     66           def myOracle(ciphertext, iv): ...
    6667         If the initialization vector (iv) is unknown is not included in
    6768         the ciphertext message, it can be ignored in the oracle
     
    210211       
    211212        if self._thread_result == None:
     213            self.log_message("Value of a byte could not be determined.  Current plaintext suffix: "+ repr(self.decrypted))
    212214            raise Exception
    213215
     
    230232    # XXX: Add logic to begin where decryption previously left off
    231233    def decrypt(self):
    232         """Decrypts a message using CBC mode. If the IV is not provided,
    233         it assumes a null IV.
     234        """Decrypts the previously supplied ciphertext. If the IV was
     235        not provided, it assumes a IV of zero bytes.
    234236
    235237        """
     
    237239        blocks = buffertools.splitBuffer(self._ciphertext, self.block_size)
    238240
    239         final = blocks[-1]
    240         iv = self._iv
    241         if iv == None:
    242             iv = '\x00'*self.block_size
    243         if len(blocks) == 1:
    244             # If only one block present, then try to use IV as prior
    245             prior = iv
    246         else:
    247             prior = blocks[-2]
    248 
    249         # Decrypt last block, starting with padding (quicker to decrypt)
    250         pad_bytes = self.probe_padding(prior, final)
    251         decrypted = self.decrypt_block(prior, final, pad_bytes)
    252 
    253         # Now decrypt all other blocks except first block
    254         for i in range(len(blocks)-2, 0, -1):
    255             decrypted = self.decrypt_block(blocks[i-1], blocks[i]) + decrypted
    256 
    257         # Finally decrypt first block
    258         decrypted = self.decrypt_block(iv, blocks[0]) + decrypted
    259        
     241        if len(self.decrypted) == 0:
     242           
     243            final = blocks[-1]
     244            iv = self._iv
     245            if iv == None:
     246                iv = '\x00'*self.block_size
     247            if len(blocks) == 1:
     248                # If only one block present, then try to use IV as prior
     249                prior = iv
     250            else:
     251                prior = blocks[-2]
     252
     253            # Decrypt last block, starting with padding (quicker to decrypt)
     254            pad_bytes = self.probe_padding(prior, final)
     255            decrypted = self.decrypt_block(prior, final, pad_bytes)
     256
     257            # Now decrypt all other blocks except first block
     258            for i in range(len(blocks)-2, 0, -1):
     259                decrypted = self.decrypt_block(blocks[i-1], blocks[i]) + decrypted
     260
     261            # Finally decrypt first block
     262            decrypted = self.decrypt_block(iv, blocks[0]) + decrypted
     263       
     264        # Start where we left off last
     265        # XXX: test this
     266        else:
     267            num_partial = len(self.decrypted) % self.block_size
     268            finished_blocks = len(self.decrypted) / self.block_size
     269            partial = self.decrypted[0:num_partial]
     270            decrypted = self.decrypted[num_partial:]
     271
     272            for i in range(-1-finished_blocks, 0, -1):
     273                decrypted = self.decrypt_block(blocks[i-1], blocks[i], partial)
     274                partial = ''
     275
     276            # Finally decrypt first block
     277            decrypted = self.decrypt_block(iv, blocks[0]) + decrypted
     278           
    260279        return buffertools.stripPKCS7Pad(decrypted)
    261280
    262281
    263282    def encrypt_block(self, plaintext, ciphertext):
     283        """Encrypts a block of plaintext.  This is accomplished by
     284        decrypting the supplied ciphertext and then computing the prior
     285        block needed to create the desired plaintext at the ciphertext's
     286        location.
     287
     288        Returns the calculated prior block and the provided ciphertext
     289        block as a tuple.
     290
     291        """
    264292        if len(plaintext) != self.block_size or len(plaintext) != len(ciphertext):
    265293            raise InvalidBlockError(self.block_size,len(plaintext))
     
    270298   
    271299   
    272     # XXX: Add option to encrypt only the last N blocks.  Supplying a shorter
    273     #      plaintext and subsequent concatenation can easily achieve this as well...
    274300    def encrypt(self,plaintext):
     301        """Encrypts a plaintext value through "CBC-R" style prior-block
     302        propagation.
     303       
     304        Returns a tuple of the IV and ciphertext. 
     305
     306        NOTE: If your target messages do not include an IV with the
     307        ciphertext, you can instead opt to encrypt a suffix of the
     308        message and include the IV as if it were a ciphertext block.
     309        This block will decrypt to an uncontrollable random value, but
     310        with careful placement, this might be ok.
     311
     312        """
     313
    275314        blocks = buffertools.splitBuffer(buffertools.pkcs7PadBuffer(plaintext, self.block_size),
    276315                                         self.block_size)
  • lib/bletchley/blobtools.py

    r1 r20  
    4141    def isExample(self, blob):
    4242        sblob = frozenset(blob)
    43         return ((self.charset == None or sblob.issubset(self.charset)) and self.extraTests(blob))
     43        if self.charset != None and not sblob.issubset(self.charset):
     44            return False
     45        return self.extraTests(blob)
    4446   
    4547    def extraTests(self, blob):
     48        """May return True, False, or None, for is an example, isn't an
     49        example, or unknown, respectively.
     50
     51        """
    4652        return True
    4753
     
    254260        chunks = blob.split('%')
    255261        if len(chunks) < 2:
    256             return False
     262            return None
    257263        for c in chunks[1:]:
    258264            if len(c) < 2:
     
    320326
    321327def possibleEncodings(blob):
    322     ret_val = set()
     328    likely = set()
     329    possible = set()
    323330    for name,encoding in encodings.items():
    324         if encoding.isExample(blob):
    325             ret_val.add(name)
    326     return ret_val
     331        result = encoding.isExample(blob)
     332        if result == True:
     333            likely.add(name)
     334        elif result == None:
     335            possible.add(name)
     336    return likely,possible
    327337
    328338
    329339def encodingIntersection(blobs):
    330340    ret_val = set(encodings.keys())
     341    p = set(encodings.keys())
    331342    for b in blobs:
    332         ret_val &= possibleEncodings(b)
    333 
    334     return ret_val
     343        likely,possible = possibleEncodings(b)
     344        ret_val &= likely | possible
     345        p &= possible
     346    return ret_val - p
    335347
    336348
     
    404416
    405417
     418#XXX: move this to buffertools
    406419def smartPermutateBlobs(blobs, block_size=8):
    407420    """
Note: See TracChangeset for help on using the changeset viewer.