def value(self): # This was found "by hand", using the idea explored in the previous # challenge: concatenate our target snippet with the original one, # and use the latter MAC code as the final MAC code of the whole # message. Thus, the crafted code snippet will look like: # # alert('Ayo, the Wu is back!'); var x = ('<GARBAGE>as that?'); # # where <GARBAGE> stands for the the concatenation of 16-byte PKCS7 # padding and the XOR between the first block of the original snippet # and the MAC code of the first part of that message. # This script was tested on Chrome and worked OK (luckily, no "'" # appeared inside <GARBAGE>). # 2 spaces complete the second block, and 6 of them are just used # to complete block 3 and leave room for the 'var x' declaration. spaces = ' '*8 var_x = 'var x = (\'' prefix = '%s%s%s' % (self.TARGET_SNIPPET, spaces, var_x) padded_prefix = PKCS7Padder(prefix).value(self.BLOCK_SIZE) snippet = BlockString(self.SNIPPET, self.BLOCK_SIZE) prefix_hash = self.hash_function.hash(prefix) garbage = ByteXOR(snippet.get_block(0), prefix_hash).value() # last block is just "as that?');" last_block = snippet.get_block(-1) crafted_snippet = '%s%s%s' % (padded_prefix, garbage, last_block) return self.hash_function.hash(crafted_snippet)
def value(self): # This was found "by hand", using the idea explored in the previous # challenge: concatenate our target snippet with the original one, # and use the latter MAC code as the final MAC code of the whole # message. Thus, the crafted code snippet will look like: # # alert('Ayo, the Wu is back!'); var x = ('<GARBAGE>as that?'); # # where <GARBAGE> stands for the the concatenation of 16-byte PKCS7 # padding and the XOR between the first block of the original snippet # and the MAC code of the first part of that message. # This script was tested on Chrome and worked OK (luckily, no "'" # appeared inside <GARBAGE>). # 2 spaces complete the second block, and 6 of them are just used # to complete block 3 and leave room for the 'var x' declaration. spaces = ' ' * 8 var_x = 'var x = (\'' prefix = '%s%s%s' % (self.TARGET_SNIPPET, spaces, var_x) padded_prefix = PKCS7Padder(prefix).value(self.BLOCK_SIZE) snippet = BlockString(self.SNIPPET, self.BLOCK_SIZE) prefix_hash = self.hash_function.hash(prefix) garbage = ByteXOR(snippet.get_block(0), prefix_hash).value() # last block is just "as that?');" last_block = snippet.get_block(-1) crafted_snippet = '%s%s%s' % (padded_prefix, garbage, last_block) return self.hash_function.hash(crafted_snippet)
def value(self, message, k): block_string = BlockString(message, self.resumable_hash.block_size()) # Compute the expandable message for this k. msg_generator = ExpandableMessageGenerator(self.hash_function, k) exp_message_state = msg_generator.state() # Build a mapping from intermediate states to block indices. state_map = self._build_state_map_for(block_string) # Find a linking block from the expandable message to the original # message. j, link = self._find_link(state_map, exp_message_state, k) # Now, generate a prefix having j blocks from the expandable message. prefix = msg_generator.value(j) # ...and remove first j+1 blocks from the original message. block_string.remove_blocks_until(j+1) return prefix + link + block_string.bytes()
def value(self, message, k): block_string = BlockString(message, self.resumable_hash.block_size()) # Compute the expandable message for this k. msg_generator = ExpandableMessageGenerator(self.hash_function, k) exp_message_state = msg_generator.state() # Build a mapping from intermediate states to block indices. state_map = self._build_state_map_for(block_string) # Find a linking block from the expandable message to the original # message. j, link = self._find_link(state_map, exp_message_state, k) # Now, generate a prefix having j blocks from the expandable message. prefix = msg_generator.value(j) # ...and remove first j+1 blocks from the original message. block_string.remove_blocks_until(j + 1) return prefix + link + block_string.bytes()
def edit(self, ciphertext, offset, plaintext): if type(ciphertext) is BlockString: ciphertext = ciphertext.bytes() length = len(plaintext) key_bytes = self.keystream[offset:offset+length] new_bytes = ByteXOR(plaintext, key_bytes).value() new_ciphertext = ciphertext[:offset] + new_bytes +\ ciphertext[offset+length:] return BlockString(new_ciphertext)
def _iterate_compress_function(self, message, initial_state=None, block_callback=None): if not isinstance(message, BlockString): message = BlockString(message, self.block_size) if initial_state is None: initial_state = self.hash_function.initial_state() hash_function = self._init_hash_function(initial_state) for index, block in enumerate(message): new_state = hash_function._process_chunk(block) hash_function._update_registers_from(new_state) if block_callback is not None: block_callback(index, block, hash_function) return tuple(hash_function.state())
def forge_from(self, message, mac): fake_message, fake_mac = self._build_fake_message_and_mac() fake_message = BlockString(fake_message, self.block_size) # Our new first block should be XORed with the original MAC. This, when # CBC-encrypted, will be like XORing the actual first block with a zero # IV. first_block = ByteXOR(fake_message.get_block(0), mac).value() # Remove first block; leave the rest untouched. fake_message.remove_block(0) # PKCS7-pad original message (since CBC encryption does so). padded_message = PKCS7Padder(message).value(self.block_size) crafted_message = padded_message + first_block + fake_message.bytes() return crafted_message, fake_mac
def decrypt_with_cipher(self, ciphertext, cipher): if type(ciphertext) != BlockString: ciphertext = BlockString(ciphertext, self.block_size) return self._iterate_blocks_with(ciphertext, cipher, self._block_decryption_callback)
def encrypt_with_cipher(self, plaintext, cipher): if type(plaintext) != BlockString: plaintext = BlockString(plaintext, self.block_size) plaintext = self._pad(plaintext) return self._iterate_blocks_with(plaintext, cipher, self._block_encryption_callback)
def _iterate_blocks_with(self, block_string, cipher, callback): self.cipher = cipher self.block_string = block_string result = BlockString(block_size=self.block_size) return reduce(lambda _result, block: _result + callback(*block), enumerate(self.block_string), result)