예제 #1
0
def check_block_delta_candidate(block_delta_i):
    with cmsh.Model() as model:
        hf: hfa.md4 = hfa.resolve(ALGO)

        # Ensure our delta is valid.
        block_delta = model.to_vec(block_delta_i, hf.block_size)

        # First construct two blocks with the given delta.
        block_1 = model.vec(hf.block_size)
        block_2 = model.vec(hf.block_size)
        model.add_assert((block_1 ^ block_2) == block_delta)

        # Assume we have any possible iv. This is safe even in the case
        # that iv_1 == iv_2 and our delta doesn't align with the blocks
        # under test (3, 11, 7, or 15), because we later calculate the
        # last possible round where we could have a difference and still
        # collide.
        iv_1 = model.vec(hf.state_size)
        iv_2 = model.vec(hf.state_size)

        # Compute the last 4 rounds and check if this is a viable candidate
        # (that we can generate a collision with).
        output_1s, _ = hf.eval(model,
                               block_1,
                               iv=iv_1,
                               rounds=range(hf.rounds - 4, hf.rounds))
        output_2s, _ = hf.eval(model,
                               block_2,
                               iv=iv_2,
                               rounds=range(hf.rounds - 4, hf.rounds))
        output_1 = model.join_vec(output_1s)
        output_2 = model.join_vec(output_2s)
        model.add_assert(output_1 == output_2)

        assert model.solve()
예제 #2
0
def bench_cmsh(num_vars, benchmark):
    cs = cmsh.Model()
    cv = [cs.var() for x in range(0, num_vars)]

    for clause in benchmark:
        i_left, op, i_right = clause
        left = cv[i_left]
        right = cv[i_right]
        if op == 'and':
            cs.add_assert(left & right)
        elif op == 'notand':
            cs.add_assert(-left & right)
        elif op == 'andnot':
            cs.add_assert(left & -right)
        elif op == 'notandnot':
            cs.add_assert(-left & -right)
        elif op == 'or':
            cs.add_assert(left | right)
        elif op == 'notor':
            cs.add_assert(-left | right)
        elif op == 'ornot':
            cs.add_assert(left | -right)
        elif op == 'notornot':
            cs.add_assert(-left | -right)

    sat = cs.solve()
    result = []
    if sat:
        for var in cv:
            result.append(bool(var))

    return sat, result
예제 #3
0
def test_mersenne_double_seed():
    model = cmsh.Model()
    left_seed = model.vec(32)
    left_state = _mersenne.seed_rand(model, left_seed)
    left_index = -1

    right_seed = model.vec(32)
    right_state = _mersenne.seed_rand(model, right_seed)
    right_index = -1

    model.add_assert(left_seed != right_seed)

    left_value, left_index = _mersenne.gen_rand_long(model, left_state,
                                                     left_index)
    right_value, right_index = _mersenne.gen_rand_long(model, right_state,
                                                       right_index)
    model.add_assert(left_value == right_value)

    left_value, left_index = _mersenne.gen_rand_long(model, left_state,
                                                     left_index)
    right_value, right_index = _mersenne.gen_rand_long(model, right_state,
                                                       right_index)
    model.add_assert(left_value == right_value)

    assert model.solve()
    assert int(left_seed) == int(right_seed)
예제 #4
0
def build_collision(differential_path, offset, rounds):
    model = cmsh.Model()
    hf = md4.md4()
    hf.rounds = rounds

    block_1 = model.vec(512)
    block_1s = model.split_vec(block_1, 32)
    block_2 = model.vec(512)
    block_2s = model.split_vec(block_2, 32)

    output_1s, rounds_1s = hf.compute(model, block_1s)
    output_1 = model.join_vec(output_1s)
    rounds_1 = model.join_vec(rounds_1s)

    output_2s, rounds_2s = hf.compute(model, block_2s)
    output_2 = model.join_vec(output_2s)
    rounds_2 = model.join_vec(rounds_2s)

    model.add_assert(block_1 != block_2)
    model.add_assert(output_1 == output_2)

    model.add_assert((rounds_1 ^ rounds_2) == differential_path)

    if model.solve():
        print("SAT", offset)
        print(hex(int(block_1)))
        print(hex(int(block_2)))
        print(hex(int(output_1)))
        print(hex(int(block_1 ^ block_2)))
        print(hex(int(rounds_1 ^ rounds_2)))
    else:
        print("UNSAT", offset)
예제 #5
0
def main():
    model = cmsh.Model()
    hf = md4()

    iv_1 = model.vec(128)
    iv_2 = model.vec(128)

    block_1 = model.vec(512)
    block_2 = model.vec(512)

    output_1s, rounds_1s = hf.compute(model, block_1, iv=iv_1)
    output_1 = model.join_vec(output_1s)
    rounds_1 = model.join_vec(rounds_1s)

    output_2s, rounds_2s = hf.compute(model, block_2, iv=iv_2)
    output_2 = model.join_vec(output_2s)
    rounds_2 = model.join_vec(rounds_2s)

    model.add_assert(iv_1 != iv_2)
    model.add_assert(block_1 == 0)
    model.add_assert(block_2 == 0)
    model.add_assert(output_1 == output_2)

    if model.solve():
        print("SAT", int(iv_1), int(iv_2))
    else:
        print("UNSAT")

    model.cleanup()
예제 #6
0
def main():
    m = cmsh.Model()
    av0 = m.vec(64)
    av1 = m.vec(64)
    av2 = m.vec(64)
    av3 = m.vec(64)
    bv0 = m.vec(64)
    bv1 = m.vec(64)
    bv2 = m.vec(64)
    bv3 = m.vec(64)
    av = m.join_vec([av0, av1, av2, av3])
    bv = m.join_vec([bv0, bv1, bv2, bv3])

    ar0, ar1, ar2, ar3 = _siphash.sipround(av0, av1, av2, av3)
    br0, br1, br2, br3 = _siphash.sipround(bv0, bv1, bv2, bv3)
    ar = m.join_vec([ar0, ar1, ar2, ar3])
    br = m.join_vec([br0, br1, br2, br3])

    eqv = m.to_vec([av[i] == bv[i] for i in range(0, len(av))])
    m.add_assert(eqv.bit_sum() == 255)

    eqr = m.to_vec([ar[i] == br[i] for i in range(0, len(ar))])
    m.add_assert(eqr.bit_sum() == 250)

    sat = m.solve()
    # assert not sat

    if sat:
        print(hex(int(av)))
        print(hex(int(bv)))
        print(hex(int(ar)))
        print(hex(int(br)))
예제 #7
0
def collision(block_differentials, rounds):
    model = cmsh.Model()
    algo = sha1()

    block_1 = model.vec(512)
    block_1s = model.split_vec(block_1, 32)
    block_2 = model.vec(512)
    block_2s = model.split_vec(block_2, 32)

    b1w = algo.block_schedule(model, block_1s)
    w_1 = model.join_vec(b1w)
    b2w = algo.block_schedule(model, block_2s)
    w_2 = model.join_vec(b2w)

    output_1s, _ = algo.compute(model, block_1s, rounds=rounds)
    output_1 = model.join_vec(output_1s)
    output_2s, _ = algo.compute(model, block_2s, rounds=rounds)
    output_2 = model.join_vec(output_2s)

    model.add_assert((block_1 ^ block_2) == to_int(block_differentials))
    model.add_assert((output_1 ^ output_2) == 0)

    if model.solve():
        print(
            "SAT",
            block_differentials,
            hex(int(block_1)),
            hex(int(block_2)),
            hex(int(block_1 ^ block_2)),
            hex(int(output_1)),
        )
    else:
        print("UNSAT", block_differentials)
예제 #8
0
def test_md4_find_ivs():
    model = cmsh.Model()
    h = md4()

    k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9"
    k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9"

    blocks_value_1 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k1, 8)))
    blocks_value_2 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k2, 8)))

    bv1 = model.join_vec(blocks_value_1)
    bv2 = model.join_vec(blocks_value_2)

    r_value_1, r_rounds_1 = h.compute(model, blocks_value_1)
    r_value_2, r_rounds_2 = h.compute(model, blocks_value_2)
    rv1 = model.join_vec(r_value_1)
    rsv1 = model.join_vec(r_rounds_1)

    blocks_1 = gen_blocks(model, 16, 32)
    blocks_2 = gen_blocks(model, 16, 32)
    b1 = model.join_vec(blocks_1)
    b2 = model.join_vec(blocks_2)

    iv_1_arr = gen_blocks(model, 4, 32)
    iv_2_arr = gen_blocks(model, 4, 32)
    iv_1 = model.join_vec(iv_1_arr)
    iv_2 = model.join_vec(iv_2_arr)

    # The blocks must differ...
    model.add_assert(b1 == bv1)
    model.add_assert(b2 == bv2)

    # But their MD4s must be the same
    result_1_arr, rounds_1_arr = h.compute(model, blocks_1, iv=iv_1_arr)
    result_2_arr, rounds_2_arr = h.compute(model, blocks_2, iv=iv_2_arr)

    result_1 = model.join_vec(result_1_arr)
    rounds_1 = model.join_vec(rounds_1_arr)
    result_2 = model.join_vec(result_2_arr)
    rounds_2 = model.join_vec(rounds_2_arr)

    model.add_assert(iv_1 == iv_2)
    model.add_assert(result_1 == rv1)
    model.add_assert(rounds_1 == rsv1)
    model.add_assert(result_1 == result_2)

    rr1 = model.join_vec(r_rounds_1)
    rr2 = model.join_vec(r_rounds_2)

    real_diff_path = rr1 ^ rr2
    differential = rounds_1 ^ rounds_2

    diff_path = differential == real_diff_path

    model.add_assume(diff_path)
    assert model.solve()
예제 #9
0
def main():
    m = cmsh.Model()
    key = m.vec(128)

    r1 = _siphash.siphash(m, key, key, outlen=16, cROUNDS=1, dROUNDS=1)

    m.add_assert(r1 == key)
    assert m.solve()

    print(hex(int(key)))
예제 #10
0
def test_md4_find_existing_collision():
    model = cmsh.Model()
    h = md4()

    k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9"
    k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9"
    blocks_value_1 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k1, 8)))
    blocks_value_2 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k2, 8)))

    indices = []
    for i in range(0, len(blocks_value_1)):
        if blocks_value_1[i] != blocks_value_2[i]:
            indices.append(i)

    r_value_1, r_rounds_1 = h.compute(model, blocks_value_1)
    r_value_2, r_rounds_2 = h.compute(model, blocks_value_2)

    blocks_1 = gen_blocks(model, 16, 32)
    blocks_2 = gen_blocks(model, 16, 32)

    # The blocks must differ...
    different_blocks = blocks_1[0] != blocks_2[0]
    for i in range(1, len(blocks_1)):
        different_blocks = different_blocks | (blocks_1[i] != blocks_2[i])
    model.add_assert(different_blocks)

    for i in range(0, len(blocks_1)):
        if i not in indices:
            model.add_assert(blocks_1[i] == blocks_value_1[i])
        model.add_assert(blocks_2[i] == blocks_value_2[i])

    # But their MD4s must be the same
    result_1, rounds_1 = h.compute(model, blocks_1)
    result_2, rounds_2 = h.compute(model, blocks_2)

    for i in range(0, 4):
        model.add_assert(result_2[i] == result_2[i])

    for i in range(0, len(rounds_1)):
        r_differential = r_rounds_1[i] ^ r_rounds_2[i]
        differential = rounds_1[i] ^ rounds_2[i]

        model.add_assert(differential == r_differential)

    assert model.solve()
    variables = []
    for index in indices:
        assert int(blocks_1[index]) == int(blocks_value_1[index])
        assert int(blocks_1[index] != blocks_2[index])
        variables.extend(blocks_1[index])

    new_solution = model.negate_solution(variables)
    model.add_assert(new_solution)

    assert not model.solve()
def main():
    mod = cmsh.Model()

    k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9"
    k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9"

    index = 1
    blocks_value_1 = list(
        map(lambda x: mod.to_vector(x, width=32), split_hex(k1, 8)))
    blocks_value_2 = list(
        map(lambda x: mod.to_vector(x, width=32), split_hex(k2, 8)))

    r_value_1, r_rounds_1 = _md4.md4(mod, blocks_value_1)
    r_value_2, r_rounds_2 = _md4.md4(mod, blocks_value_2)

    assert r_rounds_1[0] == r_rounds_2[0]
    a, b, c, d = (
        mod.vec(32),
        md4.md4.default_state[1],
        md4.md4.default_state[2],
        md4.md4.default_state[3],
    )
    x_a, x_b, x_c, x_d = 0, 0, 0, 0
    new_d_1, new_d_2 = r_rounds_1[1], r_rounds_2[1]
    x_new_d = new_d_1 ^ new_d_2
    assert new_d_1 != new_d_2

    # abcd
    # dabc
    new_x_1, new_x_2 = mod.vec(32), mod.vec(32)
    i_a, i_b, i_c, i_d = mod.vec(32), mod.vec(32), mod.vec(32), mod.vec(32)
    j_a, j_b, j_c, j_d = mod.vec(32), mod.vec(32), mod.vec(32), mod.vec(32)
    l_out_1 = _md4.md4_round([new_x_1], _md4.md4r1, [i_d, i_a, i_b, i_c], 0,
                             7)[1]
    l_out_2 = _md4.md4_round([new_x_2], _md4.md4r1, [j_d, j_a, j_b, j_c], 0,
                             7)[1]

    mod.add_assert(new_x_1 < new_x_2)
    mod.add_assert(i_a == j_a)
    mod.add_assert(i_b == j_b)
    mod.add_assert(i_c == j_c)
    mod.add_assert(i_d == j_d)
    mod.add_assert((l_out_1 ^ l_out_2) == (x_new_d))
    sat = mod.solve()
    assert sat
    while sat:
        print(
            bin(int(i_a) ^ int(j_a)),
            bin(int(new_x_1) ^ int(new_x_2)),
            bin(int(x_new_d)),
        )
        negated = mod.negate_solution(new_x_1 ^ new_x_2)

        mod.add_assert(negated)
        sat = mod.solve()
예제 #12
0
def test_known_value():
    model = cmsh.Model()
    h = md4()

    block_hex = "8" + ("0" * 127)
    block = list(map(lambda x: model.to_vector(x, width=32), split_hex(block_hex)))

    res_hex = "31d6cfe0d16ae931b73c59d7e0c089c0"
    res_known = list(map(lambda x: model.to_vector(x, width=32), split_hex(res_hex)))
    res, _ = h.compute(model, block)

    assert list(map(int, res_known)) == list(map(int, res))
예제 #13
0
def test_md4_eval():
    iv = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
    rounds = 16
    block = [0x00000080] + [0x00000000] * 15

    model = cmsh.Model()
    h = md4()

    output_state, intermediate = h.eval(model, block, iv, rounds)
    actual_state = list(map(int, output_state))
    expected_state = [0xaddcb303, 0x3665f296, 0x8ee8f245, 0xa483a664]

    assert actual_state == expected_state
예제 #14
0
def test_known_value():
    model = cmsh.Model()
    h = md5()

    block_hex = "8" + ("0" * 127)
    block = list(
        map(lambda x: model.to_vector(x, width=32), split_hex(block_hex)))

    res_hex = "d41d8cd98f00b204e9800998ecf8427e"
    res_known = list(
        map(lambda x: model.to_vector(x, width=32), split_hex(res_hex)))
    res, _ = h.compute(model, block)

    assert list(map(int, res_known)) == list(map(int, res))
예제 #15
0
def test_known_value():
    model = cmsh.Model()
    h = sha1()

    block_hex = "80000000" + ("0" * 120)
    block = list(
        map(lambda x: model.to_vector(x, width=32), split_hex(block_hex)))

    res_hex = "da39a3ee5e6b4b0d3255bfef95601890afd80709"
    res_known = list(
        map(lambda x: model.to_vector(x, width=32), split_hex(res_hex)))
    res, _ = h.compute(model, block)

    assert list(map(int, res_known)) == list(map(int, res))
예제 #16
0
def test_md4_known_collision():
    model = cmsh.Model()
    h = md4()

    k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9"
    k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9"
    blocks_1 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k1, 8)))
    blocks_2 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k2, 8)))

    assert list(map(int, blocks_1)) != list(map(int, blocks_2))
    assert len(blocks_1) == 16
    assert len(blocks_2) == 16

    res_1, _ = h.compute(model, blocks_1)
    res_2, _ = h.compute(model, blocks_2)
    assert list(map(int, res_1)) == list(map(int, res_2))
예제 #17
0
def test_mersenne_known_test_vectors():
    model = cmsh.Model()
    state = _mersenne.seed_rand(model, 1131464071)
    assert len(state) == 624
    assert int(state[0]) == 1131464071
    assert int(state[1]) == (69069 * int(state[0])) & 0xffffffff

    index = -1
    value, index = _mersenne.gen_rand_long(model, state, index)
    assert int(value) == 3720971106
    value, index = _mersenne.gen_rand_long(model, state, index)
    assert int(value) == 1185582179
    value, index = _mersenne.gen_rand_long(model, state, index)
    assert int(value) == 2564798321
    value, index = _mersenne.gen_rand_long(model, state, index)
    assert int(value) == 1931142078
예제 #18
0
def model(differential=[]):
    model = cmsh.Model()
    hf = hfa.md4()

    rounds = range(48 - 24, 48)
    iv_1 = model.vec(128)
    iv_2 = model.vec(128)
    block_1 = model.vec(512)
    block_1s = model.split_vec(block_1, 32)
    block_2 = model.vec(512)
    block_2s = model.split_vec(block_2, 32)

    output_1s, rounds_1s = hf.eval(model, block_1, iv_1, rounds)
    output_1 = model.join_vec(output_1s)

    output_2s, rounds_2s = hf.eval(model, block_2, iv_2, rounds)
    output_2 = model.join_vec(output_2s)

    for index in differential:
        model.add_assert(rounds_1s[index] == rounds_2s[index])

    model.add_assert(output_1 == output_2)
    model.add_assert(block_1 < block_2)
    model.add_assert(iv_1 == iv_2)

    for i in range(48 - 4, 48):
        bi = hf.block_schedule[i]
        model.add_assert(block_1s[bi] == block_2s[bi])

    if model.solve():
        print(hex(int(iv_1)), hex(int(block_1)), hex(int(output_1)))
        print(hex(int(iv_2)), hex(int(block_2)), hex(int(output_2)))
        dif = []
        for index, element_1 in enumerate(block_1s):
            element_2 = block_2s[index]
            dif.append(hex(int(element_1) ^ int(element_2)))
        print(dif)
        dif = []
        dc = 0
        for index, element_1 in enumerate(rounds_1s):
            element_2 = rounds_2s[index]
            if int(element_1) != int(element_2):
                dc += 1
            dif.append(hex(int(element_1) ^ int(element_2)))
        print(dif, len(dif), dc)
예제 #19
0
def main():
    with cmsh.Model() as model:
        # Model IV as 4x 32-bit vectors
        iv_1 = model.vec(128)
        iv_2 = model.vec(128)
        iv_1s = model.split_vec(iv_1, 32)
        iv_2s = model.split_vec(iv_2, 32)

        # Model final state as random 4x 32-bit vectors
        final_1 = model.vec(128)
        final_2 = model.vec(128)
        final_1s = model.split_vec(final_1, 32)
        final_2s = model.split_vec(final_2, 32)

        # Model output state as sum of iv and final
        output_1s = [ iv_1s[i] + final_1s[i] for i in range(0, len(iv_1s)) ]
        output_2s = [ iv_2s[i] + final_2s[i] for i in range(0, len(iv_2s)) ]
        output_1 = model.join_vec(output_1s)
        output_2 = model.join_vec(output_2s)

        model.add_assert(output_1 == output_2)

        # Compute IV and Final deltas:
        iv_d = iv_1 ^ iv_2
        final_d = final_1 ^ final_2

        # With iv_d == 0, the only solution is final_d == 0; i.e., it is
        # sufficient to ignore the outer addition in this construction.
        #
        # For each iv_d non-zero, there may be one or more answers.
        model.add_assert(iv_d.bit_sum() == 0)

        count = 0
        while model.solve():
            print(bin(int(iv_d)), bin(int(final_d)))
            new_iv_d = iv_d != int(iv_d)
            new_final_d = final_d != int(final_d)

            model.add_assert(new_iv_d | new_final_d)
            count += 1

            if count % 100 == 0:
                print(count)

        print(count)
예제 #20
0
def validate_output(algo, o_model, block, iv, output, rounds):
    hf: hfa.md4 = hfa.fresh(algo)
    block = _normalize_(o_model, block)
    iv = _normalize_(o_model, iv)
    output = _normalize_(o_model, output)
    rounds = _normalize_(o_model, rounds)

    with cmsh.Model() as model:
        output_a, rounds_a = hf.compute(model,
                                        block,
                                        iv=iv,
                                        rounds=algo.rounds)

        output_a = _normalize_(model, output_a)
        rounds_a = _normalize_(model, rounds_a)

        assert output_a == output
        assert rounds_a == rounds
예제 #21
0
def test_known_value():
    model = cmsh.Model()
    hf = siphash()

    key = model.to_vec(0x00, 128)
    block = []
    assert int(hf.compute(model, key, block)) == 0x1E924B9D737700D7

    key = model.to_vec(0x000102030405060708090A0B0C0D0E0F, 128)
    block = model.to_vec(0x000102030405060708090A0B0C0D0E, 120)
    assert int(hf.compute(model, key, block)) == 0xA129CA6149BE45E5

    key = model.to_vec(0x00, 128)
    block = model.to_vec(0x48656C6C6F20776F726C64, 88)
    assert int(hf.compute(model, key, block)) == 0xC9E8A3021F3822D9

    key = model.to_vec(0x00, 128)
    block = model.to_vec(0x3132333435363738313233, 88)
    assert int(hf.compute(model, key, block)) == 0xF95D77CCDB0649F
예제 #22
0
def test_mersenne_reverse_seed():
    model = cmsh.Model()

    seed = model.vec(32)
    state = _mersenne.seed_rand(model, seed)

    index = -1
    expectations = [
        3720971106, 1185582179, 2564798321, 1931142078, 1922624258, 2775287020,
        184205937, 612490464, 3208490327, 1665128171, 1140358085, 3611116024,
        953884115, 4099552555, 2606495820, 685898173
    ]

    for expected in expectations:
        value, index = _mersenne.gen_rand_long(model, state, index)
        model.add_assert(value == expected)

    assert model.solve()
    assert int(seed) == 1131464071
예제 #23
0
def last_possible_round(block_delta_i):
    with cmsh.Model() as model:
        hf: hfa.md4 = hfa.resolve(ALGO)

        # Ensure our delta is valid and split it into block-sized chunks.
        block_delta = model.to_vec(block_delta_i, hf.block_size)
        block_deltas = model.split_vec(block_delta, hf.block_size // hf.blocks)
        last_round = 0

        delta_indices = set()

        for round_num, block_index in enumerate(hf.block_schedule):
            if int(block_deltas[block_index]) != 0:
                delta_indices.add(block_index)
                last_round = round_num

        assert last_round != 0

        return tuple(delta_indices), last_round
예제 #24
0
def test_save_collision():
    with cmsh.Model() as model:
        hf = hfa.resolve('md4')

        k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9"
        k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9"

        assert k1 != k2

        known_shaped_1 = list(
            map(lambda x: model.to_vector(x, width=32), hfa.split_hex(k1, 8)))
        known_shaped_2 = list(
            map(lambda x: model.to_vector(x, width=32), hfa.split_hex(k2, 8)))

        block_1 = model.vec(hf.block_size)
        block_2 = model.vec(hf.block_size)

        output_1s, rounds_1s = hf.compute(model, block_1)
        output_2s, rounds_2s = hf.compute(model, block_2)

        output_1 = model.join_vec(output_1s)
        output_2 = model.join_vec(output_2s)

        rounds_1 = model.join_vec(rounds_1s)
        rounds_2 = model.join_vec(rounds_2s)

        model.add_assert(block_1 < block_2)
        model.add_assert(block_1 == model.join_vec(known_shaped_1))
        model.add_assert(block_2 == model.join_vec(known_shaped_2))
        model.add_assert(output_1 == output_2)

        assert model.solve()
        assert int(output_1) == int(output_2)

        db = hfd.Database(":memory:")
        default_state = model.join_vec(
            map(lambda x: model.to_vec(x, 32), hf.default_state))
        hfd.create_table(db, hf)
        hfd.save_collision(db, hf, model, block_1, default_state, output_1,
                           rounds_1, block_2, default_state, output_2,
                           rounds_2)
        db.close()
예제 #25
0
def validate_collision(algo, o_model, block_1, iv_1, block_2, iv_2):
    hf: hfa.md4 = hfa.fresh(algo)
    block_1 = _normalize_(o_model, block_1)
    iv_1 = _normalize_(o_model, iv_1)
    block_2 = _normalize_(o_model, block_2)
    iv_2 = _normalize_(o_model, iv_2)

    with cmsh.Model() as model:
        o_1, r_1 = hf.compute(model, block_1, iv=iv_1, rounds=algo.rounds)
        o_2, r_2 = hf.compute(model, block_2, iv=iv_2, rounds=algo.rounds)

        for index, i_1 in enumerate(o_1):
            assert int(i_1) == int(o_2[index])

        assert block_1 != block_2 or iv_1 != iv_2

        if block_1 > block_2:
            return True
        if block_1 == block_2 and iv_1 > iv_2:
            return True
        return False
예제 #26
0
def main():
    model = cmsh.Model()
    hf = md5()

    block_1 = model.vec(512)
    block_1s = model.split_vec(block_1, 32)

    output_1s, rounds_1s = hf.compute(model, block_1s)
    output_1 = model.join_vec(output_1s)
    rounds_1 = model.join_vec(rounds_1s)

    model.add_assert(block_1[0:32].bit_sum() == 4)
    model.add_assert(block_1[32:] == 0)
    model.add_assert(output_1 == 0xD41D8CD98F00B204E9800998ECF8427E)

    print("Solving...")
    if model.solve():
        print("SAT", int(block_1))
    else:
        print("UNSAT")

    model.cleanup()
예제 #27
0
def load_known_pieces(db, hf, block_delta_i):
    with cmsh.Model() as model:
        # Split into block-sized chunks so we can iterate over database data
        # and check if it is relevant for this solving session.
        block_delta = model.split_vec(
            model.to_vec(block_delta_i, hf.block_size),
            hf.block_size // hf.blocks)

        table_name = hf.name + "_collision_pieces"
        cols = [
            'round', 'h1_state', 'h2_state', 'd_state', 'h1_block', 'h2_block',
            'd_block', 'h1_output', 'h2_output', 'd_output'
        ]
        for row in db.query(table_name, cols):
            row['round'] = int(row['round'])
            round_num = row['round']
            block_index = hf.block_schedule[round_num]
            d_block = hex(int(block_delta[block_index]))[2:]

            if row['d_block'] != d_block:
                continue

            yield row
예제 #28
0
def find_differential(num_block_bits, state_differential):
    with cmsh.Model() as model:
        model.solver.config_timeout(30)

        hf: hfa.md4 = hfa.resolve('md4')

        raw_block_1 = model.vec(32)
        raw_block_2 = model.vec(32)
        model.add_assert((raw_block_1 ^ raw_block_2).bit_sum() == num_block_bits)

        block_1 = [ raw_block_1 ] * (hf.block_size // 32)
        block_2 = [ raw_block_1 ] * (hf.block_size // 32)

        for round_index in range(0, hf.rounds):
            iv_1 = model.vec(hf.state_size)
            iv_1s = model.split_vec(iv_1, hf.int_size)
            iv_2 = model.vec(hf.state_size)
            iv_2s = model.split_vec(iv_2, hf.int_size)

            model.add_assert((iv_1s[0] ^ iv_2s[0]) == state_differential)

            for index, state_1 in enumerate(iv_1s[1:], start=1):
                model.add_assert(state_1 == iv_2s[index])

            output_1s, _ = hf.eval(model, block_1, iv=iv_1s, rounds=[round_index])
            output_2s, _ = hf.eval(model, block_2, iv=iv_2s, rounds=[round_index])

            output_1 = model.join_vec(output_1s)
            output_2 = model.join_vec(output_2s)

            model.add_assert(output_1 == output_2)

        sat = model.solve()
        if sat is True:
            print(f"{state_differential} - SAT")
        elif sat is None:
            print(f"{state_differential} - timeout")
예제 #29
0
def build_collision(family, rounds):
    model = cmsh.Model()
    hf = md4()
    hf.rounds = rounds

    block_1 = model.vec(512)
    block_1s = model.split_vec(block_1, 32)
    block_2 = model.vec(512)
    block_2s = model.split_vec(block_2, 32)

    output_1s, rounds_1s = hf.compute(model, block_1s)
    output_1 = model.join_vec(output_1s)
    rounds_1 = model.join_vec(rounds_1s)

    output_2s, rounds_2s = hf.compute(model, block_2s)
    output_2 = model.join_vec(output_2s)
    rounds_2 = model.join_vec(rounds_2s)

    model.add_assert(block_1 != block_2)
    model.add_assert(output_1 == output_2)

    assert len(rounds_1s) == rounds
    assert len(rounds_2s) == rounds

    for r_index in range(0, rounds):
        if r_index in family:
            model.add_assert((rounds_1s[r_index] ^ rounds_2s[r_index]) != 0)
        else:
            model.add_assert((rounds_1s[r_index] ^ rounds_2s[r_index]) == 0)

    if model.solve():
        print("SAT", family, rounds)
    else:
        print("UNSAT", family, rounds)

    model.cleanup()
예제 #30
0
def main():
    m = cmsh.Model()
    v0 = m.vec(64)
    v1 = m.vec(64)
    v2 = m.vec(64)
    v3 = m.vec(64)

    r0, r1, r2, r3 = _siphash.sipround(v0, v1, v2, v3)
    o0, o1, o2, o3 = _siphash.sipround(r0, r1, r2, r3)

    m.add_assert(v0 == o0)
    m.add_assert(v1 == o1)
    m.add_assert(v2 == o2)
    m.add_assert(v3 == o3)

    sat = m.solve()
    assert sat

    while sat:
        print(hex(int(v0)), hex(int(v1)), hex(int(v2)), hex(int(v3)))
        joined = m.join_vec([v0, v1, v2, v3])
        negated = m.negate_solution(joined)
        m.add_assert(negated)
        sat = m.solve()