Beispiel #1
0
def crackMTSeedKnownPlain(bstr_cipher: bytes, bstr_known_plain: bytes,
                          offset: int, bits: int, seed_bits: int) -> int:
    """
    From a known plaintext recover the seed
    TODO: for bits to be other sizes too some lines need to be changed
    :param bstr_cipher:
    :param bstr_known_plain:
    :param offset: the known plain text starts at this position in the cipher text
    (ch. 24 prepends random known text)
    :param bits: number of bits to get from MT
    :param seed_bits: number of bits of the seed
    :return: recovered seed
    """

    known_plain_cipher = bstr_cipher[offset:offset + len(bstr_known_plain)]
    for seed in range(2**seed_bits):
        random.seed(seed)
        # construct key
        keystream = b''
        # fast forward to the proper point in the MT sequence
        for _ in range(offset):
            random.getrandbits(bits)
        for i in range(len(bstr_known_plain)):
            keystream += bytes([random.getrandbits(bits)])
        plain = xorBytestrings(known_plain_cipher, keystream)
        if plain == bstr_known_plain:
            return seed
    return None
Beispiel #2
0
def aesCTREditRecoverPlain(ctr_edit_fn: types.FunctionType,
                           *edit_fn_args) -> bytes:
    """
    Recovers the the plain text to a ctr encoded stream by calling the
    CTR edit function on it with and editing the whole plain text.
    The key is then "removed" by xoring the original and the edited
    cipher text leaving the xored original plain text and the newplain
    text
    :param ctr_edit_fn: CTR edit function name
    :param edit_fn_args: the arguments to the function. assumes the cipher
    bytearray is the first
    :return:
    """
    original_cipher = edit_fn_args[0][:]
    newplain = b'X' * len(original_cipher)
    ctr_edit_fn(*edit_fn_args[:-1], newplain)
    plain_xor = xorBytestrings(original_cipher, edit_fn_args[0])
    return xorBytestrings(plain_xor, newplain)
Beispiel #3
0
def aesCTR(bstr, bstr_key, num_bits, bstr_nonce):
    """ encryption and decryption is the same in this mode
    """
    state_iter = stateGenerator(bstr, 16, modis0=False)
    xored = b''
    counter = 0
    for state in state_iter:
        bstr_nonce_ctr = bstr_nonce + struct.pack('<q', counter)
        secondary_key = aesEncrypt(bstr_nonce_ctr, bstr_key, num_bits)
        # this will be shorter than state len if the last state is remainder:
        secondary_key = secondary_key[:len(state)]
        xored += xorBytestrings(state, secondary_key)
        counter += 1

    return xored
Beispiel #4
0
def mtStreamCipher(bstr_msg: bytes, seed: int) -> bytes:
    """
    set 3 / ch. 24, en/decrypt with keystream generated from
    MT random 8 bit numbers
    :param bstr_msg:
    :param seed: seed that will be converted to 16 bit (xored with 0xFFFF)
    :return:
    """
    # 16 bit seed
    random.seed(seed & 0xFFFF)
    keystream = b''
    for i in range(len(bstr_msg)):
        rnum = random.getrandbits(8)
        keystream += bytes([rnum])
    return xorBytestrings(bstr_msg, keystream)
Beispiel #5
0
def aesEncrypt(bstr_msg, bstr_key, num_bits, mode='ecb', bstr_IV=None):
    if len(bstr_key) != 16:
        # no key derivation yet
        print("Unsuitable key length!")
        exit(1)

    # without padding for now
    #bstr_msg = misc.padPKCS7(bstr_msg, 16)
    state_iter = stateGenerator(bstr_msg, 16)
    rounds = {128: 10, 192: 12, 256: 14}
    round_keys = aesKeyExpansion(bstr_key)
    cipher = b''

    preceding_cipher_block = bstr_IV

    for state in state_iter:
        if mode == 'cbc':
            state = xorBytestrings(state, preceding_cipher_block)

        # initial (not actual) round
        state_trans = bytes(makeNDArrayFrom(state, 4, 4).transpose().flatten())
        key_trans = bytes(
            makeNDArrayFrom(bstr_key, 4, 4).transpose().flatten())

        bstr_state = aesAddRoundkey(state_trans, key_trans)

        for r in range(0, rounds[num_bits]):
            if r == rounds[num_bits] - 1:
                # last round no Mix Columns
                bstr_state = aesSubBytes(bstr_state)
                bstr_state = aesShiftRows(bstr_state)
                key_trans = bytes(
                    makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten())
                bstr_state = aesAddRoundkey(bstr_state, key_trans)
            else:
                bstr_state = aesSubBytes(bstr_state)
                bstr_state = aesShiftRows(bstr_state)
                bstr_state = aesMixColumns(bstr_state)
                key_trans = bytes(
                    makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten())
                bstr_state = aesAddRoundkey(bstr_state, key_trans)
        state_result = bytes(
            makeNDArrayFrom(bstr_state, 4, 4).transpose().flatten())
        preceding_cipher_block = state_result

        cipher += state_result
    return cipher
Beispiel #6
0
def hammingDistance(bstr1: bytes, bstr2: bytes) -> int:
    """
    Compute Hamming Distance between two strings

    :param bstr1: byte string 1
    :param bstr2: byte string 2
    :return: int
    """
    if len(bstr1) != len(bstr2):
        print("xor not equal len!")
        exit(1)
    diff = b''
    b1 = bstr1
    b2 = bstr2
    diff = xorBytestrings(b1, b2)
    distance = 0
    for b in diff:
        distance += bin(b).count("1")
    return (distance)
Beispiel #7
0
def aesDecrypt(bstr_cipher, bstr_key, num_bits, mode='ecb', bstr_IV=None):
    if len(bstr_key) != 16:
        # no key derivation yet
        print("Unsuitable key length!")
        exit(1)

    state_iter = stateGenerator(bstr_cipher, 16)
    rounds = {128: 10, 192: 12, 256: 14}
    round_keys = aesKeyExpansion(bstr_key)
    cipher = b''
    prev_cipherstate = bstr_IV
    for state in state_iter:
        # initial round
        bstr_state = bytes(makeNDArrayFrom(state, 4, 4).transpose().flatten())
        key_trans = bytes(
            makeNDArrayFrom(bstr_key, 4, 4).transpose().flatten())
        for r in reversed(range(0, rounds[num_bits])):
            if r == rounds[num_bits] - 1:
                # first round no inverse MixColumns
                key_trans = bytes(
                    makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten())
                bstr_state = aesAddRoundkey(bstr_state, key_trans)
                bstr_state = aesInvShiftRows(bstr_state)
                bstr_state = aesInvSubBytes(bstr_state)
            else:
                key_trans = bytes(
                    makeNDArrayFrom(round_keys[r], 4, 4).transpose().flatten())
                bstr_state = aesAddRoundkey(bstr_state, key_trans)
                bstr_state = aesInvMixColumns(bstr_state)
                bstr_state = aesInvShiftRows(bstr_state)
                bstr_state = aesInvSubBytes(bstr_state)
        key_trans = bytes(
            makeNDArrayFrom(bstr_key, 4, 4).transpose().flatten())
        bstr_state = aesAddRoundkey(bstr_state, key_trans)
        bstr_state = bytes(
            makeNDArrayFrom(bstr_state, 4, 4).transpose().flatten())
        if mode == 'cbc':
            bstr_state = xorBytestrings(bstr_state, prev_cipherstate)
            prev_cipherstate = state
        cipher += bstr_state
        #cipher = misc.unpadPKCS7(cipher, 16)
    return cipher
Beispiel #8
0
def aesCTREdit(barray_cipher: bytes, bstr_key: bytes, bstr_nonce: bytes,
               bits: int, offset: int, bstr_newtext: bytes):
    """
    set 4 / ch. 25
    Edit AES CTR text encrypted in place at offset. Therefor generate the key bytes from that
    offset on, ecrypt the newtext and replace.
    :param barray_cipher: AES CTR encrypted plain text, bytearray that will be changed
    :param bstr_key: key
    :param bstr_nonce:
    :param bits:
    :param offset: offset
    :param bstr_newtext: new plain text (not going beyond the end of the cipher)
    :return:
    """

    if offset >= len(barray_cipher):
        raise exceptions.ParamValueError

    if len(bstr_newtext) > len(barray_cipher) - offset:
        raise exceptions.ParamClashError

    counter = offset // 16
    keybytes_to_generate = len(bstr_newtext)
    secondary_key = b''
    while keybytes_to_generate > 0:
        bstr_nonce_ctr = bstr_nonce + struct.pack('<q', counter)
        secondary_key += aesEncrypt(bstr_nonce_ctr, bstr_key, bits)
        counter += 1
        keybytes_to_generate -= 1

    index_in_block = offset % 16
    secondary_key_sub = secondary_key[index_in_block:index_in_block +
                                      len(bstr_newtext)]

    new_cipher = xorBytestrings(bstr_newtext, secondary_key_sub)

    if len(bstr_newtext) == 1:
        barray_cipher[offset] = new_cipher[0]
    else:
        barray_cipher[offset:offset + len(bstr_newtext)] = new_cipher
Beispiel #9
0
def aesKeyExpansion(bstr_key):
    """
    Returns the roundkeys a list of byte strings
    TODO: make length parameters variable
    """
    if len(bstr_key) != 16 and len(bstr_key) != 24 and len(bstr_key) != 32:
        print("Invalid key length!")
        exit(1)
    numbits = len(bstr_key) * 8
    rounds = {128: 10, 192: 12, 256: 14}
    round_keys = []

    # transposed since we are operating on the columns
    prevkey = makeNDArrayFrom(bstr_key, 4, 4)

    newkey = b''
    offset = 0
    rcon_round = 1
    while len(round_keys) < rounds[numbits]:
        # on every first 4 byte group of the 16 byte blocks perform rotate,
        # subbytes
        if offset == 0:
            word = bytes(prevkey[3])
            word = aesKeyExpansionCore(word, rcon_round)
            rcon_round += 1
        else:
            word = newkey[offset - 4:offset]
        word_from_prevkey = bytes(prevkey.flatten())[offset:offset + 4]
        word = xorBytestrings(word, word_from_prevkey)
        newkey += word
        offset += 4
        if offset == 16:
            offset = 0
            prevkey = makeNDArrayFrom(newkey, 4, 4)
            # transpose back and convert to byte string before appending to
            # result list
            newkey = bytes(makeNDArrayFrom(newkey, 4, 4).flatten())
            round_keys.append(newkey)
            newkey = b''
    return round_keys
Beispiel #10
0
 def testXorBytestrings(self):
     bstr1 = b'\x01\x01\x01\x01\x01\x01\x01\x01'
     bstr2 = b'\x00\x00\x00\x00\x00\x00\x00\x00'
     result = helpers.xorBytestrings(bstr1, bstr2)
     self.assertEqual(result, b'\x01\x01\x01\x01\x01\x01\x01\x01')
     self.assertEqual(helpers.xorBytestrings(b'A', b'A'), b'\x00')
Beispiel #11
0
def aesAddRoundkey(ndarray_state, ndarray_key):
    return xorBytestrings(ndarray_state, ndarray_key)