逆向常见算法之DES/3DES
2023-8-30 20:47:0 Author: xz.aliyun.com(查看原文) 阅读量:3 收藏

DES

DES(Data Encryption Standard)是一种对称密钥的块加密算法,给定一个 64 位的明文和一个 64 位的密钥(有56位起作用,其他做奇偶效验),输出一个 64 位的密文。这个密文可以用相同的密钥解密。

DES 算法的入口参数有三个:Key、Data、Mode。

Key 为 7 个字节共 56 位,是 DES 算法的工作 密钥
Data 为 8 个字节 64 位,是要被加密或被解密的 数据
Mode 为 DES 的 工作方式,有两种:加密或解密。

算法原理

Feistel

DES 算法是在 Feistel network (费斯妥网络)的基础上执行的。

加密过程

令F 为轮函数 ;令K1,K2....... ,Kn分别为第1.2...n 轮的子密钥。那么基本构造过程如下:
(1)将明文信息均分为两块:L0 R0
(2)在每一轮中,进行如下运算 (i为当前轮数):
Li+1 = Ri Ri+1=Li⊕F(Ri,Ki)
所得的结果即为:(Ri+1,Li+1)

解密过程

对于密文(Rn+1,Ln+1)我们将i由n向0进行,即,i=n.n-1,.....,0。然后对密文进行加密的逆向操作,如下
(1) Ri= Li+1.
(2)L= Ri+1⊕F(Li+1 Ki)
所得结果为(L0,RO)即原来的明文信息

1.子密钥生成

1)置换选择PC1:去除第8位奇偶校验位,将其余56位密钥位打乱重排,前28位C0,后28位D0。

# 选择置换1,输入 key 为长度为 64 的 0/1 数组
# 从64位输入密钥中选择56位,分为左右两个28位半密钥
def PC1(key):
    pc1_l = [57, 49, 41, 33, 25, 17, 9, 
            1, 58, 50, 42, 34, 26, 18, 
            10, 2, 59, 51, 43, 35, 27, 
            19, 11, 3, 60, 52, 44, 36]
    pc1_r = [63, 55, 47, 39, 31, 23, 15, 
            7, 62, 54, 46, 38, 30, 22, 
            14, 6, 61, 53, 45, 37, 29, 
            21, 13, 5, 28, 20, 12, 4]

    return [key[x-1] for x in pc1_l], [key[x-1] for x in pc1_r]

2)循环左移:将Ci-1和Di-1进行循环左移变化得到Ci和Di,位数不变。

# 循环左移off位
def leftRotate(a, off):
    return a[off:] + a[:off]

assert leftRotate([0, 1, 0, 1, 1], 2) == [0, 1, 1, 0, 1]

# 子密钥生成算法,由一个64位主密钥导出16个48位子密钥
def keyGen(key):
    assert len(key) == 64

    l, r = PC1(key)
    off = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
    res = []

    for x in range(16):
        l = leftRotate(l, off[x])
        r = leftRotate(r, off[x])

        res.append(PC2(l + r))

    return res

3)置换选择PC2:将Ci与Di合成56位中间数据,并从56位中间数据中选择一个48位的子密钥Ki(i:1~16)。这个过程中,既置换了每位的顺序,又获得了子密钥Ki,因此也可以称为压缩置换。

# 选择置换2
# 从56位的密钥中选取48位子密钥
def PC2(key):
    assert len(key) == 56

    pc2 = [14, 17, 11, 24, 1, 5, 
            3, 28, 15, 6, 21, 10,
            23, 19, 12, 4, 26, 8,
            16, 7, 27, 20, 13, 2,
            41, 52, 31, 37, 47, 55,
            30, 40, 51, 45, 33, 48,
            44, 49, 39, 56, 34, 53,
            46, 42, 50, 36, 29, 32]
    return [key[x-1] for x in pc2]

4)循环2、3过程,直至生成16个48位的子密钥。

2. 迭代加密

框架

def DES(plain, key, method):
    subkeys = keyGen(int2bin(key, 64))

    if method == 'decrypt':
        subkeys = subkeys[::-1]

    m = IP(int2bin(plain, 64))

    l, r = np.array(m, dtype=int).reshape(2, -1).tolist()

    for i in range(16):
        l, r = goRound(l, r, subkeys[i])

    return bin2int(FP(r + l))

1)初始置换IP,目的是将输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长32位,置换规则如下表所示:

# 初始置换
def IP(a):
    ip = [58, 50, 42, 34, 26, 18, 10, 2,
            60, 52, 44, 36, 28, 20, 12, 4,
            62, 54, 46, 38, 30, 22, 14, 6,
            64, 56, 48, 40, 32, 24, 16, 8,
            57, 49, 41, 33, 25, 17, 9, 1,
            59, 51, 43, 35, 27, 19, 11, 3,
            61, 53, 45, 37, 29, 21, 13, 5,
            63, 55, 47, 39, 31, 23, 15, 7]
    return [a[x-1] for x in ip]
testM = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1]
assert IP(testM) == [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0]

2)16轮feistel结构迭代(轮函数F)

Feistel加密过程:

1. 先对其进行扩展置换,使其变为 48 位的数据,
2. 然后生成的数据再与子密钥进行异或运算,得到一组新的 48 位数据
3. 再以异或运算后的 48 位数据进行 S 盒代替,将 48 位的数据,转换为 32 位的数据,
4. 再进行 P 盒置换,生成 32 位的数据
5. 最后将 P 盒置换生成的数据与本轮运算时输入的 L 进行异或运算,生成新的 R。
6. 而新的 L 是直接由本轮的 R 进行替换

a.选择运算E(也称扩展置换):将Ri-1(即输入A)扩展从32位扩展为48位,32位->48位

通过扩展置换E,数据的右半部分Ri-1从32位扩展到48位。扩展置换改变了位的次序,重复了某些位。

作用:产生与秘钥相同长度的数据以进行异或运算,R0是32位,子秘钥是48位,所以R0要先进行扩展置换之后与子秘钥进行异或运算;提供更长的结果,使得在替代运算时能够进行压缩。

b.密钥异或:48位中间结果与48位子密钥按位异或;引入密钥。

def goRound(l, r, subKey):
    return r, binXor(l, Feistel(r, subKey))

# F函数,用于处理一个半块
def Feistel(a, subKey):
    assert len(a) == 32
    assert len(subKey) == 48

    t = binXor(Expand(a), subKey)
    t = S(t)
    t = P(t)

    return t

c.S盒代换:8个S盒,每个6位输入,4位输出,混淆作用,48位->32位

# 扩张置换,将32位的数据扩展到48位
def Expand(a):
    assert len(a) == 32
    e = [32, 1, 2, 3, 4, 5,
        4, 5, 6, 7, 8, 9,
        8, 9, 10, 11, 12, 13,
        12, 13, 14, 15, 16, 17,
        16, 17, 18, 19, 20, 21,
        20, 21, 22, 23, 24, 25,
        24, 25, 26, 27, 28, 29,
        28, 29, 30, 31, 32, 1]
    return [a[x-1] for x in e]

# S盒变换,输入48位,输出32位
def S(a):
    assert len(a) == 48

    S_box = [[14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
                0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
                4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
                15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13], 
                [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
                3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
                0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
                13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9], 
                [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
                13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
                13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
                1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12],
                [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
                13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
                10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
                3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14],
                [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
                14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
                4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
                11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3],
                [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
                10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
                9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
                4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13],
                [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
                13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
                1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
                6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12],
                [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,
                1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
                7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,
                2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]]

    a = np.array(a, dtype=int).reshape(8, 6)
    res = []

    for i in range(8):
        # 用 S_box[i] 处理6位a[i],得到4位输出
        p = a[i]
        r = S_box[i][bin2int([p[0], p[5], p[1], p[2], p[3], p[4]])]
        res.append(int2bin(r, 4))

    res = np.array(res).flatten().tolist()
    assert len(res) == 32

    return res

Rn扩展置换之后与子秘钥Kn异或以后的结果作为输入块,功能是把48位数据压缩为32位数据,由8个不同的代替盒(S盒)完成。每个S盒有6位输入,4位输出。48位的输入块被分成8个6位的分组,每一个分组对应一个S盒代替操作。经过S盒代替,得到8个4位分组结果—32位。

注:每一个S-盒的输入数据是6位,输出数据是4位,但是每个S盒自身是64位!!

d.置换P:将S盒输出的32位数据打乱重排,扩散作用,32位->32位;结果为一轮f函数输出

# P置换
def P(a):
    assert len(a) == 32

    p = [16, 7, 20, 21,
        29, 12, 28, 17,
        1, 15, 23, 26,
        5, 18, 31, 10,
        2, 8, 24, 14,
        32, 27, 3, 9,
        19, 13, 30, 6,
        22, 11, 4, 25]
    return [a[x-1] for x in p]

异或:置换P输出与Ln-1异或得到Rn,一轮Feistle结构结束。由此,Ri、Li根据Ri-1、Li-1计算得出,并作为新一轮计算的输入。新一轮轮函数:扩展置换E->密钥异或->S盒运算->置换P->异或;总计16轮结束,最终生成L16和R16。

注:最后一轮的左右两部分不交换也不再运算,而是直接合并在一起R16L16,作为逆初始置换(FP置换)的输入块。

3)FP置换:初始置换IP的逆置换

# 最终置换
def FP(a):
    fp = [40, 8, 48, 16, 56, 24, 64, 32,
            39, 7, 47, 15, 55, 23, 63, 31,
            38, 6, 46, 14, 54, 22, 62, 30,
            37, 5, 45, 13, 53, 21, 61, 29,
            36, 4, 44, 12, 52, 20, 60, 28,
            35, 3, 43, 11, 51, 19, 59, 27,
            34, 2, 42, 10, 50, 18, 58, 26,
            33, 1, 41, 9, 49, 17, 57, 25]
    return [a[x-1] for x in fp]

3.解密过程

加密和解密可以使用相同的算法。加密和解密唯一不同的是秘钥的次序是相反的。为每一轮产生秘钥的算法也是循环的。加密是秘钥循环左移,解密是秘钥循环右移。解密秘钥每次移动的位数是:0、1、2、2、2、2、2、2、1、2、2、2、2、2、2、1。

程序实现

贴一下代码,方便查询和对比

python

from functools import reduce
import numpy as np

# 整数转二进制数组,指定位长 n,大端序
def int2bin(a, n):
    assert 0<=n and a < 2**n
    res = np.zeros(n, dtype = int)

    for x in range(n):
        res[n-x-1] = a % 2
        a = a // 2
    return res.tolist()

assert int2bin(0x1a, 10) == [0, 0, 0, 0, 0, 1, 1, 0, 1, 0]

# 二进制数组转整数,大端序
def bin2int(a):
    return reduce(lambda x,y: x*2+y, a)

assert bin2int([0, 0, 0, 0, 0, 1, 1, 0, 1, 0]) == 0x1a

# 循环左移off位
def leftRotate(a, off):
    return a[off:] + a[:off]

assert leftRotate([0, 1, 0, 1, 1], 2) == [0, 1, 1, 0, 1]

# 异或
def binXor(a, b):
    assert len(a) == len(b)
    return [x^y for x, y in zip(a, b)]
assert binXor([1, 1, 0, 1], [0, 1, 1, 0]) == [1, 0, 1, 1]

# 初始置换
def IP(a):
    ip = [58, 50, 42, 34, 26, 18, 10, 2,
            60, 52, 44, 36, 28, 20, 12, 4,
            62, 54, 46, 38, 30, 22, 14, 6,
            64, 56, 48, 40, 32, 24, 16, 8,
            57, 49, 41, 33, 25, 17, 9, 1,
            59, 51, 43, 35, 27, 19, 11, 3,
            61, 53, 45, 37, 29, 21, 13, 5,
            63, 55, 47, 39, 31, 23, 15, 7]
    return [a[x-1] for x in ip]
testM = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1]
assert IP(testM) == [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0]

# 最终置换
def FP(a):
    fp = [40, 8, 48, 16, 56, 24, 64, 32,
            39, 7, 47, 15, 55, 23, 63, 31,
            38, 6, 46, 14, 54, 22, 62, 30,
            37, 5, 45, 13, 53, 21, 61, 29,
            36, 4, 44, 12, 52, 20, 60, 28,
            35, 3, 43, 11, 51, 19, 59, 27,
            34, 2, 42, 10, 50, 18, 58, 26,
            33, 1, 41, 9, 49, 17, 57, 25]
    return [a[x-1] for x in fp]

# 选择置换1
# 从64位输入密钥中选择56位,分为左右两个28位半密钥
def PC1(key):
    pc1_l = [57, 49, 41, 33, 25, 17, 9, 
            1, 58, 50, 42, 34, 26, 18, 
            10, 2, 59, 51, 43, 35, 27, 
            19, 11, 3, 60, 52, 44, 36]
    pc1_r = [63, 55, 47, 39, 31, 23, 15, 
            7, 62, 54, 46, 38, 30, 22, 
            14, 6, 61, 53, 45, 37, 29, 
            21, 13, 5, 28, 20, 12, 4]

    return [key[x-1] for x in pc1_l], [key[x-1] for x in pc1_r]

testKey = [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1]
testL, testR = PC1(testKey)
assert testL + testR == [1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1]

# 选择置换2
# 从56位的密钥中选取48位子密钥
def PC2(key):
    assert len(key) == 56

    pc2 = [14, 17, 11, 24, 1, 5, 
            3, 28, 15, 6, 21, 10,
            23, 19, 12, 4, 26, 8,
            16, 7, 27, 20, 13, 2,
            41, 52, 31, 37, 47, 55,
            30, 40, 51, 45, 33, 48,
            44, 49, 39, 56, 34, 53,
            46, 42, 50, 36, 29, 32]
    return [key[x-1] for x in pc2]

# 子密钥生成算法,由一个64位主密钥导出16个48位子密钥
def keyGen(key):
    assert len(key) == 64

    l, r = PC1(key)
    off = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
    res = []

    for x in range(16):
        l = leftRotate(l, off[x])
        r = leftRotate(r, off[x])

        res.append(PC2(l + r))

    return res

assert keyGen(testKey)[-1] == [1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1]

# S盒变换,输入48位,输出32位
def S(a):
    assert len(a) == 48

    S_box = [[14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
                0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
                4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
                15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13], 
                [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
                3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
                0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
                13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9], 
                [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
                13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
                13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
                1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12],
                [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
                13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
                10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
                3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14],
                [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
                14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
                4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
                11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3],
                [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
                10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
                9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
                4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13],
                [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
                13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
                1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
                6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12],
                [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,
                1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
                7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,
                2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]]

    a = np.array(a, dtype=int).reshape(8, 6)
    res = []

    for i in range(8):
        # 用 S_box[i] 处理6位a[i],得到4位输出
        p = a[i]
        r = S_box[i][bin2int([p[0], p[5], p[1], p[2], p[3], p[4]])]
        res.append(int2bin(r, 4))

    res = np.array(res).flatten().tolist()
    assert len(res) == 32

    return res

# 扩张置换,将32位的半块扩展到48位
def Expand(a):
    assert len(a) == 32
    e = [32, 1, 2, 3, 4, 5,
        4, 5, 6, 7, 8, 9,
        8, 9, 10, 11, 12, 13,
        12, 13, 14, 15, 16, 17,
        16, 17, 18, 19, 20, 21,
        20, 21, 22, 23, 24, 25,
        24, 25, 26, 27, 28, 29,
        28, 29, 30, 31, 32, 1]
    return [a[x-1] for x in e]

# P置换
def P(a):
    assert len(a) == 32

    p = [16, 7, 20, 21,
        29, 12, 28, 17,
        1, 15, 23, 26,
        5, 18, 31, 10,
        2, 8, 24, 14,
        32, 27, 3, 9,
        19, 13, 30, 6,
        22, 11, 4, 25]
    return [a[x-1] for x in p]

# F函数,用于处理一个半块
def Feistel(a, subKey):
    assert len(a) == 32
    assert len(subKey) == 48

    t = binXor(Expand(a), subKey)
    t = S(t)
    t = P(t)

    return t

def goRound(l, r, subKey):
    return r, binXor(l, Feistel(r, subKey))

def DES(plain, key, method):
    subkeys = keyGen(int2bin(key, 64))

    if method == 'decrypt':
        subkeys = subkeys[::-1]

    m = IP(int2bin(plain, 64))

    l, r = np.array(m, dtype=int).reshape(2, -1).tolist()

    for i in range(16):
        l, r = goRound(l, r, subkeys[i])

    return bin2int(FP(r + l))

print(hex(DES(0x11aabbccddeeff01, 0xcafababedeadbeaf, 'encrypt')))
# 0x2973a7e54ec730a3
print(hex(DES(0x2973a7e54ec730a3, 0xcafababedeadbeaf, 'decrypt')))
# 0x11aabbccddeeff01

c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/*------------------------
     定义枚举型全局变量
------------------------*/
typedef enum
{
    false = 0,
    true = 1
} bool;

// 十六轮子密钥
static bool SubKey[16][48] = {0};

/*---------------------*/
/*-------------------------------------------------------------
     各种置换表
-------------------------------------------------------------*/
// IP置换表
const char IP_Table[64] = {
 58,50,42,34,26,18,10, 2,60,52,44,36,28,20,12, 4,
 62,54,46,38,30,22,14, 6,64,56,48,40,32,24,16, 8,
 57,49,41,33,25,17, 9, 1,59,51,43,35,27,19,11, 3,
 61,53,45,37,29,21,13, 5,63,55,47,39,31,23,15, 7
};
// IP-1置换表
const char IPR_Table[64] = {
 40, 8,48,16,56,24,64,32,39, 7,47,15,55,23,63,31,
 38, 6,46,14,54,22,62,30,37, 5,45,13,53,21,61,29,
 36, 4,44,12,52,20,60,28,35, 3,43,11,51,19,59,27,
 34, 2,42,10,50,18,58,26,33, 1,41, 9,49,17,57,25
};

// E扩展表
static char E_Table[48] = {
 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
  8, 9,10,11,12,13,12,13,14,15,16,17,
    16,17,18,19,20,21,20,21,22,23,24,25,
    24,25,26,27,28,29,28,29,30,31,32, 1
};
// PC1置换表
static char PC1_Table[56] = {
 57,49,41,33,25,17, 9, 1,58,50,42,34,26,18,
 10, 2,59,51,43,35,27,19,11, 3,60,52,44,36,
 63,55,47,39,31,23,15, 7,62,54,46,38,30,22,
 14, 6,61,53,45,37,29,21,13, 5,28,20,12, 4
};

// pc2表
static char PC2_Table[48] = {
 14,17,11,24, 1, 5, 3,28,15, 6,21,10,
 23,19,12, 4,26, 8,16, 7,27,20,13, 2,
 41,52,31,37,47,55,30,40,51,34,33,48,
 44,49,39,56,34,53,46,42,50,36,29,32
};
//  移位表
static char Move_Table[16] = {
  1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
// S盒
static char S_Box[8][4][16] = {
    //S1
    14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
     0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
     4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
    15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,
    //S2
    15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
     3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
     0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
    13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,
    //S3
    10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
    13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
    13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
     1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,
     //S4
      7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
     13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
     10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
      3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,
      //S5
       2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
      14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
       4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
      11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,
      //S6
      12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
      10,15, 4, 2, 7,12, 0, 5, 6, 1,13,14, 0,11, 3, 8,
       9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
          4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,
          //S7
           4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
          13, 0,11, 7, 4, 0, 1,10,14, 3, 5,12, 2,15, 8, 6,
           1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
           6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,
           //S8
           13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
            1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
            7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
            2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11
};
//P置换表
static char P_Table[32] = {
 16, 7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10,
  2, 8,24,14,32,27, 3, 9,19,13,30, 6,22,11, 4,25
};
/*-------------------------------------------------------------------*/

/*-----------------------------自定义函数-----------------------------*/
void SetKey(char My_key[8]); //生成16轮的子密钥;
void ByteToBit(bool* Data_out, char* Data_in, int Num); //字节转换成位;
void Change_bit(bool* Data_out, int Num);//二进制的位置进行转换;
void BitToByte(char My_message[8], bool* Message_in, int Num); //位转换成字节;
void TableReplace(bool* Data_out, bool* Data_in, const char* Table, int Num);  //各种表的置换算法;
void Bitcopy(bool* Data_out, bool* Data_in, int Num);  //二进制数组的拷贝
void Loop_bit(bool* Data_out, int movstep, int len);  //左移位;
void Run_Des(char My_message[8], char HexMssage[16]);//des的轮加密算法
void Xor(bool* Message_out, bool* Message_in, int Num); //执行异或
void S_change(bool* Data_out, bool* Data_in);  // S盒变换;
void HexToBit(bool* Data_out, char* Data_in, int Num); // 十六进制转二进制
void BitToHex(char* Data_out, bool* Data_in, int Num); //二进制转换成十六进制;
void Run_desDes(char My_message[8], char HexMessage[16]);// DES轮解密算法;

/*--------------------------*/

/*--------------------------主函数----------------------------------*/
int main()
{
    int i = 0, j;
    char My_key[8] = {0};  //记录加密密钥;
    char You_key[8] = {0}; //解密密钥
    char My_message[8] = {0}; //明文
    char Message_hex[16] = {0};//16进制的密文
    printf("请输入你要加密的内容(8 Byte):\n");
    gets(My_message);
    printf("请输入你的加密密钥:\n");
    gets(My_key);
    i = strlen(My_key);
    while(i != 8)
    {
        printf("请输入加密密钥(8 Byte)\n");
        gets(My_key);
        i = 0;
        i = strlen(My_key);
    }
    SetKey(My_key);  //生成16轮的加密子密钥;
    Run_Des(My_message, Message_hex); //des的轮加密过程
    printf("经过加密的密文为:\n");
    for(i = 0; i < 16; i++)
    {
        printf("%c ", Message_hex[i]);
    }
    printf("\n");
    printf("请输入你的解密密钥(8 Byte):\n");
    gets(You_key);
    i = strlen(You_key);
    while(i != 8)
    {
        printf("请输入解密密钥(8 Byte)\n");
        gets(You_key);
        i = 0;
        i = strlen(You_key);
    }
    SetKey(You_key);  //生成16轮的解密子密钥;
    Run_desDes(My_message, Message_hex);//解密;
    printf("解密结果为:\n");
    for(i = 0; i < 8; i++)
    {
        printf("%c ", My_message[i]);
    }
    printf("\n");
    return 0;
}

/*--------------------具体函数定义----------------------*/
void Bitcopy(bool* Data_out, bool* Data_in, int Num) //二进制数组拷贝
{
    int i = 0;
    for(i = 0; i < Num; i++)
    {
        Data_out[i] = Data_in[i];
    }

}
void Change_bit(bool* Data_out, int Num) //二进制的位置进行转换;
{
    int i, j;
    static bool Temp[8] = {0};
    for(i = 0; i < Num / 8; i++)
    {
        Bitcopy(Temp, Data_out, Num / 8);
        for(j = 0; j < Num / 8; j++)
        {
            Data_out[j] = Temp[Num / 8 - 1 - j];
        }
        Data_out += Num / 8;
    }
}
void ByteToBit(bool* Data_out, char* Data_in, int Num) //字节转位
{
    int i, j;
    for(i = 0; i < Num; i++)
    {
        Data_out[i] = (Data_in[i / 8] >> (i % 8)) & 0x01;
    }
    //Change_bit(Data_out,Num);
}
void BitToHex(char* Data_out, bool* Data_in, int Num) //二进制转十六进制
{
    int i;
    for(i = 0; i < Num / 4; i++)
    {
        Data_out[i] = 0;
    }
    for(i = 0; i < Num / 4; i++)
    {
        Data_out[i] = Data_in[4 * i] + Data_in[4 * i + 1] * 2 + Data_in[4 * i + 2] * 4 + Data_in[4 * i + 3] * 8;
        if(Data_out[i] % 16 > 9)
        {
            Data_out[i] = Data_out[i] % 16 + '7';
        }
        else
            Data_out[i] = Data_out[i] % 16 + '0';
    }
}
void HexToBit(bool* Data_out, char* Data_in, int Num) //十六进制转二进制
{
    int i;
    for(i = 0; i < Num; i++)
    {
        if(Data_in[i / 4] <= '9')
        {
            Data_out[i] = ((Data_in[i / 4] - '0') >> (i % 4)) & 0x01;
        }
        else
        {
            Data_out[i] = ((Data_in[i / 4] - '7') >> (i % 4)) & 0x01;
        }
    }
}
void BitToByte(char My_message[8], bool* Message_in, int Num) //位转换成字节
{
    int i = 0;
    for(i = 0; i < (Num / 8); i++)
    {
        My_message[i] = 0;
    }
    for(i = 0; i < Num; i++)
    {
        My_message[i / 8] |= Message_in[i] << (i % 8);
    }
}
void TableReplace(bool* Data_out, bool* Data_in, const char* Table, int Num) // 置换算法
{
    int i = 0;
    static bool Temp[256] = {0};
    for(i = 0; i < Num; i++)
    {
        Temp[i] = Data_in[Table[i] - 1];
    }
    Bitcopy(Data_out, Temp, Num);
}
void Loop_bit(bool* Data_out, int movstep, int len)
{
    static bool Temp[256] = {0};
    Bitcopy(Temp, Data_out, movstep);
    Bitcopy(Data_out, Data_out + movstep, len - movstep);
    Bitcopy(Data_out + len - movstep, Temp, movstep);
    /*Temp=Data_out;
    Temp[movstep]='\0';
    Data_out=Data_out+movstep;
    Data_out+(len-movstep)=Temp;*/
}
void Xor(bool* Message_out, bool* Message_in, int Num)//执行异或
{
    int i;
    for(i = 0; i < Num; i++)
    {
        Message_out[i] = Message_out[i] ^ Message_in[i];
    }
}
void SetKey(char My_key[8])
{
    int i, j;
    static bool Key_bit[64] = {0}; //Key的二进制缓存;
    static bool* Key_bit_L, * Key_bit_R;
    Key_bit_L = &Key_bit[0]; //key的左边28位;
    Key_bit_R = &Key_bit[28]; //key的右边28位;
    ByteToBit(Key_bit, My_key, 64);
    /* Change_bit(Key_bit,64) ;//二进制的位置进行转换;
     for(i=0;i<64;i++)
     {
      printf("%d ",Key_bit[i]);
     }
     printf("\n");
     printf("\n");*/
    TableReplace(Key_bit, Key_bit, PC1_Table, 56);//pc-1 置换
    for(i = 0; i < 16; i++)
    {
        Loop_bit(Key_bit_L, Move_Table[i], 28);
        Loop_bit(Key_bit_R, Move_Table[i], 28);
        TableReplace(SubKey[i], Key_bit, PC2_Table, 48);//pc-2置换
    }
}
void S_change(bool* Data_out, bool* Data_in) //S盒变换
{
    int i;
    int r = 0, c = 0;//S盒的行和列;
    for(i = 0; i < 8; i++, Data_in = Data_in + 6, Data_out = Data_out + 4)
    {
        r = Data_in[0] * 2 + Data_in[5] * 1;
        c = Data_in[1] * 8 + Data_in[2] * 4 + Data_in[3] * 2 + Data_in[4] * 1;
        ByteToBit(Data_out, &S_Box[i][r][c], 4);
    }
}
void F_change(bool Data_out[32], bool Data_in[48])   // f函数;
{
    int i;
    static bool Message_E[48] = {0};  //存放E置换的结果;
    TableReplace(Message_E, Data_out, E_Table, 48);//E表置换
    Xor(Message_E, Data_in, 48);
    S_change(Data_out, Message_E);                 // S盒变换
    TableReplace(Data_out, Data_out, P_Table, 32);  //P置换
}
void Run_Des(char My_message[8], char HexMssage[16])//des轮加密算法;
{
    int i;
    static bool Message_bit[64] = {0};
    static bool* Message_bit_L = &Message_bit[0], * Message_bit_R = &Message_bit[32];
    static bool Temp[32] = {0};
    ByteToBit(Message_bit, My_message, 64);
    /*Change_bit(Message_bit,64) ;//二进制的位置进行转换;
    for(i=0;i<64;i++)
    {
     printf("%d ",Message_bit[i]);
    }
    printf("\n");
    printf("\n");*/
    TableReplace(Message_bit, Message_bit, IP_Table, 64);
    for(i = 0; i < 16; i++)
    {
        Bitcopy(Temp, Message_bit_R, 32);
        F_change(Message_bit_R, SubKey[i]);
        Xor(Message_bit_R, Message_bit_L, 32);
        Bitcopy(Message_bit_L, Temp, 32);
    }
    TableReplace(Message_bit, Message_bit, IPR_Table, 64);
    BitToHex(HexMssage, Message_bit, 64);//二进制转换成十六进制;
}
void Run_desDes(char My_message[8], char HexMessage[16])// DES轮解密算法;
{
    int i = 0;
    static bool Message_bit[64] = {0};
    static bool* Message_bit_L = &Message_bit[0], * Message_bit_R = &Message_bit[32];
    static bool Temp[32] = {0};
    HexToBit(Message_bit, HexMessage, 64);
    TableReplace(Message_bit, Message_bit, IP_Table, 64);
    for(i = 15; i >= 0; i--)
    {
        Bitcopy(Temp, Message_bit_L, 32);
        F_change(Message_bit_L, SubKey[i]);
        Xor(Message_bit_L, Message_bit_R, 32);
        Bitcopy(Message_bit_R, Temp, 32);
    }
    TableReplace(Message_bit, Message_bit, IPR_Table, 64);
    BitToByte(My_message, Message_bit, 64);
}

题目练习

[羊城杯 2020]babyre

64位elf文件

findcrypt发现有aes

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int i; // [rsp+0h] [rbp-140h]
  char v5[16]; // [rsp+A0h] [rbp-A0h] BYREF
  char s[64]; // [rsp+B0h] [rbp-90h] BYREF
  char v7[72]; // [rsp+F0h] [rbp-50h] BYREF
  unsigned __int64 v8; // [rsp+138h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  sub_402563();
  __isoc99_scanf("%39s", s);
  if ( (unsigned int)strlen(s) != 16 )
  {
    puts("Wrong!");
    exit(0);
  }
  DES_string_to_key();
  if ( !(unsigned int)DES_set_key_checked() )
  {
    memset(v5, 0, 8uLL);
    DES_ncbc_encrypt();
    for ( i = 0; i <= 15; ++i )
    {
      if ( v7[i] != byte_6040C0[i] )
        puts("wrong!");
    }
    if ( (*(unsigned int (__fastcall **)(char *, char *))byte_40272D)(s, v7) )
      puts("Correct!");
    else
      puts("Wrong!");
    exit(0);
  }
  puts("convert to key_schedule failed.");
  return 0xFFFFFFFFLL;
}

main函数里有des,byte_40272D是经过sub_402563smc的代码

先动调出sub_40272D。这里使用了openssl的动态加密算法库,需要在本地也安装上

wget https://www.openssl.org/source/openssl-1.0.0.tar.gz

#解压
tar -vxzf openssl-1.0.0.tar.gz

cd openssl-1.0.0
mkdir build

#创建版本信息文件(内容在下一步),无此文件链接时会报找不到版本信息
vim openssl.ld

#进入vim输入
OPENSSL_1.0.0 {
  global:
  *;
};

OPENSSL_1.0.1 {
  new*;
}OPENSSL_1.0.0;

OPENSSL_1.0.1p {
  new*;
}OPENSSL_1.0.0;
#esc    :wq

#配置
./config no-asm shared -Wl,--version-script=openssl.ld --prefix=./build

#编译
make -j`nproc`

sudo cp libcrypto.so.1.0.0 /usr/lib/

环境配置好后开始动调

在 sub_402563(a1, a2, a3);处打一个断点,F4运行到这,再向下一步,byte_40272D就解密了

点进去c强制分析,在开头p生成函数

void __fastcall __noreturn sub_40272D(__int64 a1)
{
  int i; // [rsp+18h] [rbp-128h]
  int j; // [rsp+1Ch] [rbp-124h]
  int k; // [rsp+24h] [rbp-11Ch]
  int m; // [rsp+28h] [rbp-118h]
  char v5[192]; // [rsp+30h] [rbp-110h] BYREF
  char s[16]; // [rsp+F0h] [rbp-50h] BYREF
  _BYTE v7[56]; // [rsp+100h] [rbp-40h] BYREF
  unsigned __int64 v8; // [rsp+138h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  __isoc99_scanf("%40s", s);
  if ( (unsigned int)strlen(s) != 32 )
  {
    puts("Wrong!");
    exit(0);
  }
  sub_400C91(v5, a1);
  sub_401B8E(v5, s);
  sub_401B8E(v5, v7);
  for ( i = 0; i <= 31; ++i )
  {
    for ( j = 0; i / 4 > j; ++j )
      s[i] ^= s[j];
  }
  for ( k = 1; k <= 31; ++k )
    byte_6040D0[k - 1] = (2 * (s[k - 1] ^ 0x13) + 7) ^ ((unsigned __int8)s[k - 1] % 9u + s[k] + 2);
  if ( v7[15] == 0xC4 )
  {
    for ( m = 0; m <= 30; ++m )
      ;
  }
}

其中 sub_400C91(v5, a1); sub_401B8E(v5, s); sub_401B8E(v5, v7);是AES加密

所以总体的逻辑就是先进行des加密,正确后进入sub_40272D,des的结果作为key,再输入并进行aes加密

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+0h] [rbp-140h]
  char v5[128]; // [rsp+10h] [rbp-130h] BYREF
  char v6[16]; // [rsp+90h] [rbp-B0h] BYREF
  char v7[16]; // [rsp+A0h] [rbp-A0h] BYREF
  char s[64]; // [rsp+B0h] [rbp-90h] BYREF
  char v9[72]; // [rsp+F0h] [rbp-50h] BYREF
  unsigned __int64 v10; // [rsp+138h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  sub_402563(argc, argv, envp);
  __isoc99_scanf("%39s", s);
  if ( (unsigned int)strlen(s) != 16 )
  {
    puts("Wrong!");
    exit(0);
  }
  DES_string_to_key("this is my key", v6);
  if ( !(unsigned int)DES_set_key_checked(v6, v5) )
  {
    memset(v7, 0, 8uLL);
    DES_ncbc_encrypt(s, v9, 60LL, v5, v7, 1LL);
    for ( i = 0; i <= 15; ++i )
    {
      if ( v9[i] != byte_6040C0[i] )
        puts("wrong!");
    }
    sub_40272D((__int64)s);
  }
  puts("convert to key_schedule failed.");
  return -1;
}

先来des:

des的key并不是所给的字符串'this is my key',而是经过一些汇编代码处理字符串得到的。在scanf处下一个断点,之后F7过检测,让程序运行到下一个if结构中。这时v6中的也不是key,在汇编界面找到对应的寄存器中才是正确的key

des的密文就是byte_6040C0 = [0x0A, 0xF4, 0xEE, 0xC8, 0x42, 0x8A, 0x9B, 0xDB, 0xA2, 0x26, 0x6F, 0xEE, 0xEE, 0xE0, 0xD8, 0xA2]

分别用ECB模式和CBC模式解DES,两次解密结果的拼接即为第一次正确的输入

from Crypto.Cipher import DES
key=b'\xAD\x52\xF2\x4C\xE3\x2C\x20\xD6'
des_ecb=DES.new(key,DES.MODE_ECB)
des_cbc=DES.new(key,DES.MODE_CBC,key)
cipher=b'\x0A\xF4\xEE\xC8\x42\x8A\x9B\xDB\xA2\x26\x6F\xEE\xEE\xE0\xD8\xA2'
m1=des_ecb.decrypt(cipher)
m2=des_cbc.decrypt(cipher)
print(m1)
print(m2)

#th1s1sth3n1c3k3y

接下来进入aes:

input在传入后先经过aes,之后经过异或等处理,key已知,但是找不着enc了。。

再次查看汇编,在enc在两段有反编译的代码中间,byte_604100 = [ 0xBD, 0xAD, 0xB4, 0x84, 0x10, 0x63, 0xB3, 0xE1, 0xC6, 0x84,0x2D, 0x6F, 0xBA, 0x88, 0x74, 0xC4, 0x90, 0x32, 0xEA, 0x2E, 0xC6, 0x28, 0x65, 0x70, 0xC9, 0x75, 0x78, 0xA0, 0x0B, 0x9F, 0xA6, 0x00, 0x30, 0xE4, 0xD2, 0xC3, 0xEF, 0x75, 0xED, 0xA8, 0xE1, 0xA1, 0x73, 0x81, 0xE2, 0xE9, 0xAB, 0xC8, 0xBF, 0xCA, 0x52, 0xE8, 0xED, 0x6B, 0xA2, 0x39, 0x86, 0x21, 0xD0, 0xF6, 0x50, 0x3E, 0xF3, 0x5C]

在函数最后提示了 if ( v7[15] == 0xC4 )

res = "BDADB4841063B3E1C6842D6FBA8874C49032EA2EC6286570C97578A00B9FA6"
res = bytearray.fromhex(res)
aes_key = b'th1s1sth3n1c3k3y'
flag = [0] * 32
flag[31] = 0xc4
flags = []

def deep_search(flag, deep):
    if deep == 0:
        flags.append(flag.copy())
    else:
        for i in range(0xff):
            if ((2 * (i ^ 0x13) + 7) ^ (i % 9 + flag[deep] + 2)) & 0xff == res[deep-1]:
                flag[deep-1] = i
                deep_search(flag, deep-1)

deep_search(flag, 31)
print(flags, "\nfind solver number is: ", len(flags))


for flag in flags:
    for i in range(31, -1, -1):
        for j in range(int(i/4)):
            flag[i] ^= flag[j]
    res = AES.new(aes_key, AES.MODE_ECB).decrypt(bytes(flag))
    print(res)

GWHT{th1s_gam3_1s_s0_c00l_and_d}

3DES

随着计算机算力的增长,DES加密56位的秘钥容易受到穷举攻击。因此,3DES作为替换升级的方案应运而生。

算法原理

加密

3DES(DESede , TripleDES)也是三重DES,是为了增加DES的强度,将DES重复3次所得到的一种加密算法。

三重DES的密钥长度为3cheng56=168 bit,进行加密-解密-加密的过程,设Ek()和Dk()分别代表DES算法的加密和解密过程,k代表DES算法使用的秘钥,M代表明文,C代表密文,则3DES加密为:C = Ek3(Dk2(Ek2(Dk1(C))))

可以使秘钥k1 = k3 ,即使用两个有效的秘钥,以降低对计算机算力的要求(DES_EDE2)

当三重DES中所有密钥都相同时,三重DES就等于普通的DES了,这样3DES就与DES兼容了

解密

解密过程和加密过程正好相反,以密钥3-密钥2-密钥1的顺序执行解密-加密-解密的操作

程序实现

c

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <memory.h>
using namespace std;

typedef bool
(*PSubKey)[16][48];

// 初始置换
const static char Table_IP[64] =
{
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};

// 末置换
const static char Table_InverseIP[64] =
{
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25
};

// 扩展置换
static const char Table_E[48] =
{
32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
};

// 密钥初始置换
const static char Table_PC1[56] = {
57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
};

// 左移运算
const static char Table_Moveleft[16] =
{
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};

// 密钥压缩置换
const static char Table_PC2[48] =
{
14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};

// S盒
const static char Box_S[8][4][16] =
{
// S1
14, 4, 13, 1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,
// S2
15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,
// S3
10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,
// S4
7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,
// S5
2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,
// S6
12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,
// S7
4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,
// S8
13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};

// P盒置换
const static char Table_P[32] =
{
16, 7, 20, 21, 29, 12, 28, 17, 1,  15, 23, 26, 5,  18, 31, 10,
2,  8, 24, 14, 32, 27, 3,  9,  19, 13, 30, 6,  22, 11, 4,  25
};

static bool SubKey[2][16][48];//两个密钥的16轮子密钥
static char Tmp[256], deskey[16];

#define ENCRYPT 0
#define DECRYPT 1

//通用置换函数
void Transform(bool *Out, bool *In, const char *Table, int len)
{
for(int i = 0; i < len; ++ i)
Tmp[i] = In[ Table[i] - 1 ];
memcpy(Out, Tmp, len);
}

//异或运算
void Xor(bool *InA, const bool *InB, int len)
{
for(int i = 0; i < len; ++ i)
InA[i] ^= InB[i];
}

//循环左移
void MoveLeft(bool *In, int len, int loop)
{
memcpy(Tmp, In, loop);
memcpy(In, In + loop, len - loop);
memcpy(In + len - loop, Tmp, loop);
}

//字节转换成位
void Byte2Bit(bool *Out, const char *In, int bits)
{
for(int i = 0; i < bits; ++ i)
Out[i] = (In[i >> 3] >> (i & 7)) & 1;
}

//位转换字节
void Bit2Byte(char *Out, const bool *In, int bits)
{
memset(Out, 0, bits >> 3);
for(int i = 0; i < bits; ++ i)
Out[i >> 3] |= In[i] << (i & 7);
}

//S 盒置换
void funS(bool Out[32], const bool In[48])
{
for(char i = 0, j, k; i < 8; ++ i, In += 6, Out += 4)
{
j = (In[0] << 1) + In[5];
k = (In[1] << 3) + (In[2] << 2) + (In[3] << 1) + In[4];
Byte2Bit(Out, &Box_S[i][j][k], 4);
}
}

//F 函数
void funF(bool In[32], const bool Ki[48])
{
static bool MR[48];
Transform(MR, In, Table_E, 48);
Xor(MR, Ki, 48);
funS(In, MR);
Transform(In, In, Table_P, 32);
}

//生成子密钥
void MakeSubKey(PSubKey pSubKey, const char Key[8])
{
static bool K[64], *KL = &K[0], *KR = &K[28];
Byte2Bit(K, Key, 64);
Transform(K, K, Table_PC1, 56);
for(int i = 0; i < 16; ++ i)
{
MoveLeft(KL, 28, Table_Moveleft[i]);
MoveLeft(KR, 28, Table_Moveleft[i]);
Transform((*pSubKey)[i], K, Table_PC2, 48);
}
}

//生成密钥
void MakeKey(const char* Key, int len)
{
memset(deskey, 0, 16);
memcpy(deskey, Key, len > 16 ? 16 : len);
MakeSubKey(&SubKey[1], &deskey[8]);
}

//一重DES加/解密
void DES(char Out[8], char In[8], const PSubKey pSubKey, bool Type)
{
static bool M[64], tmp[32], *Li = &M[0], *Ri = &M[32];
Byte2Bit(M, In, 64);
Transform(M, M, Table_IP, 64);
if( Type == ENCRYPT ){ //加密

for(int i = 0; i < 16; ++ i)
{
memcpy(tmp, Ri, 32);
funF(Ri, (*pSubKey)[i]);
Xor(Ri, Li, 32);
memcpy(Li, tmp, 32);
}
}
else //解密
{
for(int i = 15; i >= 0; -- i)
{
memcpy(tmp, Li, 32);
funF(Li, (*pSubKey)[i]);
Xor(Li, Ri, 32);
memcpy(Ri, tmp, 32);
}
}
Transform(M, M, Table_InverseIP, 64);
Bit2Byte(Out, M, 64);
}

bool DoDES(char *Out, char *In, long datalen, const char *Key, int keylen, bool Type)
{
if( !( Out && In && Key && (datalen=(datalen+7)&0xfffffff8) ) )
return false;

MakeKey(Key, keylen);
// 3次DES 加密:加(key0)-解(key1)-加(key0) 解密:解(key0)-加(key1)-解(key0)
for(long i = 0, j = datalen >> 3; i < j; ++ i, Out += 8, In += 8)
{
DES(Out, In,  &SubKey[0], Type);
DES(Out, Out, &SubKey[1], !Type);
DES(Out, Out, &SubKey[0], Type);
}
return true;
}

int main(int argc,char *argv[])
{
int i;
char key[255];
char buf[255];
char str[8];
char key1[8];
char key2[8];

cout<<"Please input The string before encrypting: \n";
cin.getline(str, 255, '\n');
do
{
cout<<"Please input Key1(8 chars): \n";
cin>>key1;
} while (strlen(key1) != 8); //key1为8个字符

cout<<"Please input Key2: \n";
cin>>key2;

memset(key, 0, sizeof(key));
for (i = 0; i < 8; i ++)
{
key[i] = key1[i];
key[i + 8] = key2[i];
}

memset(buf, 0, sizeof(buf));
strcpy(buf, str);
cout<<"\nBefore encrypting\n";
cout<<buf<<endl;

DoDES(buf, buf, sizeof(str), key, sizeof(key), ENCRYPT);
cout<<"\nAfter encrypting\n";
cout<<buf<<endl;

DoDES(buf, buf, sizeof(str), key, sizeof(key), DECRYPT);
cout<<"\nAfter decrypting\n";
cout<<buf<<endl;

return 0;
}

python

from libdes import DES_Encrypt, DES_Decrypt


def validate_des_key(key: bytes) -> bool:
    for keyByte in key:
        binStr: str = "{0:0>8b}".format(keyByte)
        if sum([1 if b == '1' else 0 for b in binStr]) % 2 == 0:
            return False
    return True


if __name__ == '__main__':
    plaintextHex: str = input('plaintext:')
    key1Hex: str = input('key1:')
    if not validate_des_key(bytes.fromhex(key1Hex)):
        raise Exception('Parity check failed on the key.')
    key2Hex: str = input('key2:')
    if not validate_des_key(bytes.fromhex(key2Hex)):
        raise Exception('Parity check failed on the key.')
    key3Hex: str = input('key3:')
    if not validate_des_key(bytes.fromhex(key3Hex)):
        raise Exception('Parity check failed on the key.')

    ciphertext1: bytes = DES_Encrypt(
        bytes.fromhex(plaintextHex),
        bytes.fromhex(key1Hex),
    )

    ciphertext2: bytes = DES_Decrypt(
        ciphertext1,
        bytes.fromhex(key2Hex),
    )

    ciphertext3: bytes = DES_Encrypt(
        ciphertext2,
        bytes.fromhex(key3Hex),
    )

    print('ciphertext:', ciphertext3.hex())

    plaintext3: bytes = DES_Decrypt(
        ciphertext3,
        bytes.fromhex(key3Hex),
    )

    plaintext2: bytes = DES_Encrypt(
        plaintext3,
        bytes.fromhex(key2Hex),
    )

    plaintext1: bytes = DES_Decrypt(
        plaintext2,
        bytes.fromhex(key1Hex),
    )

    print('plaintext:', plaintext1.hex())

题目练习

[强网杯] just re

32位exe文件

ida打开,findcrypt插件发现des加密

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char ArgList[100]; // [esp+4h] [ebp-68h] BYREF

  puts("      #                        ######         ");
  puts("      # #    #  ####  #####    #     # ###### ");
  puts("      # #    # #        #      #     # #      ");
  puts("      # #    #  ####    #      ######  #####  ");
  puts("#     # #    #      #   #      #   #   #      ");
  puts("#     # #    # #    #   #      #    #  #      ");
  puts(" #####   ####   ####    #      #     # ###### ");
  sub_401CE0("%s", (char)ArgList);
  if ( sub_401610(ArgList) && sub_4018A0(ArgList) )
  {
    puts("congrats!");
    sub_401CA0("flag{%.26s}\n\n", (char)ArgList);
    return 0;
  }
  else
  {
    puts("sorry..");
    return 0;
  }
}

main函数看不出什么,先从des的表开始

按x查找,找到连续使用三次des的函数

操作太多了,考虑使用z3或者动调

找到3des之后追不了了,查看汇编

上面的一段很像smc,解密之后应该可以把3des和main函数联系起来

回到main函数分析,sub_4018A0会jumpout到sub_401610的 WriteProcessMemory(CurrentProcess, sub_4018A0, &xmmword_405018, 0x60u, 0);

int __thiscall sub_401610(_BYTE *this)
{
  unsigned int v2; // eax
  int v3; // esi
  char v4; // dh
  unsigned __int8 v5; // dl
  unsigned int v6; // eax
  int v7; // ecx
  __m128i v8; // xmm5
  char v9; // dl
  unsigned __int8 v10; // dh
  unsigned __int8 v11; // cl
  char v12; // ch
  unsigned __int8 v13; // ch
  char v14; // dl
  unsigned __int8 v15; // dh
  int v16; // esi
  __m128i v17; // xmm0
  __m128i v18; // xmm0
  int v19; // esi
  __m128i v20; // xmm4
  int v21; // ecx
  unsigned __int64 v22; // rax
  HANDLE CurrentProcess; // eax
  unsigned __int64 v25; // [esp-54h] [ebp-60h]
  unsigned int v26; // [esp-20h] [ebp-2Ch]
  unsigned __int8 v27; // [esp-1h] [ebp-Dh]

  v25 = __rdtsc();
  v2 = 0;
  v3 = 0;
  while ( 1 )
  {
    v4 = this[v3];
    if ( v4 >= '0' && v4 <= '9' )               // 数字
    {
      v5 = v4 - 65;
      goto LABEL_6;
    }
    v5 = v4 - 'A';                              // A-F = 0-5
    if ( (unsigned __int8)(v4 - 'A') > 0x19u )  // a-z
      break;
LABEL_6:
    v2 *= 16;
    if ( (unsigned __int8)(v4 - 48) <= 9u )
    {
      v6 = v2 - 48;
LABEL_10:
      v2 = v4 + v6;
      goto LABEL_11;
    }
    if ( v5 <= 0x19u )
    {
      v6 = v2 - 55;                             // A-Z = 10-15
      goto LABEL_10;
    }
LABEL_11:
    if ( ++v3 >= 8 )
    {
      v7 = 1;
      goto LABEL_14;
    }
  }
  v7 = 0;
LABEL_14:
  v8 = _mm_shuffle_epi32(_mm_cvtsi32_si128(v2), 0);
  if ( !v7 )
    return 0;
  v9 = this[8];
  v10 = 0;
  if ( v9 < 48 || v9 > 57 )
  {
    v11 = v9 - 65;
    v27 = v9 - 65;
    if ( (unsigned __int8)(v9 - 65) <= 0x19u )
      goto LABEL_19;
LABEL_33:
    v16 = 0;
    goto LABEL_34;
  }
  v11 = v9 - 65;
  v27 = v9 - 65;
LABEL_19:
  v12 = this[9];
  if ( v12 >= 48 && v12 <= 57 )
  {
    v13 = v12 - 65;
    goto LABEL_23;
  }
  v13 = v12 - 65;
  v27 = v11;
  if ( v13 > 0x19u )
    goto LABEL_33;
LABEL_23:
  if ( (unsigned __int8)(v9 - 48) > 9u )
  {
    if ( v27 > 0x19u )
      v14 = 0;
    else
      v14 = 16 * (v9 - 7);
  }
  else
  {
    v14 = 16 * v9;
  }
  v15 = this[9] - 48;
  if ( v15 <= 9u )
    goto LABEL_32;
  if ( v13 > 0x19u )
  {
    v15 = 0;
LABEL_32:
    v10 = v14 + v15;
    v16 = 1;
    goto LABEL_34;
  }
  v16 = 1;
  v10 = v14 + this[9] - 55;
LABEL_34:
  v17 = _mm_cvtsi32_si128((char)v10);
  v18 = _mm_unpacklo_epi8(v17, v17);
  v26 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v18, v18), 0).m128i_u32[0];
  if ( v16 )
  {
    v19 = 0;
    if ( dword_4053C4 >= 2 )
    {
      v19 = 16;
      v20 = _mm_mullo_epi32(_mm_cvtepu8_epi32(_mm_cvtsi32_si128(v26)), (__m128i)xmmword_404380);
      xmmword_405018 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32((__m128i)xmmword_404340, v8),
                                   _mm_add_epi32(v20, (__m128i)xmmword_405018));
      xmmword_405028 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404350, (__m128i)xmmword_404340), v8),
                                   _mm_add_epi32(v20, (__m128i)xmmword_405028));
      xmmword_405038 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404360, (__m128i)xmmword_404340), v8),
                                   _mm_add_epi32(v20, (__m128i)xmmword_405038));
      xmmword_405048 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404370, (__m128i)xmmword_404340), v8),
                                   _mm_add_epi32(v20, (__m128i)xmmword_405048));
    }
    do
    {
      *((_DWORD *)&xmmword_405018 + v19) = (v19 + v2) ^ (16843009 * v10 + *((_DWORD *)&xmmword_405018 + v19));
      ++v19;
    }
    while ( v19 < 24 );
    v21 = 0;
    while ( *((_BYTE *)&xmmword_405018 + v21) == *((_BYTE *)&loc_404148 + v21) )
    {
      if ( ++v21 >= 96 )
      {
        v22 = __rdtsc();
        if ( HIDWORD(v22) > HIDWORD(v25) || (unsigned int)(v22 - v25) >= 0xFFFFFF )
          MEMORY[0] = 0;
        CurrentProcess = GetCurrentProcess();
        WriteProcessMemory(CurrentProcess, sub_4018A0, &xmmword_405018, 96u, 0);
        return 1;
      }
    }
  }
  return 0;
}

WriteProcessMemory:将数据写入指定进程中的内存区域。要写入的整个区域必须可访问,否则操作将失败。

要写入的sub_4018A0就是smc处理过的函数,开始动调

先在 main函数的 if ( sub_401610(&v4) && sub_4018A0(&v4) )处打一个断点,然后输点什么进去(比如12345678),接着一直F7到这个循环

这段的意思是(0x12345678+0x10+i)^(90*1010101+ds:[405058+4 *i])将计算的结果给405058+4 * i,判断405058处地址与404188处地址是否相等

from z3 import *
a=[0x1e47913f,0x1e87963c,0xfa0b0acd,0x035b0958,0xf5e74cf4,0xfa1261dc,0x854b2f05,0xf852ed82]
b=[0x24448840,0x24848d4c,0x000001fc,0x0f50006a,0x1c244411,0x000f58e8,0x8d406a00,0x02482484]
solver=z3.Solver()
x=BitVec('x',32)
y=BitVec('y',32)
for i in range(8):
    solver.add(((a[i]+y*0x1010101)^(i+0x10+x))==b[i])
solver.add(x>0)
solver.add(y>0,y<0xff)
if (solver.check()==z3.sat):
    print(solver.model())
else:
    print("unsat")

a和b分别是下图的esi和esp

得到 [y = 25, x = 321135112],结果转换16进制前10个字符为1324220819

rdtsc:可用来获得程序或者一段代码运行的时间,这里有反调试的作用

在重进填数之前先把 v23 = __rdtsc();nop了,这样sub_401610就通了

WriteProcessMemory写入的新机器码没有显示,使用od

先去掉所有的int3和rdtsc

再通过搜索popa指令找到WriteProcessMemory

在上面有一个mov dword ptr ds:[eax],eax判断输入,会结束程序,需要nop掉

接下来F4到retn处,sub_4018A0就显露出来了。oddump出来分析

int __thiscall sub_4018A0(int this)
{
  size_t v1; // kr04_4
  signed int v2; // kr08_4
  int v3; // edi
  int i; // esi
  int v5; // edx
  int v6; // eax
  int v7; // ecx
  char v8; // ah
  int v9; // eax
  __int128 v11; // [esp+8h] [ebp-270h] BYREF
  int v12; // [esp+18h] [ebp-260h]
  int v13; // [esp+1Ch] [ebp-25Ch]
  __int128 Src[2]; // [esp+28h] [ebp-250h] BYREF
  char v15[128]; // [esp+50h] [ebp-228h] BYREF
  char v16[128]; // [esp+D0h] [ebp-1A8h] BYREF
  char v17[128]; // [esp+150h] [ebp-128h] BYREF
  int v18; // [esp+1D0h] [ebp-A8h] BYREF
  int v19; // [esp+1D4h] [ebp-A4h]
  int v20[6]; // [esp+1D8h] [ebp-A0h] BYREF
  char v21[64]; // [esp+1F0h] [ebp-88h] BYREF
  char v22[68]; // [esp+230h] [ebp-48h] BYREF

  strcpy((char *)Src, "AFSAFCEDYCXCXACNDFKDCQXC");
  v11 = *(_OWORD *)(this + 10);
  memset(v21, 0, sizeof(v21));
  memset(v22, 0, 0x40u);
  v1 = strlen((const char *)Src);
  memcpy(v20, Src, v1);
  memset((char *)v20 + v1, 0, 24 - v1);
  v18 = v20[0];
  v19 = v20[1];
  sub_401000(&v18, v17);
  v18 = v20[2];
  v19 = v20[3];
  sub_401000(&v18, v16);
  v18 = v20[4];
  v19 = v20[5];
  sub_401000(&v18, v15);
  v2 = strlen((const char *)&v11);
  memcpy(v21, &v11, v2);
  v3 = 8 * (v2 / 8) + 8;
  memset(&v21[v2], (char)(8 - v2 % 8), 8 - v2 % 8);
  if ( v3 > 0 )
  {
    for ( i = 0; i < v3; i += 8 )
    {
      v5 = (unsigned __int8)v21[i + 4];
      v6 = (unsigned __int8)v21[i + 5];
      v18 = ((unsigned __int8)v21[i + 3] << 24) | ((unsigned __int8)v21[i + 2] << 16) | ((unsigned __int8)v21[i + 1] << 8) | (unsigned __int8)v21[i];
      v19 = (v6 << 8) | v5 | (((unsigned __int8)v21[i + 6] | ((unsigned __int8)v21[i + 7] << 8)) << 16);
      sub_401500(v16, v15);
      v7 = v18;
      v22[i] = v18;
      v22[i + 1] = BYTE1(v7);
      v22[i + 2] = BYTE2(v7);
      v22[i + 3] = HIBYTE(v7);
      HIWORD(v7) = HIWORD(v19);
      v8 = BYTE1(v19);
      v22[i + 4] = v19;
      v22[i + 5] = v8;
      v22[i + 6] = BYTE2(v7);
      v22[i + 7] = HIBYTE(v7);
    }
  }
  *(_QWORD *)&v11 = 0xFACE0987E6A97C50ui64;
  v9 = 0;
  *((_QWORD *)&v11 + 1) = 0x6C97BB90CF0DD520i64;
  v12 = -1326018416;
  v13 = -391862661;
  while ( *((_BYTE *)&v11 + v9) == v22[v9] )
  {
    if ( ++v9 >= 16 )
      return 1;
  }
  return 0;
}

3des加密,密钥为AFSAFCEDYCXCXACNDFKDCQXC

密文

解密后将两段合起来即可

flag{13242208190dcc509a6f75849b}


文章来源: https://xz.aliyun.com/t/12810
如有侵权请联系:admin#unsafe.sh