def _bitflip(ctxt: bytes, input_str: str) -> bytes: inject = b'dataz;admin=true' targetblock = ctxt[AES.block_size:(2 * AES.block_size)] badblock = xor(inject, xor(input_str.encode(), targetblock)) start = ctxt[:AES.block_size] end = ctxt[2 * AES.block_size:] return start + badblock + end
def _bitflip(ctxt, input_str): inject = 'dataz;admin=true' targetblock = ctxt[AES.block_size:(2 * AES.block_size)] badblock = xor(inject, xor(input_str, targetblock)) start = ctxt[:AES.block_size] end = ctxt[2 * AES.block_size:] return start + badblock + end
def _bitflip(ctxt, user_data): inject = b'dataz;admin=true' targetblock = ctxt[(2 * AES.block_size):(3 * AES.block_size)] keybytes = xor(user_data, targetblock) badblock = xor(inject, keybytes) start = ctxt[:(2 * AES.block_size)] end = ctxt[(3 * AES.block_size):] return start + badblock + end
def p25() -> bytes: with open('Data/25.txt', 'rb') as f: data = b64decode(f.read().replace(b'\n', b'')) key = b'YELLOW SUBMARINE' ptxt = aes_ecb_decrypt(data, key) key = urandom(16) ctxt = aes_ctr(ptxt, key) newtext = b'A' * len(ctxt) edited = _edit_ctxt(ctxt, key, 0, newtext) return xor(xor(edited, ctxt), newtext)
def _break_cbc(ctxt, key, iv): ptxt = '' prevblock = iv for block in range(len(ctxt) / AES.block_size): ctxtblock = ctxt[block * AES.block_size:(block + 1) * AES.block_size] cipherout = '' for cur_pad_byte in range(1, AES.block_size + 1): mask = ''.join([chr(cur_pad_byte ^ ord(s)) for s in cipherout]) for byt in range(0xff + 1): validpad = True block = 'A' * (AES.block_size - len(mask) - 1) + chr(byt) + mask out = aes_cbc_decrypt(ctxtblock, key, block) # server would be doing this try: validate_pkcs7(out) except ValueError: validpad = False # back to client now if validpad: cipherout = chr(byt ^ cur_pad_byte) + cipherout break ptxt += xor(prevblock, cipherout) prevblock = ctxtblock return ptxt
def p49() -> str: our_id = 1 target_id = 2 valid_msg = f'from=#{our_id}&to=#{target_id}&amount=#{1000000}'.encode() good_iv = b'\x00' * AES.block_size client_mac = cbcmac(valid_msg, good_iv) bad_msg = f'from=#{target_id}&to=#{our_id}&amount=#{1000000}'.encode() bad_iv = xor(bad_msg[:AES.block_size], xor(valid_msg[:AES.block_size], good_iv)) assert validate_message(bad_msg, bad_iv, client_mac) valid_msg = f'from=#{target_id}&tx_list=#3:5000;4:7000'.encode() valid_mac = cbcmac(valid_msg) bad_msg = f';{our_id}:1000000'.encode() forged_mac = forge_mac(valid_mac, bad_msg) forged_msg = pkcs7(valid_msg) + pkcs7(bad_msg) assert compare_digest(forged_mac, cbcmac(forged_msg)) return f'Successfully stole 1M spacebucks! Message "{forged_msg.decode()}"' \ f'signed with MAC {hexlify(forged_mac).decode()}'
def aes_ctr(intxt: bytes, key: bytes, nonce: int = 0) -> bytes: outtxt = b'' count = 0 cipher = AES.new(key, AES.MODE_ECB) while intxt: val = _format_64bit(nonce) + _format_64bit(count) stream = cipher.encrypt(val) outtxt += xor(intxt[:AES.block_size], stream) intxt = intxt[AES.block_size:] count += 1 return outtxt
def p49(): our_id = 1 target_id = 2 valid_msg = 'from=#{}&to=#{}&amount=#{}'.format(our_id, target_id, 1000000) good_iv = '\x00' * AES.block_size client_mac = cbcmac(valid_msg, good_iv) bad_msg = 'from=#{}&to=#{}&amount=#{}'.format(target_id, our_id, 1000000) bad_iv = xor(bad_msg[:AES.block_size], xor(valid_msg[:AES.block_size], good_iv)) assert validate_message(bad_msg, bad_iv, client_mac) valid_msg = 'from=#{}&tx_list=#{}'.format(target_id, '3:5000;4:7000') valid_mac = cbcmac(valid_msg) bad_msg = ';{}:1000000'.format(our_id) forged_mac = forge_mac(valid_mac, bad_msg) forged_msg = pkcs7(valid_msg) + pkcs7(bad_msg) assert compare_digest(forged_mac, cbcmac(forged_msg)) return 'Successfully stole 1M spacebucks! Message "{}" signed with MAC {}'.format( forged_msg, hexlify(forged_mac))
def aes_cbc_decrypt(ctxt, key, iv): ptxt = '' cipher = AES.new(key, AES.MODE_ECB) prev_block = iv for block in range(len(ctxt) / AES.block_size): start = block * AES.block_size end = start + AES.block_size cur_block = ctxt[start:end] tmp = cipher.decrypt(cur_block) ptxt += xor(prev_block, tmp) prev_block = cur_block return ptxt
def aes_cbc_encrypt(ptxt, key, iv): ctxt = '' cipher = AES.new(key, AES.MODE_ECB) prev_block = iv padded = pkcs7(ptxt) for block in range(len(padded) / AES.block_size): start = block * AES.block_size end = start + AES.block_size cur_block = padded[start:end] tmp = xor(prev_block, cur_block) ctxtblock = cipher.encrypt(tmp) ctxt += ctxtblock prev_block = ctxtblock return ctxt
def p27() -> bytes: key = urandom(16) print(f'The key is {hexlify(key).decode()}') msg = b'Super secret message unfortunately encrypted in a bad manner' ctxt = aes_cbc_encrypt(msg, key, key) c1 = ctxt[:AES.block_size] zeros = b'\x00' * AES.block_size ctxt = c1 + zeros + c1 + ctxt[3 * AES.block_size:] try: plaintext = aes_cbc_decrypt(ctxt, key, key) return _check_ascii_compliant(plaintext) except ValueError as e: ptxt = e.args[0] p1, p3 = ptxt[:AES.block_size], ptxt[2 * AES.block_size:3 * AES.block_size] return b'Recovered ' + hexlify(xor(p1, p3))
def p50(): key = 'YELLOW SUBMARINE' str1 = 'alert(\'MZA who was that?\');\n' target_hash = cbcmac(str1, key=key) str2 = 'alert(\'Ayo, the Wu is back!\');//' intermediate_hash = cbcmac(str2, key=key) block0 = '\x10' * AES.block_size block1 = xor(intermediate_hash, str1[:AES.block_size]) block2 = str1[AES.block_size:] valid_snippet = str2 + block0 + block1 + block2 collision_hash = cbcmac(valid_snippet, key=key) assert collision_hash == target_hash return 'Created snippet {} with hash {}. Target snippet was {} with hash {}'.format( repr(valid_snippet), hexlify(collision_hash), repr(str1), hexlify(target_hash))
def p50() -> str: key = b'YELLOW SUBMARINE' msg1 = b'alert(\'MZA who was that?\');\n' target_hash = cbcmac(msg1, key=key) msg2 = b'alert(\'Ayo, the Wu is back!\');//' intermediate_hash = cbcmac(msg2, key=key) block0 = b'\x10' * AES.block_size block1 = xor(intermediate_hash, msg1[:AES.block_size]) block2 = msg1[AES.block_size:] valid_snippet = msg2 + block0 + block1 + block2 collision_hash = cbcmac(valid_snippet, key=key) assert collision_hash == target_hash return f'Created snippet {valid_snippet} ' \ f'with hash {hexlify(collision_hash).decode()}.\n' \ f'Target snippet was {msg1} ' \ f'with hash {hexlify(target_hash).decode()}'
def p27(): key = urandom(16) print 'The key is {}'.format(hexlify(key)) msg = 'Super secret message unfortunately encrypted in a bad manner' ctxt = aes_cbc_encrypt(msg, key, key) c1 = ctxt[:AES.block_size] zeros = '\x00' * AES.block_size ctxt = c1 + zeros + c1 + ctxt[3 * AES.block_size:] try: plaintext = aes_cbc_decrypt(ctxt, key, key) return _check_ascii_compliant(plaintext) except ValueError as e: start = len('Invalid ASCII - ') ptxt = str(e)[start:] p1, p3 = ptxt[:AES.block_size], ptxt[2 * AES.block_size:3 * AES.block_size] return 'Recovered ' + hexlify(xor(p1, p3))
def _break_cbc(ctxt: bytes, key: bytes, iv: bytes) -> bytes: ptxt = b'' prevblock = iv for block in range(len(ctxt) // AES.block_size): ctxtblock = ctxt[block * AES.block_size:(block + 1) * AES.block_size] cipherout = b'' for cur_pad_byte in range(1, AES.block_size + 1): mask = bytes([(cur_pad_byte ^ s) for s in cipherout]) for byte in range(0xff + 1): validpad = True byte_str = int.to_bytes(byte, 1, byteorder='little') block = b'A' * (AES.block_size - len(mask) - 1) + byte_str + mask out = aes_cbc_decrypt(ctxtblock, key, block) # server would be doing this try: validate_pkcs7(out) except ValueError: validpad = False # back to client now if validpad: cipher_byte = int.to_bytes(byte ^ cur_pad_byte, 1, byteorder='little') cipherout = cipher_byte + cipherout break ptxt += xor(prevblock, cipherout) prevblock = ctxtblock return ptxt
def forge_mac(valid_mac, our_msg): message_block = xor(valid_mac, pkcs7(our_msg)) return cbcmac(message_block)
def forge_mac(valid_mac: bytes, our_msg: bytes) -> bytes: message_block = xor(valid_mac, pkcs7(our_msg)) return cbcmac(message_block)