Пример #1
0
def test_get_data_fragment_with_padding():
    udp_payload = get_random_bytes(DATA_FRAG_PAYLOAD_SIZE - 1)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    _, frag_byte, _, payload = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE, 1)

    assert b2i(frag_byte) & FragmentGenerator.LAST_FRAG_FLAG
    assert b2i(frag_byte) & FragmentGenerator.PADDING_FLAG
    assert b2i(frag_byte) == 0b1100_0000
    assert payload[0:DATA_FRAG_PAYLOAD_SIZE - 1] == udp_payload
    assert len(
        fragment) == DATA_FRAG_PAYLOAD_SIZE + FRAG_ID_SIZE + FRAG_FLAG_SIZE

    udp_payload = get_random_bytes(1)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    _, frag_byte, _, payload = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE, 2)

    assert b2i(frag_byte) & FragmentGenerator.LAST_FRAG_FLAG
    assert b2i(frag_byte) & FragmentGenerator.PADDING_FLAG
    assert b2i(frag_byte) == 0b1100_0000
    assert payload[0:1] == udp_payload
    assert len(
        fragment) == DATA_FRAG_PAYLOAD_SIZE + FRAG_ID_SIZE + FRAG_FLAG_SIZE
Пример #2
0
def c11_encrypt_ecb_or_cbc_oracle(plain_text):
    block_size = 16
    key = get_random_bytes(block_size)

    prefix = get_random_bytes(10)
    suffix = get_random_bytes(10)
    msg = pkcs7_pad(prefix + plain_text + suffix, block_size)

    if random.random() >= 0.5:
        print("S2C11 - doing CBC")
        iv = get_random_bytes(16)
        return aes128_cbc_encode(key, iv, msg)
    else:
        print("S2C11 - doing ECB")
        return aes128_ecb_encode(key, msg)
Пример #3
0
def c19():
    b64_cipher_texts = [
        b'SSBoYXZlIG1ldCB0aGVtIGF0IGNsb3NlIG9mIGRheQ==',
        b'Q29taW5nIHdpdGggdml2aWQgZmFjZXM=',
        b'RnJvbSBjb3VudGVyIG9yIGRlc2sgYW1vbmcgZ3JleQ==',
        b'RWlnaHRlZW50aC1jZW50dXJ5IGhvdXNlcy4=',
        b'SSBoYXZlIHBhc3NlZCB3aXRoIGEgbm9kIG9mIHRoZSBoZWFk',
        b'T3IgcG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==',
        b'T3IgaGF2ZSBsaW5nZXJlZCBhd2hpbGUgYW5kIHNhaWQ=',
        b'UG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==',
        b'QW5kIHRob3VnaHQgYmVmb3JlIEkgaGFkIGRvbmU=',
        b'T2YgYSBtb2NraW5nIHRhbGUgb3IgYSBnaWJl',
        b'VG8gcGxlYXNlIGEgY29tcGFuaW9u',
        b'QXJvdW5kIHRoZSBmaXJlIGF0IHRoZSBjbHViLA==',
        b'QmVpbmcgY2VydGFpbiB0aGF0IHRoZXkgYW5kIEk=',
        b'QnV0IGxpdmVkIHdoZXJlIG1vdGxleSBpcyB3b3JuOg==',
        b'QWxsIGNoYW5nZWQsIGNoYW5nZWQgdXR0ZXJseTo=',
        b'QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=',
        b'VGhhdCB3b21hbidzIGRheXMgd2VyZSBzcGVudA==',
        b'SW4gaWdub3JhbnQgZ29vZCB3aWxsLA==',
        b'SGVyIG5pZ2h0cyBpbiBhcmd1bWVudA==',
        b'VW50aWwgaGVyIHZvaWNlIGdyZXcgc2hyaWxsLg==',
        b'V2hhdCB2b2ljZSBtb3JlIHN3ZWV0IHRoYW4gaGVycw==',
        b'V2hlbiB5b3VuZyBhbmQgYmVhdXRpZnVsLA==',
        b'U2hlIHJvZGUgdG8gaGFycmllcnM/',
        b'VGhpcyBtYW4gaGFkIGtlcHQgYSBzY2hvb2w=',
        b'QW5kIHJvZGUgb3VyIHdpbmdlZCBob3JzZS4=',
        b'VGhpcyBvdGhlciBoaXMgaGVscGVyIGFuZCBmcmllbmQ=',
        b'V2FzIGNvbWluZyBpbnRvIGhpcyBmb3JjZTs=',
        b'SGUgbWlnaHQgaGF2ZSB3b24gZmFtZSBpbiB0aGUgZW5kLA==',
        b'U28gc2Vuc2l0aXZlIGhpcyBuYXR1cmUgc2VlbWVkLA==',
        b'U28gZGFyaW5nIGFuZCBzd2VldCBoaXMgdGhvdWdodC4=',
        b'VGhpcyBvdGhlciBtYW4gSSBoYWQgZHJlYW1lZA==',
        b'QSBkcnVua2VuLCB2YWluLWdsb3Jpb3VzIGxvdXQu',
        b'SGUgaGFkIGRvbmUgbW9zdCBiaXR0ZXIgd3Jvbmc=',
        b'VG8gc29tZSB3aG8gYXJlIG5lYXIgbXkgaGVhcnQs',
        b'WWV0IEkgbnVtYmVyIGhpbSBpbiB0aGUgc29uZzs=',
        b'SGUsIHRvbywgaGFzIHJlc2lnbmVkIGhpcyBwYXJ0',
        b'SW4gdGhlIGNhc3VhbCBjb21lZHk7',
        b'SGUsIHRvbywgaGFzIGJlZW4gY2hhbmdlZCBpbiBoaXMgdHVybiw=',
        b'VHJhbnNmb3JtZWQgdXR0ZXJseTo=',
        b'QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=',
    ]

    block_size = 16
    random_key = get_random_bytes(block_size)
    reused_nonce = 0

    def c19_cryptor(plain_text):
        return aes128_ctr_encode(random_key, reused_nonce, plain_text)

    cipher_texts = [b64decode(s) for s in b64_cipher_texts]
    repeat_length = min(map(len, cipher_texts))
    chunks = [ct[0:repeat_length] for ct in cipher_texts]
    chunks = transpose(chunks)
    keystream = bytes(map(lambda t: t[1], map(c4_best_single_byte_xor,
                                              chunks)))
    for ct in cipher_texts:
        ctt = ct[0:repeat_length]
        print(xor_buf(ctt, keystream))
Пример #4
0
def make_fragment(message_id, fragment_number, last_fragment, payload,
                  payload_limit):
    if fragment_number > 0b0011_1111:
        raise ValueError("Too many fragments needed for this payload.")

    if not payload and message_id != DUMMY_FRAG_ID:
        raise ValueError("No more fragments left to generate.")

    frag_byte = fragment_number

    if last_fragment:
        frag_byte |= FragmentGenerator.LAST_FRAG_FLAG

    if len(payload) < payload_limit:
        frag_byte |= FragmentGenerator.PADDING_FLAG

        padding_bytes, padding_len = padding_length_to_bytes(payload_limit -
                                                             len(payload))
    else:
        padding_len = 0
        padding_bytes = bytes()

    fragment = i2b(message_id, FRAG_ID_SIZE) + i2b(frag_byte, FRAG_FLAG_SIZE)

    fragment += padding_bytes

    fragment += payload[:payload_limit] + get_random_bytes(padding_len)

    return fragment
Пример #5
0
def test_get_data_fragment_2_fragments():
    udp_payload = get_random_bytes(400)
    fragmented_payload = bytes()

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    msg_id, is_last, fragment_id, payload = parse_fragment(fragment)

    fragmented_payload += payload

    assert msg_id == f.message_id
    assert not is_last
    assert fragment_id == 0

    fragment = f.get_data_fragment()

    msg_id, is_last, fragment_id, payload = parse_fragment(fragment)

    fragmented_payload += payload

    assert msg_id == f.message_id
    assert is_last
    assert fragment_id == 1
    assert udp_payload == fragmented_payload
Пример #6
0
def test_gen_init_msg():
    priv1 = params.group.gensecret()
    priv2 = params.group.gensecret()
    priv3 = params.group.gensecret()

    pub1 = params.group.expon_base([priv1])
    pub2 = params.group.expon_base([priv2])
    pub3 = params.group.expon_base([priv3])

    passes = 100

    for _ in range(passes):
        chan_keys = [gen_sym_key(), gen_sym_key(), gen_sym_key()]
        payload = get_random_bytes(100)

        proc_chan_keys = []

        message = gen_init_msg([pub1, pub2, pub3], chan_keys, payload)

        for priv_key in [priv1, priv2, priv3]:
            proc_chan_key, proc_payload, message = process(priv_key, message)

            proc_chan_keys.append(proc_chan_key)

        assert chan_keys == proc_chan_keys
        assert payload == proc_payload
Пример #7
0
def c13():
    block_size = 16
    secret_key = get_random_bytes(block_size)

    def encryptor(email_address):
        return aes128_ecb_encode(
            secret_key, pkcs7_pad(c13_profile_for(email_address), block_size))

    def decryptor(cipher_text):
        return c13_parse_kv(
            pkcs7_unpad(aes128_ecb_decode(secret_key, cipher_text),
                        block_size))

    # The minimum amount of prefix padding to cause a duplicated block
    # will give us the target block in the next block
    for repeat_pad_size in range(2 * block_size - 1, 3 * block_size):
        repeat_pad = b"A" * repeat_pad_size
        trick_email_address = repeat_pad + pkcs7_pad(
            b"admin", block_size) + b"@example.com"
        cipher_text = encryptor(trick_email_address)

        chunks = chunk(cipher_text, block_size)
        # If we have a repeat, the block after repeat is target
        next_is_target = False
        target_cipher_block = b''
        last_chunk = b''
        for c in chunks:
            if next_is_target:
                target_cipher_block = c
                break
            next_is_target = (c == last_chunk)
            last_chunk = c
        if target_cipher_block != b'':
            break

    if target_cipher_block == b'':
        raise RuntimeError("Didn't find target cipher block")

    # At some padding between 0..block_size the end block should
    # be 'user<pkcspadding>'. If so, replacing it with our
    # target cipher block should give us something which will decode
    # to our desired plaintext
    for padding_size in range(0, block_size):
        padded_email_address = (b"A" * padding_size) + b"@example.com"

        cipher_text = encryptor(padded_email_address)
        # Splice in target block
        cipher_text = bytearray(cipher_text)
        cipher_text[-block_size:] = target_cipher_block
        cipher_text = bytes(cipher_text)
        try:
            profile = decryptor(cipher_text)
            if profile[b"role"] == b"admin":
                print("S2C13 - did it! got an admin role")
                return
        except (KeyError, ValueError):
            pass

    print("S2C13 fail. Bad coder, no biscuit")
Пример #8
0
def c14():
    unknown_key = get_random_bytes(16)

    #    oracle = lambda pt: c14_encryption_oracle(unknown_key, pt)

    def oracle(pt):
        return c14_encryption_oracle(unknown_key, pt)

    block_size = 16

    pad_char = b'A'

    recovered_plain_text = bytearray()
    chosen_plain_text = bytearray()
    while True:

        # We construct a (block_size - 1) piece plain text. Which
        # ends in the our recovered plain text and is prepended with enough
        # pad_char to make the size
        chosen_plain_text[:] = recovered_plain_text
        if len(chosen_plain_text) > block_size - 1:
            chosen_plain_text = chosen_plain_text[-(block_size - 1):]

        added_pad = max(0, (block_size - 1) - len(chosen_plain_text))
        chosen_plain_text = bytearray(pad_char * added_pad) + chosen_plain_text
        assert len(
            chosen_plain_text
        ) == block_size - 1, "Using correct size chosen_plain_text block"

        # By prepending with enough pad_chars and appending with bytes 0->255,
        # and repeating until we get block_size different
        # answers, we find 'block_size' candidate cipher blocks for each possible end byte
        dictionary = c14_dictionary_for_block(oracle, block_size,
                                              chosen_plain_text)

        next_byte = None
        for num_attempts in range(0, 10 * block_size):
            pad = pad_char * added_pad
            cipher_text = oracle(pad)
            for c in chunk(cipher_text, block_size):
                try:
                    next_byte = dictionary[c]
                    break
                except KeyError:
                    pass

        if next_byte is None:
            raise RuntimeError("Failed to find next byte in {} iterations",
                               num_attempts)

        recovered_plain_text.append(next_byte)
        print("{}".format(recovered_plain_text.decode('ascii')))

    print("S2C14 msg is {}", recovered_plain_text)
Пример #9
0
def test_get_data_fragment_too_many():
    udp_payload = get_random_bytes(400)

    f = FragmentGenerator(udp_payload)

    try:
        for _ in range(1000):
            f.get_data_fragment()
        assert False
    except ValueError:
        assert True
Пример #10
0
def test_get_init_fragment():
    udp_payload = get_random_bytes(120)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_init_fragment()

    msg_id, is_last, fragment_id, payload = parse_fragment(fragment)

    assert msg_id == f.message_id
    assert is_last
    assert fragment_id == 0
    assert udp_payload == payload
Пример #11
0
def test_get_data_fragment():
    udp_payload = get_random_bytes(DATA_FRAG_PAYLOAD_SIZE)

    f = FragmentGenerator(udp_payload)

    fragment = f.get_data_fragment()

    _, frag_byte, payload = cut(fragment, FRAG_ID_SIZE, FRAG_FLAG_SIZE)

    assert b2i(frag_byte) & FragmentGenerator.LAST_FRAG_FLAG
    assert b2i(frag_byte) == 0b0100_0000
    assert payload[0:DATA_FRAG_PAYLOAD_SIZE] == udp_payload
    assert len(
        fragment) == DATA_FRAG_PAYLOAD_SIZE + FRAG_ID_SIZE + FRAG_FLAG_SIZE
Пример #12
0
    def recv_response(self, response):
        self.last_interaction = time()
        """Turns the response into a MixMessage and saves its fragments for
        later sending.
        """
        frag_gen = FragmentGenerator(response)

        while frag_gen:
            print(self, "Data", "<-", len(frag_gen.udp_payload))

            fragment = frag_gen.get_data_fragment()
            packet = fragment + get_random_bytes(MIX_COUNT * CTR_PREFIX_LEN)

            ChannelExit.to_mix.append(DATA_MSG_FLAG + i2b(self.in_chan_id, CHAN_ID_SIZE) + packet)
Пример #13
0
def c17():
    block_size = 16
    random_key = get_random_bytes(block_size)
    random_iv = get_random_bytes(block_size)

    cipher_text = c17_encryptor(block_size, random_key, random_iv)

    cipher_blocks = chunk(cipher_text, block_size)
    cipher_blocks.insert(0, random_iv)

    def c17_decryptor(cipher_text):
        return c17_decryptor_good_padding(block_size, random_key, random_iv,
                                          cipher_text)

    def break_one_block(i):
        return c17_break_block(cipher_blocks[i], cipher_blocks[i + 1],
                               c17_decryptor)

    plain_text = b''.join((map(break_one_block,
                               range(0,
                                     len(cipher_blocks) - 1))))
    plain_text = pkcs7_unpad(plain_text, block_size)
    print("S3C17: {}".format(plain_text))
Пример #14
0
def c16():
    block_size = 16
    random_key = get_random_bytes(block_size)
    random_iv = get_random_bytes(block_size)

    payload = bytearray(b";admin=true;")
    # Hide the special chars by flipping a bit in them
    payload[0] ^= 0x01
    payload[6] ^= 0x01
    payload[11] ^= 0x01

    # Assuming we don't know the prefix, we will try at each offset
    for offset in range(0, block_size):
        chosen_plain_text = b'A' * offset
        # Prepend a sacrificial block, in which we can flip bits
        chosen_plain_text += b'A' * block_size
        chosen_plain_text += payload

        cipher_text = bytearray(
            c16_encryptor(block_size, random_key, random_iv,
                          chosen_plain_text))
        # We don't know which block to flip. Let's try 'em all
        for block_index in range(0, (len(cipher_text) // block_size) - 1):
            # Flip the corresponding bits in the sacrificial block
            cipher_text[(block_index * block_size) + offset + 0] ^= 0x01
            cipher_text[(block_index * block_size) + offset + 6] ^= 0x01
            cipher_text[(block_index * block_size) + offset + 11] ^= 0x01
            try:
                if (c16_decryptor(block_size, random_key, random_iv,
                                  bytes(cipher_text))):
                    print("S2C16 got admin")
                    return
            except Exception:
                # pkcs 7 fail?
                pass

    print("S2C16 fail :-(")
Пример #15
0
def c12():

    unknown_key = get_random_bytes(16)

    def oracle(pt):
        return c12_encryption_oracle(unknown_key, pt)

    # Shim is number of bytes to fill a block
    (block_size, shim_size) = c12_discover_block_and_shim_sizes(oracle)
    print("S2C12 - found block size {}".format(block_size))

    is_ecb = c12_detect_ecb(oracle, block_size)
    print("S2C12 - is ECB?:  {}".format(is_ecb))

    known_bytes = bytearray()

    for index in range(0, 10 * block_size):
        #        block_index = index // block_size
        chunk_index = index % block_size

        #        print("block_index {} chunk_index {}".format(block_index, chunk_index))

        needed_pad_len = (block_size - 1) - chunk_index
        needed_pad = bytes(needed_pad_len)

        trick_block = bytearray(block_size) + known_bytes
        trick_block = trick_block[-(block_size - 1):]

        block_dictionary = c12_make_block_dictionary(oracle, block_size,
                                                     trick_block)
        cipher_text = oracle(needed_pad)

        cipher_chunks = chunk(cipher_text, block_size)
        interesting_chunk = cipher_chunks[index // block_size]
        #        print("C0: {}".format(interesting_chunk))
        try:
            plain_text_byte = block_dictionary[interesting_chunk]
        except KeyError:
            break

        known_bytes.append(plain_text_byte)


#        print("Got byte: {}".format(plain_text_byte))
#        print("Got known bytes: {}".format(known_bytes))

    plain_text = pkcs7_unpad(known_bytes, block_size)
    print("S2C12 - got msg: {}", plain_text.decode('ascii'))
Пример #16
0
    def encrypt(self, plain_text):
        self.counter.next()

        msg_type, chan_id, ctr_prefix, payload = cut(plain_text,
                                                     MSG_TYPE_FLAG_LEN,
                                                     CHAN_ID_SIZE,
                                                     CTR_PREFIX_LEN)

        reserved = get_random_bytes(RESERVED_LEN)

        # use all 0s as link key, since they can not be exchanged yet
        cipher = gcm_cipher(self.key, int(self.counter))

        # ctr encrypt the header with a random link counter prefix
        header, mac = cipher.encrypt_and_digest(chan_id + ctr_prefix +
                                                msg_type + reserved)

        return bytes(self.counter) + header + mac + payload
Пример #17
0
def c14_encryption_oracle(key, chosen_plain_text):
    block_size = 16

    secret_suffix = b64decode(
        """Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg
aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq
dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg
YnkK""")
    prefix_size = randrange(20, 40)
    random_prefix = get_random_bytes(prefix_size)
    msg = random_prefix + chosen_plain_text + secret_suffix
    #    chunk_index = 0
    #    chunks = chunk(msg, 16)
    #    for c in chunks:
    #        chunk_index+= 1
    #        print("JB - oracle pt {}/{}: [{}]".format(chunk_index, len(chunks), c))
    msg = pkcs7_pad(msg, block_size)

    return aes128_ecb_encode(key, msg)
Пример #18
0
    def forward_request(self, request):
        """Takes a mix fragment, already stripped of the channel id."""
        self.last_interaction = time()

        ctr, cipher_text = cut(request, CTR_PREFIX_LEN)
        ctr = b2i(ctr)

        self.request_replay_detector.check_replay_window(ctr)

        cipher = ctr_cipher(self.key, ctr)

        forward_msg = cipher.decrypt(cipher_text) + get_random_bytes(CTR_MODE_PADDING)

        print(self, "Data", "->", len(forward_msg) - CTR_PREFIX_LEN)

        ChannelMid.requests.append(DATA_MSG_FLAG + i2b(self.out_chan_id, CHAN_ID_SIZE) + forward_msg)

        timed_out = check_for_timed_out_channels(ChannelMid.table_in)

        for in_id in timed_out:
            out_id = ChannelMid.table_in[in_id].out_chan_id

            del ChannelMid.table_in[in_id]
            del ChannelMid.table_out[out_id]
Пример #19
0
 def send_chan_confirm(self):
     print(self, "Init", "<-", "len:", DATA_PACKET_SIZE)
     ChannelExit.to_mix.append(CHAN_CONFIRM_MSG_FLAG + i2b(self.in_chan_id, CHAN_ID_SIZE) + bytes(CTR_PREFIX_LEN) + get_random_bytes(DATA_PACKET_SIZE))
Пример #20
0
from Counter import Counter
from LinkEncryption import LinkEncryptor, LinkDecryptor
from ReplayDetection import ReplayDetectedError
from constants import DATA_MSG_FLAG, CHAN_ID_SIZE, REPLAY_WINDOW_SIZE, CHANNEL_CTR_START
from util import get_random_bytes, i2b, gen_sym_key

payload = get_random_bytes(200)
msg_type = DATA_MSG_FLAG
chan_id = 128
msg_ctr = bytes(Counter(CHANNEL_CTR_START))

link_key = gen_sym_key()


def test_link_encryption():
    encryptor = LinkEncryptor(link_key)
    decryptor = LinkDecryptor(link_key)

    encrypted = encryptor.encrypt(msg_type + i2b(chan_id, CHAN_ID_SIZE) +
                                  msg_ctr + payload)

    chan_id2, msg_ctr2, payload2, msg_type2 = decryptor.decrypt(encrypted)

    assert int(encryptor.counter) in decryptor.replay_detector
    assert chan_id == chan_id2
    assert msg_ctr == msg_ctr2
    assert payload == payload2
    assert msg_type == msg_type2


def test_replay_detection_already_seen():
Пример #21
0
def c24_cryptor(seed):
    known_plain_text = b'A' * 15
    random_prefix = get_random_bytes(randrange(10, 20))
    return mt_ctr(seed, random_prefix + known_plain_text)