예제 #1
0
def attack(ciphertext):
    guessed_clear = b''

    split_string = lambda x, n: [x[i:i + n] for i in range(0, len(x), n)]
    blocks = split_string(ciphertext, BLOCK_SIZE)

    for block_n in range(
            len(blocks) - 1, 0,
            -1):  #build pair of blocks starting from end of message
        spliced_ciphertext = blocks[block_n - 1] + blocks[block_n]

        decoded_bytes = b'?' * BLOCK_SIZE  #output of block cipher decoding values

        ##GET VALUE OF SECRET BYTE byte
        for byte in range(BLOCK_SIZE - 1, -1, -1):
            new_pad_len = BLOCK_SIZE - byte

            #Build hacked ciphertext tail with values to obtain desired padding
            hacked_ciphertext_tail = b''
            for padder_index in range(1, new_pad_len):
                hacked_ciphertext_tail += bytearray.fromhex(
                    '{:02x}'.format(new_pad_len
                                    ^ decoded_bytes[byte + padder_index]))

            for i in range(0, 256):
                attack_str = bytearray.fromhex('{:02x}'.format(
                    (i ^ spliced_ciphertext[byte])))
                hacked_ciphertext = spliced_ciphertext[:
                                                       byte] + attack_str + hacked_ciphertext_tail + spliced_ciphertext[
                                                           byte + 1 +
                                                           new_pad_len - 1:]

                if (is_padding_ok(hacked_ciphertext)):

                    test_correctness = hacked_ciphertext[:byte -
                                                         1] + bytearray.fromhex(
                                                             '{:02x}'.format((
                                                                 1 ^
                                                                 hacked_ciphertext[
                                                                     byte]))
                                                         ) + hacked_ciphertext[
                                                             byte:]
                    if (not is_padding_ok(test_correctness)):
                        continue

                    decoded_bytes = decoded_bytes[:byte] + bytearray.fromhex(
                        '{:02x}'.format(hacked_ciphertext[byte]
                                        ^ new_pad_len)) + decoded_bytes[byte +
                                                                        1:]
                    guessed_clear = bytearray.fromhex(
                        '{:02x}'.format(i ^ new_pad_len)) + guessed_clear
                    break

    return guessed_clear[:-guessed_clear[-1]]  #remove padding!
예제 #2
0
def attack_message(msg):

    cipherfake=[0] * 16
    plaintext = [0] * 16
    current = 0
    message=""


    #I devide the list of bytes in blocks, and I put them in another list
    number_of_blocks = int(len(msg)/BLOCK_SIZE)
    blocks = [[]] * number_of_blocks
    for i in (range(number_of_blocks)):
        blocks[i] = msg[i * BLOCK_SIZE: (i + 1) * BLOCK_SIZE]

    for z in range(len(blocks)-1):  #for each message, I calculate the number of block
        for itera in range (1,17): #the length of each block is 16. I start by one because than I use its in a counter
            for v in range(256):
                cipherfake[-itera]=v
                if is_padding_ok(bytes(cipherfake)+blocks[z+1]): #the idea is that I put in 'is_padding_ok' the cipherfake(array of all 0) plus the last block
                                                                 #if the function return true I found the value
                    current=itera
                    plaintext[-itera]= v^itera^blocks[z][-itera]

            for w in range(1,current+1):
                cipherfake[-w] = plaintext[-w]^itera+1^blocks[z][-w] #for decode the second byte I must set the previous bytes with 'itera+1'


        for i in range(16):
            if plaintext[i] >= 32:
                char = chr(int(plaintext[i]))
                message += char

    #print("Crack: " + message + "\n")
    return str.encode(message)
예제 #3
0
def attack(ciphertext):
    blocks = [ciphertext[i:i + BLOCK_SIZE] for i in range(0, len(ciphertext), BLOCK_SIZE)]
    current_block = len(blocks)-1
    plaintext = ""

    # Cycle over blocks starting from last one and last one -1.
    while current_block > 0:
        pad_len = get_padding(blocks, current_block)
        idx_paderror = BLOCK_SIZE - pad_len
        iv_copy = bytearray(blocks[current_block-1])  # Need another copy of the IV to send it to the oracle for decrypt so that I do not modify blocks
        
        while idx_paderror > 0:
            idx_reverse = BLOCK_SIZE - 1

            while idx_reverse >= idx_paderror:  # Here I modify the bytes of padding increasing them with XOR
                iv_copy[idx_reverse] = iv_copy[idx_reverse] ^ pad_len ^ (pad_len + 1)
                idx_reverse -= 1
    
            for guessedValue in range(0, 256):  # Here I find the guessed value and decrypt the current index
                iv_copy[idx_reverse] = guessedValue
                if is_padding_ok(bytes(iv_copy) + blocks[current_block]):
                    plaintext += chr((pad_len + 1) ^ guessedValue ^ blocks[current_block - 1][idx_reverse])
                    break
                
            pad_len += 1
            idx_paderror -= 1
        # }END WHILE that Cycle over bytes.
        current_block -= 1
    # }END WHILE that Cycle over blocks.
    return str.encode(plaintext[::-1])
예제 #4
0
def get_pad_len(encrypted_msg):
    array = bytearray(encrypted_msg)
    pad_len = 16
    while True:
        array[-(pad_len + BLOCK_SIZE)] ^= 1
        if not is_padding_ok(bytes(array)):
            return pad_len
        pad_len -= 1
예제 #5
0
def decrypt_block(array, pad_len):
    cleartext = bytearray()
    for current_pl in range(pad_len, BLOCK_SIZE):
        new_pl = current_pl + 1
        for i in range(1, new_pl):
            value = current_pl ^ new_pl
            array[-(i + BLOCK_SIZE)] = array[-(i + BLOCK_SIZE)] ^ value
        c = array[-(new_pl + BLOCK_SIZE)]
        for byte in range(0, 256):
            array[-(new_pl + BLOCK_SIZE)] = byte
            if is_padding_ok(bytes(array)):
                cleartext.append(c ^ new_pl ^ byte)
                break
    return cleartext[::-1]
예제 #6
0
def get_padding(blocks, current_block):
    idx_paderror = 0
    if current_block < len(blocks) - 1:  # If I am not visiting the last block, I have no padding.
        idx_paderror = BLOCK_SIZE
    else:  # Else I find the Pad Length.
        iv_fake = bytearray(blocks[current_block - 1])
        for byte in iv_fake:
            # Check if it is == 255 because if I do byte+1 I could get a value out of range
            iv_fake[idx_paderror] = byte - 1 if iv_fake[idx_paderror] == 255 else byte + 1

            if not is_padding_ok(bytes(iv_fake) + blocks[current_block]):
                break
            idx_paderror += 1
    return BLOCK_SIZE - idx_paderror