Пример #1
0
def make_a_decision(bad_var_term_pairs, p_unif_problem):
    constraints = p_unif_problem.constraints
    disequations = p_unif_problem.disequations
    for (var, term) in bad_var_term_pairs:
        if (isinstance(term, Constant)):
            continue
        if (isinstance(term, FuncTerm) and term.function.symbol == "h"):
            continue
        if (isinstance(term, FuncTerm) and term.function.symbol == "f"):
            #fix it using the Prev rule
            term = convert_to_xorterm(term)
            for prev_term in constraints[var]:
                if (not isinstance(prev_term, Variable)):
                    candidate_equation = Equation(xor(term, prev_term), Zero())
                    if (consistent_with_diseqs(candidate_equation,
                                               disequations)):
                        return candidate_equation
        if (isinstance(term, Variable)):
            #set it to zero if consistent
            candidate_equation = Equation(term, Zero())
            if (consistent_with_diseqs(candidate_equation, disequations)):
                return candidate_equation
        if (isinstance(term, XORTerm)):
            #if it has a variable x in it, set x to some subset
            #otherwise, use the cancel rule to cancel two terms
            terms = term.arguments
            terms = simplify(terms)
            terms = list(map(convert_to_xorterm, terms))
            vars = get_vars_in_list(terms)
            if (len(vars) == 0):
                pairs = findsubsets(terms, 2)
                #print(pairs)
                for pair in pairs:
                    (left, right) = pair
                    left = convert_to_xorterm(left)
                    right = convert_to_xorterm(right)
                    candidate_equation = Equation(xor(left, right), Zero())
                    if (consistent_with_diseqs(candidate_equation,
                                               disequations)):
                        return candidate_equation
            else:
                for var in vars:
                    subsets = powerset(terms)
                    for subset in subsets:
                        xor_terms = list(set(subset) | set([var]))
                        if (len(xor_terms) == 1):
                            left_side = xor_terms[0]
                        else:
                            left_side = xor(*xor_terms)
                        candidate_equation = Equation(left_side, Zero())
                        if (consistent_with_diseqs(candidate_equation,
                                                   disequations)):
                            return candidate_equation
    return None
Пример #2
0
def test_pick_fail():
    c = Function("C", 3)
    f = Function("f", 1)
    a = Constant("a")
    b = Constant('1')
    e = Constant("e")
    p = Constant('p')
    q = Constant('q')
    i = Constant('i')
    j = Constant('j')
    x = Variable("x")
    z = Zero()

    func = FuncTerm(f, [a])
    func2 = FuncTerm(f, [e])

    func_pi = FuncTerm(c, [p, i, b])
    func_qj = FuncTerm(c, [q, j, b])

    eq1 = Equation(func, z)
    eq2 = Equation(func_qj, x)
    eq3 = Equation(xor(func_pi, func), z)
    eq4 = Equation(xor(xor(func_pi, func), func2), z)

    topf: Set[Equation] = {eq1, eq4}
    print("Testing pick_fail with ", topf)
    new_set = pick_fail(topf, cbc_gen)
    print("Result: ", new_set)
    print()

    topf: Set[Equation] = {eq1, eq2, eq3}
    print("Testing pick_fail with ", topf)
    new_set = pick_fail(topf, ex4_gen)
    print("Result: ", new_set)
    print()
Пример #3
0
def test_check_xor_structure():
    f = Function("f", 1)
    a = Constant("a")
    b = Constant("b")
    c = Constant("c")
    x = Variable("x")
    z = Zero()

    func = FuncTerm(f, [a])
    func1 = FuncTerm(f, [b])
    func2 = FuncTerm(f, [c])
    func3 = FuncTerm(f, [x])
    func4 = xor(func, func1)
    func5 = xor(func2, func3)

    eq1 = Equation(func, b)
    eq2 = Equation(func3, c)
    eq3 = Equation(func5, z)
    eq4 = Equation(xor(func2, func3), z)
    eq5 = Equation(xor(func4, func5), z)

    topf: Set[Equation] = {eq1, eq2, eq3, eq5}

    print("Testing pick_f with equation set: ", topf)
    print("Result pick_f: ", pick_f(topf))
    print()
Пример #4
0
def get_resolution_term_and_remaining_term(t):
    #Assume that t is in XOR form.
    #For example, if t is f(x) + a + b + c
    #The result is [(f(x), a + b + c), (a, f(x) + b + c), (b, f(x) + a + c), (c, f(x) + a + b)]
    if (not is_XOR_Term(t)):
        return [(t, Zero())]
    else:
        length = len(t.arguments)
        results = []
        for i in range(0, length):
            remaining = deepcopy(t.arguments)
            del remaining[i]
            results.append((t.arguments[i], XORTerm(remaining)))
        return results
Пример #5
0
def test_elimf():
    f = Function("f", 1)
    xo = Function("f", 2)
    z = Zero()
    c = Constant("c")
    x = Variable("x")
    b = Variable("b")

    func = FuncTerm(f, [x])
    func2 = FuncTerm(f, [z])
    func3 = FuncTerm(xo, [c, b])

    eq1 = Equation(func, c)
    eq2 = Equation(xor(func, func3), z)
    eq3 = Equation(b, func)
    eq4 = Equation(func2, z)

    topf: Set[Equation] = {eq1, eq2, eq3, eq4}
    print("Testing elim_f with ", topf)
    new_set = elim_f(topf)
    print("Result ", new_set)
    print()
Пример #6
0
def test_pick_c():
    c = Function("C", 3)
    f = Function("f", 1)
    a = Constant("a")
    b = Constant('1')
    p = Constant('p')
    q = Constant('q')
    i = Constant('i')
    j = Constant('j')
    x = Variable("x")
    z = Zero()

    func = FuncTerm(f, [a])

    func_pi = FuncTerm(c, [p, i, b])
    func_qj = FuncTerm(c, [q, j, b])

    eq1 = Equation(func, z)
    eq2 = Equation(func_qj, x)
    eq3 = Equation(xor(func_pi, func), 0)

    topf: Set[Equation] = {eq1, eq2, eq3}
    print("Testing pick_c with ", topf)
Пример #7
0
def fix(sigma, constraint):
    #Fix sigma by instantiating it so that it becomes a P-unifier.
    print("fixing:")
    print(sigma)
    if (contains_original_var_only(sigma)):
        return sigma
    else:
        #Prepare for a list of saturation problem
        problem_list = []
        for var in sigma.domain():
            if (is_original_variable(var)):
                problem = deepcopy(constraint[var])
                problem.append(ConstrainedTerm(var * sigma, SubstituteTerm()))
                problem_list.append(problem)

        #Solve them
        list_of_substitutions = []
        for p in problem_list:
            saturation_result = saturate(p)
            substs = []
            for sat_res in saturation_result:
                if (sat_res.term == Zero()):
                    substs.append(sat_res.constraint)
            list_of_substitutions.append(substs)

        #Combine the resulting substitutions
        results = combine_list_of_substitutions(list_of_substitutions)
        if (results == []):
            return None

        #Find a substitution that can be fixed recursively
        # Use it to instantiate sigma, return the result
        for tau in results:
            result = fix(tau, instantiate_a_constraint(constraint, tau))
            if (result != None):
                return sigma * result
        return None
Пример #8
0
def test_elimc():
    c = Function("C", 3)
    p = Constant('p')
    q = Constant('q')
    i = Constant('i')
    j = Constant('j')
    a = Constant('1')
    x = Variable("x")
    z = Zero()

    func_pi = FuncTerm(c, [p, i, a])
    func_qj = FuncTerm(c, [q, j, a])

    eq1 = Equation(xor(func_pi, func_qj), z)
    eq2 = Equation(xor(func_qj, func_pi), z)
    eq3 = Equation(func_pi, x)

    topf: Set[Equation] = {eq1, eq2, eq3}
    print("Testing elim_c with ", topf)
    new_set = elim_c(topf)
    print("Result: ", new_set)
    print()

    b = Constant('2')

    func_pi = FuncTerm(c, [p, i, a])
    func_qj = FuncTerm(c, [q, j, b])

    eq1 = Equation(xor(func_pi, func_qj), z)
    eq2 = Equation(xor(func_qj, func_pi), z)

    topf: Set[Equation] = {eq1, eq2}
    print("Testing elim_c with ", topf)
    new_set = elim_c(topf)
    print("Result: ", new_set)
    print()
Пример #9
0
"""
Functions that check syntatically
the security of a mode of operation.

Based on Hai Lin's work.
"""
from typing import Tuple, Dict, List, Optional
from symcollab.algebra import Term, Function, Variable, Constant, FuncTerm
from symcollab.xor import xor
from symcollab.xor.structure import Zero

__all__ = ['moo_depth_random_check']

f = Function("f", 1)
zero = Zero()


def moo_depth_random_check(
        last_block: Term,
        block: Term,
        possible_subs: Optional[Dict[Term, List[Term]]] = None) -> bool:
    """
    Given two sequential ciphertexts, infer whether the
    mode of operation is secure by analyzing the depths
    of encryption applied and whether it has randomness.

    False in this context means a maybe.
    """
    _, last_high = moo_f_depth(last_block, possible_subs)
    low, high = moo_f_depth(block, possible_subs)
    return low == high and \
Пример #10
0
b = Constant("b")
c = Constant("c")
d = Constant("d")
f = Function("f", 1)

t0 = a
t1 = xor(a, b)
t2 = xor(b, c)
t3 = f(xor(x1, c))
t4 = f(x2)

constraint = dict()
constraint[x1] = [t1, t0]
constraint[x2] = [t0, t1, t2]
constraint[x3] = [t1, t2, t3]
constraint[x4] = [t1, t2, t3, t4]
initial_list = [t1, t2, t3, t4]

constraint = add_empty_subst_to_dictionary(constraint)

initial_list = list(map(convert_to_XORTerm, initial_list))
initial_list = add_empty_subst_to_initial_list(initial_list)

results = saturate(initial_list)
for res in results:
    if (res.term == Zero()):
        result = fix(res.constraint, constraint)
        if (result != None):
            print("I found a unifier:")
            print(result)
Пример #11
0
def disequation_from_equation(eq):
    lhs = deepcopy(eq.left_side)
    return Disequation(lhs, Zero())
Пример #12
0
def moo_check(moo_name: str = 'cipher_block_chaining',
              schedule_name: str = 'every',
              unif_algo: Callable = p_unif,
              length_bound: int = 10,
              knows_iv: bool = True,
              invert_check: bool = False) -> 'MOOCheckResult':
    """
    Simulates a MOOProgram interaction and checks if any conditions for security fails.
    Currently it checks syntactically and for collisions.

    Parameters
    ==========
    moo_name: str
      Name of the mode of operation to consider.
    schedule_name: str
      Name of the schedule to consider.
    unif_algo: Callable
      Unification algorithm to use when checking for collisions
    length_bound: int
      The maximum interactions to check for collisions. Default is 10.
    knows_iv: bool
      Whether or not the adversary knows the initialization vector.

    """
    program = MOOProgram(moo_name, schedule_name)
    xor_zero = Zero()
    constraints: Dict[Variable, List[Term]] = dict()
    known_terms: List[Term] = [xor_zero, program.nonces[0]
                               ] if knows_iv else [xor_zero]
    ciphertexts_received: List[Term] = list()
    result = None
    invertible = False

    # Start interactions

    # Custom case seems to fail, but it may be a parse error
    # xor(f(C[i-1]),xor(f(f(C[i-1])),P[i])) does not parse, but it is correct.

    def symbolic_moo_gen(session_label, block_label):
        c = Function("C", 3)
        p = Constant(session_label)
        i = Constant(block_label)
        a = Constant("1")
        pList = [
            Variable(f"x{session_label}{block_label}"),
            Variable(f"x{session_label}{block_label}"),
            Variable(f"x{session_label}{block_label}")
        ]
        cList = [c(p, i, a), c(p, i, a), c(p, i, a)]
        return program.chaining_function(3, [0], pList, cList)

    symbolic_check_secure = symbolic_check(symbolic_moo_gen)
    #print("Result :", symbolic_check_secure)

    for i in range(1, length_bound + 1):
        plaintext = Variable(f"x_{i}")
        constraints[plaintext] = deepcopy(known_terms)
        if unif_algo != XOR_rooted_security:
            known_terms.append(plaintext)

        result = program.rcv_block(plaintext)
        if result is not None:
            ciphertext = unravel(result.message, result.substitutions)

            #check for invertibility
            if invert_check and i == 1:
                invertible = InvertMOO(ciphertext, f"x_{i}", program.nonces,
                                       program.nonces[0], knows_iv)

            # Check for syntactic security
            #if len(ciphertexts_received) > 1:
            #    last_ciphertext = ciphertexts_received[-1]
            #    if moo_depth_random_check(last_ciphertext, ciphertext, constraints):
            #        return MOOCheckResult(True, None, invertible, i)
            if symbolic_check_secure:
                return MOOCheckResult(True, None, invertible)

            # Check for collisions
            new_constraints = deepcopy(constraints)
            collisions = search_for_collision(ciphertext, ciphertexts_received,
                                              new_constraints, unif_algo)
            if any_unifiers(collisions):
                return MOOCheckResult(False, collisions, invertible, i)

            known_terms.append(ciphertext)
            ciphertexts_received.append(ciphertext)

    # Stop Interaction
    last_result = program.rcv_stop()

    # If the last block wasn't returned, we'll use the stop frame to check
    if result is None:
        ciphertext = unravel(last_result.message, last_result.substitutions)
        collisions = search_for_collision(ciphertext, ciphertexts_received,
                                          constraints, unif_algo)
        if any_unifiers(collisions):
            return MOOCheckResult(False, collisions, invertible,
                                  length_bound + 1)

    # If we got this far then no unifiers were found
    print("No unifiers found.")
    return MOOCheckResult(False, None, invertible, -1)