反转加密算法,使字符串中的每个字符与另一个字符进行异或,使用奇偶校验来控制偏移量

时间:2015-10-04 00:57:27

标签: python algorithm encryption recursion parity

我已经从我正在调查的挑战二进制文件中推翻了以下算法:

def encrypt(plain):
    l = len(plain)
    a = 10
    cipher = ""

    for i in range(0, l):
        if i + a < l - 1:
            cipher += chr( xor(plain[i], plain[i+a]) )
        else:
            cipher += chr( xor(plain[i], plain[a]) )

        if ord(plain[i]) % 2 == 0: a += 1 # even
        else: a -= 1 # odd

    return cipher

from binascii import hexlify
print hexlify(encrypt("this is a test string"))

基本上,它会将每个字符与字符串中的另一个字符进行异或,偏移aa初始值为10,因为函数会对字符串中的字符进行迭代,a +=1如果字符的值为偶数,则为a -= 1,如果它为&#39} ; s奇怪。

我已经知道如何反转这个密码并检索纯文本,它需要使用递归函数来找出原始字符串中哪些字符偏移是偶数/奇数。 IE:鉴于XOR%2的属性,我们现在认为如果cipher[0]是奇数,则plain[0]plain[10]是奇数,但不是两者。同样,如果cipher[0]为偶数,那么plain[0]plain[10]都是偶数,或者两者都是奇数。从那里,递归算法应该能够完成其余的工作。

一旦我们知道明文中的哪些字符是偶数/奇数,那么逆转其余字符是微不足道的。我花了几个小时来解决这个问题,但现在我无法实施它。

我过去曾使用过基本的递归算法,但从来没有使用任何&#34;分支出来的#34;解决这样的问题。

给定由此函数产生的cipher字符串,我们怎样才能使用递归算法来确定原始普通字符串中每个字符的奇偶校验?

编辑:很抱歉只是为了清楚并回应评论,在对此问题进行了几个小时后,我认为上面提到的递归策略是解决此问题的唯一方法。如果不是,我可以提供解决标题问题的任何提示/帮助。

1 个答案:

答案 0 :(得分:1)

您可以使用所谓的recursive backtracking来解决此问题。做一个假设然后沿着那条路走下去,直到你解密了字符串或者你已经达成了矛盾。当你遇到矛盾时,你会返回失败,并且调用函数会尝试下一个可能性。如果您返回成功,则将成功返回给调用者。

对不起,我无法抗拒试图解决这个问题。这就是我想出的:

# Define constants for even/odd/notset so we can use them in a list of
# assumptions about parity.
even = 0
odd = 1
notset = 2

# Define success and failure so that success and failure can be passed
# as a result.
success = 1
failure = 0

def tryParity(i, cipher, a, parities, parityToSet):
    newParities = list(parities)
    for j, p in parityToSet:
        try:

            if parities[j] == notset:
                newParities[j] = p
            elif parities[j] != p:
                # Failure due to contradiction.
                return failure, []

        except IndexError:
            # If we get an IndexError then this can't be a valid set of values for the parity.
            # Error caused by a bad value for "a".
            return failure, []

    # Update "a" based on parity of i
    new_a = a+1 if newParities[i] == even else a-1

    return findParities(i+1,cipher,new_a,newParities)


def findParities(i, cipher, a, parities):
    # Start returning when you've reached the end of the cipher text.
    # This is when success start bubbling back up through the call stack.
    if i >= len(cipher):
        return success, [parities] # list of parities

    # o stands for the index of the other char that would have been XORed.
    # "o" for "other"
    o = i+a if i + a < len(cipher)-1 else a

    result = None
    resultParities = []
    toTry = []

    # Determine if cipher[index] is even or odd
    if ord(cipher[i]) % 2 == 0:
        # Try both even and both odd
        toTry = (((i,even),(o,even)),
                 ((i,odd),(o,odd)))

    else:
        # Try one or the other even, one or the other odd
        toTry = (((i,odd),(o,even)),
                 ((i,even),(o,odd)))


    # Try first possiblity, if success add parities it came up with to result
    resultA, resultParA = tryParity(i, cipher, a, parities, toTry[0])

    if resultA == success:
        result = success
        resultParities.extend(resultParA)

    # Try second possiblity, if success add parities it came up with to result
    resultB, resultParB = tryParity(i, cipher, a, parities, toTry[1])

    if resultB == success:
        result = success
        resultParities.extend(resultParB)

    return result, resultParities

def decrypt(cipher):
    a = 10
    parities = list([notset for _ in range(len(cipher))])

    # When done, possible parities will contain a list of lists,
    # where the inner lists have the parity of each character in the cipher.
    # Comes back with mutiple results because each 
    result, possibleParities = findParities(0,cipher,a,parities)

    # A print for me to check that the parities that come back match the real parities
    print(possibleParities)
    print(list(map(lambda x: 0 if ord(x) % 2 == 0 else 1, "this is a test string")))

    # Finally, armed with the parities, decrypt the cipher. I'll leave that to you.
    # Maybe more recursion is needed

# test call
decrypt(encrypt("this is a test string"))

它似乎有效,但我没有尝试任何其他输入。

此解决方案只为您提供了奇偶校验,我将字符的解密留给您。他们可能可以一起完成,但我想集中精力回答你提出的问题。我使用的是Python 3,因为它是我安装的。

我也是这个领域的初学者。我推荐阅读Peter Norvig的书。谢谢你提出的棘手问题。