Exemple #1
0
    def decrypt(self, ciphertext: bytes, unpad: bool=True) -> Bytes:
        """
        Decrypts `ciphertext`.
        
        Parameters:
            ciphertext (bytes): Bytes-like object to be decrypted.
            unpad       (bool): Unpads the plaintext with PKCS7.
        
        Returns:
            Bytes: Resulting plaintext.
        """
        plaintext = b''
        ciphertext = Bytes.wrap(ciphertext)

        if len(ciphertext) % self.cipher.block_size != 0:
            raise Exception("Ciphertext is not a multiple of the block size")

        last_block = self.iv
        for block in get_blocks(ciphertext, self.cipher.block_size):
            enc_block = last_block ^ Bytes.wrap(self.cipher.decrypt(block))
            plaintext += enc_block
            last_block = block

        if unpad:
            plaintext = self.padder.unpad(plaintext)

        return plaintext
Exemple #2
0
def oid_tuple_to_bytes(oid_tuple: tuple) -> bytes:
    """
    BER-encodes an OID tuple.

    Parameters:
        oid_tuple: OID tuple to encode.
    
    Returns:
        bytes: BER-encoded OID.
    """
    oid_bytes = bytes([oid_tuple[0] * 40 + oid_tuple[1]])

    for next_int in oid_tuple[2:]:
        if next_int < 256:
            oid_bytes += bytes([next_int])
        else:
            as_bin = bin(next_int)[2:]
            as_bin = as_bin.zfill(math.ceil(len(as_bin) / 7) * 7)

            bin_blocks = get_blocks(as_bin, 7)
            new_bin_blocks = ['1' + block for block in bin_blocks[:-1]]
            new_bin_blocks.append('0' + bin_blocks[-1])

            oid_bytes += bytes([int(block, 2) for block in new_bin_blocks])

    return oid_bytes
Exemple #3
0
    def encrypt(self, plaintext: bytes, pad: bool=True) -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            plaintext (bytes): Bytes-like object to be encrypted.
            pad        (bool): Pads the plaintext with PKCS7.
        
        Returns:
            Bytes: Resulting ciphertext.
        """
        plaintext = Bytes.wrap(plaintext)

        if pad:
            plaintext = self.padder.pad(plaintext)


        if len(plaintext) % self.cipher.block_size != 0:
            raise Exception("Plaintext is not a multiple of the block size")

        ciphertext = Bytes(b'')
        last_block = self.iv

        for block in get_blocks(plaintext, self.cipher.block_size):
            enc_block = self.cipher.encrypt(bytes(last_block ^ block))
            ciphertext += enc_block
            last_block = enc_block

        return ciphertext
Exemple #4
0
    def compression_func(self, block: bytes, state: bytes) -> Bytes:
        """
        SHA-2 compression function.

        Parameters:
            block (bytes): Block being digested.
            state (bytes): Current digest state.
        
        Returns:
            Bytes: Hash output.
        """
        bit_mask = 0xFFFFFFFF if self.state_size == 4 else 0xFFFFFFFFFFFFFFFF
        bit_size = self.state_size * 8

        state = [int.from_bytes(chunk, 'big') for chunk in state.chunk(self.state_size)]
        w = [int.from_bytes(b, 'big') for b in get_blocks(block, self.state_size)] + ([None] * (self.rounds - 16))

        for i in range(16, self.rounds):
            s0 = right_rotate(w[i-15], self.rot[0], bit_size) ^ right_rotate(w[i-15], self.rot[1], bit_size) ^ (w[i-15] >> self.rot[2])
            s1 = right_rotate(w[i-2], self.rot[3], bit_size) ^ right_rotate(w[i-2], self.rot[4], bit_size) ^ (w[i-2] >> self.rot[5])
            w[i] = (w[i-16] + s0 + w[i-7] + s1) & bit_mask


        a = state[0]
        b = state[1]
        c = state[2]
        d = state[3]
        e = state[4]
        f = state[5]
        g = state[6]
        h = state[7]

        for i in range(self.rounds):
            S1 = right_rotate(e,  self.rot[6], bit_size) ^ right_rotate(e, self.rot[7], bit_size) ^ right_rotate(e, self.rot[8], bit_size)
            ch = g ^ (e & (f ^ g))
            temp1 = (h + S1 + ch + self.k[i] + w[i])
            S0 = right_rotate(a, self.rot[9], bit_size) ^ right_rotate(a, self.rot[10], bit_size) ^ right_rotate(a, self.rot[11], bit_size)
            maj = (a & b) ^ (a & c) ^ (b & c)
            temp2 = (S0 + maj)

            h = g
            g = f
            f = e
            e = (d + temp1) & bit_mask
            d = c
            c = b
            b = a
            a = (temp1 + temp2) & bit_mask


        state[0] += a
        state[1] += b
        state[2] += c
        state[3] += d
        state[4] += e
        state[5] += f
        state[6] += g
        state[7] += h

        return Bytes(b''.join([int.to_bytes(h_i & bit_mask, self.state_size, 'big') for h_i in state]))
Exemple #5
0
def pem_encode(der_bytes: bytes, marker: str, width: int=70, encryption: str=None, passphrase: bytes=None, iv: bytes=None, use_rfc_4716: bool=False) -> bytes:
    """
    PEM-encodes DER-encoded bytes.

    Parameters:
        der_bytes   (bytes): DER-encoded bytes.
        marker        (str): Header and footer marker (e.g. 'RSA PRIVATE KEY').
        width         (int): Maximum line width before newline.
        encryption    (str): (Optional) RFC1423 encryption algorithm (e.g. 'DES-EDE3-CBC').
        passphrase  (bytes): (Optional) Passphrase to encrypt DER-bytes (if applicable).
        iv          (bytes): (Optional) IV to use for CBC encryption.
        use_rfc_4716 (bool): Use RFC4716 (SSH2) formatting rather than RFC1421 (PEM).

    Returns:
        bytes: PEM-encoded bytes.
    """
    additional_headers = ''
    if encryption:
        if not passphrase:
            raise ValueError('Encryption requested found but passphrase not specified.')

        cbc = create_pem_cbc_obj(passphrase, encryption, iv)
        der_bytes = cbc.encrypt(der_bytes)
        additional_headers = f'Proc-Type: 4,ENCRYPTED\nDEK-Info: {encryption},{cbc.iv.hex().upper().decode()}\n\n'

    data = b'\n'.join(get_blocks(base64.b64encode(der_bytes), block_size=width, allow_partials=True))

    if use_rfc_4716:
        begin_delim = '---- '
        end_delim = ' ----'
    else:
        begin_delim = '-----'
        end_delim = '-----'

    return f"{begin_delim}BEGIN {marker}{end_delim}\n{additional_headers}".encode('utf-8') + data + f"\n{begin_delim}END {marker}{end_delim}".encode('utf-8')
Exemple #6
0
    def execute(self) -> Bytes:
        """
        Executes the attack.

        Parameters:
            unpad (bool): Whether or not to PKCS7 unpad the result.
        
        Returns:
            Bytes: The recovered plaintext.
        """
        baseline = len(self.oracle.encrypt(b''))
        block_size = self.oracle.test_io_relation()['block_size']

        plaintexts = []
        for curr_block in RUNTIME.report_progress(range(baseline //
                                                        block_size),
                                                  unit='blocks'):
            log.debug("Starting iteration {}".format(curr_block))

            plaintext = b''
            for curr_byte in RUNTIME.report_progress(range(block_size),
                                                     unit='bytes'):
                if curr_block == 0:
                    payload = ('A' * (block_size - (curr_byte + 1))).encode()
                else:
                    payload = plaintexts[-1][curr_byte + 1:]

                one_byte_short = get_blocks(self.oracle.encrypt(payload),
                                            block_size=block_size)[curr_block]

                for i in range(256):
                    curr_byte = struct.pack('B', i)
                    ciphertext = self.oracle.encrypt(payload + plaintext +
                                                     curr_byte)

                    # We're always editing the first block to look like block 'curr_block'
                    if get_blocks(ciphertext,
                                  block_size=block_size)[0] == one_byte_short:
                        plaintext += curr_byte
                        break

            plaintexts.append(plaintext)
        return Bytes(b''.join(plaintexts))
Exemple #7
0
    def chunk(self, size: int, allow_partials: bool=False) -> list:
        """
        Chunks the Bytes into `size` length chunks.

        Parameters:
            size            (int): Size of the chunks.
            allow_partials (bool): Whether or not to allow the last chunk to be a partial.
        
        Returns:
            list: List of Bytes.
        """
        return get_blocks(self, size, allow_partials)
Exemple #8
0
    def full_round(self, block_num: int, state: list=None) -> Bytes:
        """
        Performs a full round of ChaCha.

        Parameters:
            block_num (int): Current block number.
        
        Returns:
            Bytes: Keystream block.
        """
        ctr_bytes = int.to_bytes(block_num, 4, 'little')

        x = state or [
            *[int.from_bytes(block, 'little') for block in get_blocks(self.constant, 4)],
            *[int.from_bytes(block, 'little') for block in get_blocks(self.key, 4)],
                int.from_bytes(ctr_bytes, 'little'),
            *[int.from_bytes(block, 'little') for block in get_blocks(self.nonce, 4)]
        ]


        tmp = deepcopy(x)

        for _ in range(self.rounds // 2):
            # Odd round
            x[0], x[4], x[ 8], x[12] = QUARTER_ROUND(x[0], x[4], x[ 8], x[12])
            x[1], x[5], x[ 9], x[13] = QUARTER_ROUND(x[1], x[5], x[ 9], x[13])
            x[2], x[6], x[10], x[14] = QUARTER_ROUND(x[2], x[6], x[10], x[14])
            x[3], x[7], x[11], x[15] = QUARTER_ROUND(x[3], x[7], x[11], x[15])

            # Even round
            x[0], x[5], x[10], x[15] = QUARTER_ROUND(x[0], x[5], x[10], x[15])
            x[1], x[6], x[11], x[12] = QUARTER_ROUND(x[1], x[6], x[11], x[12])
            x[2], x[7], x[ 8], x[13] = QUARTER_ROUND(x[2], x[7], x[ 8], x[13])
            x[3], x[4], x[ 9], x[14] = QUARTER_ROUND(x[3], x[4], x[ 9], x[14])

        for i in range(16):
            x[i] += tmp[i]

        return Bytes(b''.join([int.to_bytes(state_int & 0xFFFFFFFF, 4, 'little') for state_int in x]), byteorder='little')
Exemple #9
0
    def yield_state(self, message: bytes) -> Bytes:
        """
        Yields the intermediate, hashed states of the `message`.

        Parameters:
            message (bytes): Message to be hashed.
        
        Returns:
            Bytes: Intermediate, hashed states.
        """
        state = self.initial_state

        for block in get_blocks(self.pad_func(message), self.block_size):
            state = self.compression_func(block, state)
            yield state
Exemple #10
0
    def clamp_to_curve(self, x: int, swap_bit_order: bool = True) -> int:
        """
        Coerces `x` to a valid x-coordinate on the curve.

        Parameters:
            x               (int): `x` value to coerce.
            swap_bit_order (bool): Whether or not to swap the bit order before processing.

        Returns:
            int: Valid x-coordinate.
        """
        from samson.utilities.manipulation import get_blocks

        as_bits = bin(x)[2:].zfill(self.b)
        if swap_bit_order:
            as_bits = ''.join(
                [block[::-1] for block in get_blocks(as_bits, 8)])

        return 2**(self.n) | sum(2**i * int((as_bits)[i])
                                 for i in range(self.c, self.n))
Exemple #11
0
    def decrypt(self, ciphertext: bytes, unpad: bool=True) -> Bytes:
        """
        Decrypts `ciphertext`.
        
        Parameters:
            ciphertext (bytes): Bytes-like object to be decrypted.
            unpad       (bool): Unpads the plaintext with PKCS7.
        
        Returns:
            Bytes: Resulting plaintext.
        """
        ciphertext = Bytes.wrap(ciphertext)

        plaintext = Bytes(b'')
        for block in get_blocks(ciphertext, self.cipher.block_size):
            plaintext += self.cipher.decrypt(block)

        if unpad:
            plaintext = self.padder.unpad(plaintext)

        return plaintext
Exemple #12
0
    def encrypt(self, plaintext: bytes, pad: bool=True) -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            plaintext (bytes): Bytes-like object to be encrypted.
            pad        (bool): Pads the plaintext with PKCS7.
        
        Returns:
            Bytes: Resulting ciphertext.
        """
        plaintext = Bytes.wrap(plaintext)

        if pad:
            plaintext = self.padder.pad(plaintext)

        ciphertext = Bytes(b'')
        for block in get_blocks(plaintext, self.cipher.block_size):
            ciphertext += self.cipher.encrypt(block)

        return ciphertext
Exemple #13
0
    def decrypt(self, ciphertext: bytes) -> Bytes:
        """
        Decrypts `ciphertext`.

        Parameters:
            ciphertext (bytes): Bytes-like object to be decrypted.
        
        Returns:
            Bytes: Resulting plaintext.
        """
        plaintext = b''
        ciphertext = Bytes.wrap(ciphertext)

        last_block = self.iv

        for block in get_blocks(ciphertext,
                                self.cipher.block_size,
                                allow_partials=True):
            enc_block = self.cipher.encrypt(
                bytes(last_block))[:len(block)] ^ block
            plaintext += enc_block
            last_block = block

        return plaintext
Exemple #14
0
    def encrypt(self, plaintext: bytes) -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            plaintext (bytes): Bytes-like object to be encrypted.
        
        Returns:
            Bytes: Resulting ciphertext.
        """
        ciphertext = b''
        plaintext = Bytes.wrap(plaintext)

        last_block = self.iv

        for block in get_blocks(plaintext,
                                self.cipher.block_size,
                                allow_partials=True):
            enc_block = self.cipher.encrypt(
                bytes(last_block))[:len(block)] ^ block
            ciphertext += enc_block
            last_block = enc_block

        return ciphertext
Exemple #15
0
    diff_block_num = diff_location // 16
    diff_prefix_len = diff_location % 16

    # Find our injection point
    mask_location = input_mask.decode().format('<MASK>').index('<MASK>')
    exploit_block_num = mask_location // block_size + 1
    exploit_padding_len = block_size - diff_prefix_len

    # Pad injection to next block boundary
    exploit = b'a' * exploit_padding_len
    diff_block_num += 1

    # Build exploit block
    injection_location = block_size - mask_location

    exploit = exploit[:injection_location] + pkcs7.pad(
        injections[0]) + exploit[injection_location:]
    diff_block_num += 1

    # Send exploit block to server
    exploit_ciphertext = encryptor(exploit.decode())

    # Rearrange blocks to complete valid payload
    blocks = get_blocks(exploit_ciphertext, block_size)

    blocks[diff_block_num] = blocks[exploit_block_num]
    del blocks[exploit_block_num]

    crafted_payload = b''.join(blocks)
    print(login(crafted_payload))