[AFCTF2018]一道有趣的题目

题目源码:

#加密代码
def encrypt(plainText):
    space = 10
    cipherText = ""
    for i in range(len(plainText)):
        if i + space < len(plainText) - 1:
            cipherText += chr(ord(plainText[i]) ^ ord(plainText[i + space]))
        else:
            cipherText += chr(ord(plainText[i]) ^ ord(plainText[space]))
        if ord(plainText[i]) % 2 == 0:
            space += 1
        else:
            space -= 1
    return cipherText
    
# 密码
# 15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206

加密原理是明文自身每个字节依次与自身的某一个字节异或,与谁异或由space决定

第一步要做的就是把space的变化情况爆破出来

space初始为10,后续根据明文的ascii值是否为偶数来决定space加一还是减一

明文字符的ascii值可以根据其二进制的最后一位判断,为0则为偶数,1则为奇数

首先爆破出明文字符串中每个字符的二进制的最后一位

明文和密文长度一样,为28个字符,由每个字符的最后一位组成的字符串也是28,二进制最后一位要么是0要么是1,那么这个由明文每个字符二进制最后一位组成的字符串一共有2的28次方的可能性,爆破:

c='15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206'
c=bytes.fromhex(c)
def crackit():
    '''
    暴力求出每个明文字符的最后一位
    :return: 每个明文字符最后一位组成的字符串
    '''
    for x in range(1<<28):
        temp=bin(x)[2:].zfill(28)
        space = 10
        flag=0
        for i in range(len(temp)):
            if i + space < len(temp) - 1:
                tempx= int(temp[i]) ^ int(temp[i + space])
            else:
                tempx= int(temp[i]) ^ int(temp[space])
            if tempx!=(c[i]%2):
                flag=1
                break
            elif int(temp[i]) % 2 == 0:
                space += 1
            else:
                space -= 1
        if flag!=1:
            print(temp)
            break
#temp='1010011010010101111111101001'

爆破出tmp后,我们可以根据tmp也就是每个明文字符ascii的奇偶性来找到密文字符是由明文对应字符与明文的哪个位置上的字符异或得来的

也就是爆出来space,然后求出来space或者space+i是多少

temp='1010011010010101111111101001'
def crackit_2():
    '''
    解出每个方程中的明文字符的序号.
    :return: 每个方程中的明文字符的序号组成的列表.
    '''
    space = 10
    g=[]
    for i in range(len(temp)):
        if i + space < len(temp) - 1:
            g.append((i,i+space))
        else:
            g.append((i,space))
        if int(temp[i]) % 2 == 0:
            space += 1
        else:
            space -= 1
    return g

最后根据这个列表来还原密文,简单的异或

#加密代码
def encrypt(plainText):
    space = 10
    cipherText = ""
    for i in range(len(plainText)):
        if i + space < len(plainText) - 1:
            cipherText += chr(ord(plainText[i]) ^ ord(plainText[i + space]))
        else:
            cipherText += chr(ord(plainText[i]) ^ ord(plainText[space]))
        if ord(plainText[i]) % 2 == 0:
            space += 1
        else:
            space -= 1
    return cipherText
    
# 密码
# 15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206
c='15120d1a0a0810010a031d3e31000d1d170d173b0d173b0c07060206'
c=bytes.fromhex(c)
def crackit():
    '''
    暴力求出每个明文字符的最后一位
    :return: 每个明文字符最后一位组成的字符串
    '''
    for x in range(1<<28):
        temp=bin(x)[2:].zfill(28)
        space = 10
        flag=0
        for i in range(len(temp)):
            if i + space < len(temp) - 1:
                tempx= int(temp[i]) ^ int(temp[i + space])
            else:
                tempx= int(temp[i]) ^ int(temp[space])
            if tempx!=(c[i]%2):
                flag=1
                break
            elif int(temp[i]) % 2 == 0:
                space += 1
            else:
                space -= 1
        if flag!=1:
            print(temp)
            break
temp='1010011010010101111111101001'
def crackit_2():
    '''
    解出每个方程中的明文字符的序号.
    :return: 每个方程中的明文字符的序号组成的列表.
    '''
    space = 10
    g=[]
    for i in range(len(temp)):
        if i + space < len(temp) - 1:
            g.append((i,i+space))
        else:
            g.append((i,space))
        if int(temp[i]) % 2 == 0:
            space += 1
        else:
            space -= 1
    return g
def solve():
    g=crackit_2()
    plain=['a','f','c','t','f','{']+[-1]*22
    while -1 in plain:
        for i in range(28):
            if plain[g[i][0]]!=-1:
                plain[g[i][1]]=chr(ord(plain[g[i][0]])^c[i])
            elif plain[g[i][1]]!=-1:
                plain[g[i][0]]=chr(ord(plain[g[i][1]])^c[i])
        for i in plain:
            print(i,end='')
        print('\n')

print(crackit_2())

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Paintrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值