CTF-密码学题目解析之SM4

admin 2024年7月1日14:35:40评论5 views字数 14814阅读49分22秒阅读模式

0.省流

这次的出题是个套娃题,主要是针对IDA工具的使用和SM4密码算法,题目本身难度不是很大,如果做题的人能搞清楚SM4算法,这道题解出来还是比较容易的。

1.SM4

SM4算法是一种对称分组密码算法,被中国国家密码管理局设计并公布,作为国家密码标准(GBT.32907-2016)。它广泛应用于无线局域网中的数据加密与认证。SM4算法具有较高的安全性和效率,是我国自主研发的密码算法。

1.1.SM4算法的来源

SM4算法最初由中国国家密码管理局在2006年设计,作为无线局域网(WLAN)安全标准。它于2016年成为中国的国家标准,并被广泛应用于国密算法体系中。SM4的设计基于分组密码的基本原理,采用了32轮的Feistel结构,与AES类似,但具有独特的S盒和密钥扩展机制。

1.2.SM4算法详解

SM4算法包括密钥扩展和加密两个主要部分。密钥扩展用于生成32个轮密钥,加密部分则是利用这些轮密钥对数据进行加密。SM4算法的每一轮加密操作包括字节替代、行移位、列混淆和轮密钥加等步骤。

  • 密钥扩展

密钥扩展过程将128位的密钥扩展成32个轮密钥,每个轮密钥也是128位。扩展过程包括非线性变换和线性变换。

  • 加密过程

初始密钥加:将输入的明文与密钥进行初始加法操作。

轮函数:每一轮包括S盒替代、线性变换和与轮密钥的异或操作。

输出变换:最终将轮函数输出的结果进行变换,得到密文。

1.3.SM4代码实现

S_BOX = [
    0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
    0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
    0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
    0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
    0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
    0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
    0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
    0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
    0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
    0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
    0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
    0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
    0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
    0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
    0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
    0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
]
FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]
CK = [
    0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
    0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
    0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
    0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
    0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
    0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
    0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
    0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
]

def left_rotate(value, shift):
    return ((value << shift) & 0xffffffff) | (value >> (32 - shift))

def tau(a):
    b = [0] * 4
    for i in range(4):
        b[i] = S_BOX[(a >> (24 - i * 8)) & 0xff]
    return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]

def L(b):
    return b ^ left_rotate(b, 2) ^ left_rotate(b, 10) ^ left_rotate(b, 18) ^ left_rotate(b, 24)

def L_prime(b):
    return b ^ left_rotate(b, 13) ^ left_rotate(b, 23)

def T(a):
    return L(tau(a))

def T_prime(a):
    return L_prime(tau(a))

def key_expansion(MK):
    K = [0] * 36
    rk = [0] * 32
    for i in range(4):
        K[i] = MK[i] ^ FK[i]
    for i in range(32):
        K[i + 4] = K[i] ^ T_prime(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i])
        rk[i] = K[i + 4]
    return rk

def sm4_encrypt_block(plaintext, rk):
    X = [0] * 36
    for i in range(4):
        X[i] = plaintext[i]
    for i in range(32):
        X[i + 4] = X[i] ^ T(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ rk[i])
    return [X[35], X[34], X[33], X[32]]
MK = [0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210]
rk = key_expansion(MK)
plaintext = [0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210]
ciphertext = sm4_encrypt_block(plaintext, rk)

print("密文: ", [hex(x) for x in ciphertext])

2.题目:

题目名称:StrangerSM4

题目文件:Stranger

CTF-密码学题目解析之SM4

2.1.出题思路

  • 题目背景:

选择SM4算法作为加密算法,并在程序中嵌入了静态分析和逆向工程技术。

  • 嵌入花指令:

通过插入花指令增加静态分析的难度,解题者需要去除这些指令以进行进一步分析。

  • 修改S盒:

通过修改SM4算法的S盒,使得标准解密算法无法直接解密,增加破解的难度。

  • 要求解密:

通过静态分析和逆向工程技术,修复并分析程序,最终解密出正确的flag。

2.2.解题思路

获得附件后,照常拖入 exeinfope 中查看程序信息,如下:

为 64 位 elf 可执行程序,无壳,拖入 ida64 中打开,找到主函数,发现 f5 反编译失败,按 空格键转为汇编代码形式,如下:

CTF-密码学题目解析之SM4

着重关注上图的红框,发现在 100F 处出现了 call $+5,在 0101B 处出现了很明显的垃圾指令 0EB,很明显,这里被嵌入了花指令,我们需要把花指令去除。

仔细观察,push rbp 是调用 call $+5 前必须操作的,有个 push rbp,那必定要用 pop rbp, 因此我们可以锁定花指令的范围即从 100E-101C,把这些指令均 patch 为 0x90 即可,如下图操作:

CTF-密码学题目解析之SM4

点击 change byte,进行 patch,如下:

CTF-密码学题目解析之SM4

点击 ok 完成操作。下图是 patch 之后的样子。

CTF-密码学题目解析之SM4

现在花指令去除了,但是函数的栈帧仍然不正确,我们需要进行修改。修改步骤如下:

  1. 让 ida,重新分析 main 代码,不进行此步将无法修改栈帧。选中 main 函数主体,选中

后按’C’健,点击 analysis 即可。

CTF-密码学题目解析之SM4
CTF-密码学题目解析之SM4
  1. 进行修改栈帧。首先找到 main 函数的结尾地址,这里为 1226 如下:
CTF-密码学题目解析之SM4

然后我们在 mian 函数处,右键,点击 edit function,如下图:

CTF-密码学题目解析之SM4

点击进行修改,将 end address 修改为 1184,确定后,再 f5 即可成功反编译 main 函数。(由于写 wp 时发现了一些 bug,修改了程序,重新编译了,导致上面和下面的地址略有不同,但解题过程没有改变)。

CTF-密码学题目解析之SM4
CTF-密码学题目解析之SM4

到这里,我们可以对 main 函数正式进行分析。主函数分析:

  1. 首先程序会打印一大堆字符串,我们可以看,最后一串告诉我们要输入 128bit 的 16 进制字符串,也就是 4 组 32bit。

  2. 上图中第 18 行是个输入,从变量 v4-v7

  3. 进入第 19 行 sub_CE6 函数,如下:

CTF-密码学题目解析之SM4

继续进入 sub_ABA,如下:

CTF-密码学题目解析之SM4

查看 qword_13E0[i],发现:

CTF-密码学题目解析之SM4

发现神秘的 4 组数字,拿去网上搜索,发现与分组密码的密钥扩展有关。可以猜测主函 数中的 sub_C96 是个密钥扩展函数。

CTF-密码学题目解析之SM4

结合题目名称 strangerSm,猜测与 sm4 相关。继续往下分析,我们现在进入 sub_CE6 中 的 sub_B56 函数,如下:

CTF-密码学题目解析之SM4

根据这里,我们再进行一个回顾,已经可以猜测 sub_CE6 是一个密钥扩展函数,而且从 主函数我们可以发现传入的第一个参数已知的,猜测为加密密钥。如下图,为了更方便 观察,使用 ida 改了下变量名:

CTF-密码学题目解析之SM4

这里对两个函数进行了描述,大概就是先将加密密钥与一个固定值进行异或,异或之后 得到新的临时密钥,这一步操作就是 sub_ABA()。假设密钥以 32bit 为一组,那么再将临 时密钥扩展至 36 组,取后面 32 组为我们的轮密钥。

以上,我们几乎可以确定 sub_CE6 就是一个密钥扩展函数,而每个分组的密钥扩展函数 都会有固定值,我们查看 sub_B56 中的固定值 qword_1400

CTF-密码学题目解析之SM4

到这里我们可以确定就是 sm4 分组加密了。网上搜索 sm4 加密,查看其加密以及密钥扩展算法:

CTF-密码学题目解析之SM4

我们可以发现,这里的密钥扩展算法就和 ida 反编译出的一模一样,忽略其他细节,我们看看加密函数是否符合 sm4 的加密流程。回到主函数,解析已写好,如下:

CTF-密码学题目解析之SM4

到这里为止,程序的思路就是输入我们的 flag 值,进行 sm4 分组加密,拿到的密文再与程 序中的密文进行对比,相等则输入 flag 正确。只要这个算法没有被修改,那我们可以直接进 行解密,因为 key 值我们也是可以知道的,如下:

CTF-密码学题目解析之SM4

这里本身展示是以单个字节 db 为单位展示的,但我们可以知道程序中是以 32bit 为一组存 放变量,因此需要将四个db 转为 dd,在 ida 中按‘D’键可以实现,而我们可以很明显的知道

key=0123456789ABCDEFFEDCBA9876543210,

同理,

密文=3c76695402bbaac02dd870514abcd0f0

直接进行解密,如下:


**from pysm4 import decrypt**

**from Crypto.Util.number import ***

**key=0x0123456789abcdeffedcba9876543210**

**cipher = 0x3c76695402bbaac02dd870514abcdofo plaintext = decrypt(cipher, key)**

**print(long_to_bytes(plaintext))**
CTF-密码学题目解析之SM4

发现是乱码,发现不对,猜测算法内部发生了改变。继续往下分析,sm4 分组算法最重要的就是轮函数和密钥扩展算法,这两个算法包含一个合成变换T,如下:

CTF-密码学题目解析之SM4

因此,若想要改变内部的算法而保持加密框架不变,那么可以猜是从以下方便入手(仅个人想法):

1 改变非线性变换 S 盒

2 改变线性变换 L

3 改变轮函数中,X0,X1,X2,X3 的组合顺序,比如变成 F = X1^T(X0^X2^X3^RK) 4 改变常量值,如密钥扩展中的固定值(结合上面分析,可知这里没有改变)。剩下,我们就可以一一去分析了。

首先查看 S 盒中的常量,原本 S 盒值应为:

CTF-密码学题目解析之SM4

本程序中的 S 盒值为:

CTF-密码学题目解析之SM4

很明显不对,因此定改变了S盒的值,再去查看其它的发现均未改变,此时,这道题就变成了:

题:已知使用的是 sm4 分组算法,给出密文和密钥,但 S 盒改变,请解出明文。

那这就好办了,只是改变了 S 盒,我们可以从 pysm4 中找到 sm4 加解密的原文件,稍加修 改即可。

CTF-密码学题目解析之SM4

找到之后,为了不改变源文件,我们将整⻚复制下来,放到我们解题文件中,再将 S 盒修改为程序中的 S 盒。下面对 S 盒进行提取,找到 S 盒,按 shift+E 进行提取,

CTF-密码学题目解析之SM4

然后将 S 盒值复制至解题文件中,稍微写个 for 循环替换 S 盒中的值,照常解密,即可把 flag 解出。

3.解题代码

解题脚本如下:

**# from pysm4 import decrypt 这里需要注释掉,避免产生函数冲突 from Crypto.Util.number import ***

**from sys import version_info**

**from base64 import b64encode, b64decode from binascii import hexlify, unhexlify**

**__all__ = ['encrypt_ecb''decrypt_ecb''encrypt_cbc''decrypt_cbc',**

**'encrypt''decrypt']**

**if version_info[0] == 2:**

**# python2**

**PY2 = True**

**PY3 = False**

**else:**

**# python3**

**PY2 = False**

**PY3 = True**

**if PY2:**

**_range = xrange**

**string_types = (basestring,)**

**text_type = unicode**

**binary_type = str**

**else:**

**_range = range**

**string_types = (str,)**

**text_type = str**

**binary_type = bytes**

**E_FMT = 'UTF8'**

**#S盒 S_BOX = {**

**0X00: 0XD6, 0X01: 0X90, 0X02: 0XE9, 0X03: 0XFE, 0X04: 0XCC, 0X05: 0XE1, 0X06: 0X3D, 0X07: 0XB7,**

**0X08: 0X16, 0X09: 0XB6, 0X0A: 0X14, 0X0B: 0XC2, 0X0C: 0X28, 0X0D: 0XFB, 0X0E: 0X2C, 0X0F: 0X05,**

**0X10: 0X2B, 0X11: 0X67, 0X12: 0X9A, 0X13: 0X76, 0X14: 0X2A, 0X15: 0XBE, 0X16: 0X04, 0X17: 0XC3,**

**0X18: 0XAA, 0X19: 0X44, 0X1A: 0X13, 0X1B: 0X26, 0X1C: 0X49, 0X1D: 0X86, 0X1E: 0X06, 0X1F: 0X99,**

**0X20: 0X9C, 0X21: 0X42, 0X22: 0X50, 0X23: 0XF4, 0X24: 0X91, 0X25: 0XEF, 0X26: 0X98, 0X27: 0X7A,**

**0X28: 0X33, 0X29: 0X54, 0X2A: 0X0B, 0X2B: 0X43, 0X2C: 0XED, 0X2D: 0XCF, 0X2E: 0XAC, 0X2F: 0X62,**

**0X30: 0XE4, 0X31: 0XB3, 0X32: 0X1C, 0X33: 0XA9, 0X34: 0XC9, 0X35: 0X08, 0X36: 0XE8, 0X37: 0X95,**

**0X38: 0X80, 0X39: 0XDF, 0X3A: 0X94, 0X3B: 0XFA, 0X3C: 0X75, 0X3D: 0X8F, 0X3E: 0X3F, 0X3F: 0XA6,**

**0X40: 0X47, 0X41: 0X07, 0X42: 0XA7, 0X43: 0XFC, 0X44: 0XF3, 0X45: 0X73, 0X46: 0X17, 0X47: 0XBA,**

**0X48: 0X83, 0X49: 0X59, 0X4A: 0X3C, 0X4B: 0X19, 0X4C: 0XE6, 0X4D: 0X85, 0X4E: 0X4F, 0X4F: 0XA8,**

**0X50: 0X68, 0X51: 0X6B, 0X52: 0X81, 0X53: 0XB2, 0X54: 0X71, 0X55: 0X64, 0X56: 0XDA, 0X57: 0X8B,**

**0X58: 0XF8, 0X59: 0XEB, 0X5A: 0X0F, 0X5B: 0X4B, 0X5C: 0X70, 0X5D: 0X56, 0X5E: 0X9D, 0X5F: 0X35,**

**0X60: 0X1E, 0X61: 0X24, 0X62: 0X0E, 0X63: 0X5E, 0X64: 0X63, 0X65: 0X58, 0X66: 0XD1, 0X67: 0XA2,**

**0X68: 0X25, 0X69: 0X22, 0X6A: 0X7C, 0X6B: 0X3B, 0X6C: 0X01, 0X6D: 0X21, 0X6E: 0X78, 0X6F: 0X87,**

**0X70: 0XD4, 0X71: 0X00, 0X72: 0X46, 0X73: 0X57, 0X74: 0X9F, 0X75: 0XD3, 0X76: 0X27, 0X77: 0X52,**

**0X78: 0X4C, 0X79: 0X36, 0X7A: 0X02, 0X7B: 0XE7, 0X7C: 0XA0, 0X7D: 0XC4, 0X7E: 0XC8, 0X7F: 0X9E,**

**0X80: 0XEA, 0X81: 0XBF, 0X82: 0X8A, 0X83: 0XD2, 0X84: 0X40, 0X85: 0XC7, 0X86: 0X38, 0X87: 0XB5,**

**0X88: 0XA3, 0X89: 0XF7, 0X8A: 0XF2, 0X8B: 0XCE, 0X8C: 0XF9, 0X8D: 0X61, 0X8E: 0X15, 0X8F: 0XA1,**

**0X90: 0XE0, 0X91: 0XAE, 0X92: 0X5D, 0X93: 0XA4, 0X94: 0X9B, 0X95: 0X34, 0X96: 0X1A, 0X97: 0X55,**

**0X98: 0XAD, 0X99: 0X93, 0X9A: 0X32, 0X9B: 0X30, 0X9C: 0XF5, 0X9D: 0X8C, 0X9E: 0XB1, 0X9F: 0XE3,**

**0XA0: 0X1D, 0XA1: 0XF6, 0XA2: 0XE2, 0XA3: 0X2E, 0XA4: 0X82, 0XA5: 0X66, 0XA6: 0XCA, 0XA7: 0X60,**

**0XA8: 0XC0, 0XA9: 0X29, 0XAA: 0X23, 0XAB: 0XAB, 0XAC: 0X0D, 0XAD: 0X53, 0XAE: 0X4E, 0XAF: 0X6F,**

**0XB0: 0XD5, 0XB1: 0XDB, 0XB2: 0X37, 0XB3: 0X45, 0XB4: 0XDE, 0XB5: 0XFD, 0XB6: 0X8E, 0XB7: 0X2F,**

**0XB8: 0X03, 0XB9: 0XFF, 0XBA: 0X6A, 0XBB: 0X72, 0XBC: 0X6D, 0XBD: 0X6C, 0XBE: 0X5B, 0XBF: 0X51,**

**0XC0: 0X8D, 0XC1: 0X1B, 0XC2: 0XAF, 0XC3: 0X92, 0XC4: 0XBB, 0XC5: 0XDD, 0XC6: 0XBC, 0XC7: 0X7F,**

**0XC8: 0X11, 0XC9: 0XD9, 0XCA: 0X5C, 0XCB: 0X41, 0XCC: 0X1F, 0XCD: 0X10, 0XCE: 0X5A, 0XCF: 0XD8,**

**0XD0: 0X0A, 0XD1: 0XC1, 0XD2: 0X31, 0XD3: 0X88, 0XD4: 0XA5, 0XD5: 0XCD, 0XD6: 0X7B, 0XD7: 0XBD,**

**0XD8: 0X2D, 0XD9: 0X74, 0XDA: 0XD0, 0XDB: 0X12, 0XDC: 0XB8, 0XDD: 0XE5, 0XDE: 0XB4, 0XDF: 0XB0,**

**0XE0: 0X89, 0XE1: 0X69, 0XE2: 0X97, 0XE3: 0X4A, 0XE4: 0X0C, 0XE5: 0X96, 0XE6: 0X77, 0XE7: 0X7E,**

**0XE8: 0X65, 0XE9: 0XB9, 0XEA: 0XF1, 0XEB: 0X09, 0XEC: 0XC5, 0XED: 0X6E, 0XEE: 0XC6, 0XEF: 0X84,**

**0XF0: 0X18, 0XF1: 0XF0, 0XF2: 0X7D, 0XF3: 0XEC, 0XF4: 0X3A, 0XF5: 0XDC, 0XF6: 0X4D, 0XF7: 0X20,**

**0XF8: 0X79, 0XF9: 0XEE, 0XFA: 0X5F, 0XFB: 0X3E, 0XFC: 0XD7, 0XFD: 0XCB, 0XFE: 0X39, 0XFF: 0X48**

**}**

**new_values=[ 0x45, 0x1F, 0x18, 0x7B, 0x79, 0x44, 0x7F, 0x0B, 0xE0,**

**0x7D, 0xF3, 0x76, 0x67, 0xB3, 0xD7, 0xDE, 0xC4, 0xBB, 0xEC, 0x51, 0x3A, 0x28, 0xD0, 0xA5, 0x0C, 0xFB, 0x0F, 0x75, 0x14, 0x8A, 0xC3, 0x19, 0x72, 0xB1, 0x7C, 0x32, 0xAF, 0xBF, 0xBC, 0x66, 0x92, 0x11, 0xE1, 0xB4, 0xCF, 0x90, 0x2C, 0x9C, 0x1E, 0xE7, 0x81, 0xA4, 0xBE, 0x9E, 0xDF, 0x1A, 0xAD, 0xC5, 0x2B, 0x02, 0x08, 0x2F, 0xCE, 0x34, 0x83, 0x5A, 0xFC, 0x5B, 0x64, 0x31, 0x35, 0x6F, 0xA3, 0xF6, 0xDD, 0x05, 0xB8, 0x52, 0x4A, 0x46, 0x9B, 0xE8, 0xA6, 0xB0, 0x53, 0x82, 0x49, 0xE4, 0xFA,**

**0x5E,**

**0x5C, 0x38, 0x96, 0xAC, 0xA1, 0x86, 0xB2, 0x2E, 0xFD, 0x80, 0x1C, 0x91, 0x04, 0x5F, 0x8C, 0x97, 0xF5, 0x33, 0xFE, 0x77, 0xAE, 0x03, 0x59, 0x27, 0x3D, 0x98, 0x73, 0xD2, 0xCC, 0xA2, 0x8E, 0xC7, 0x3E, 0x50, 0x26, 0x24, 0x85, 0x21, 0xBD, 0x07, 0x63, 0x20, 0xDB, 0x4C, 0xD5, 0xF7, 0xD3, 0x13, 0x42, 0xE5, 0x01, 0xC1, 0xF9, 0xD4, 0xA8, 0x54, 0xC9, 0xD8, 0x30, 0xB5, 0xEF, 0xF2, 0xFF, 0xDA, 0xE2, 0x6D, 0xA9, 0xE6, 0xC8, 0x7E, 0x10, 0x8B, 0x74, 0x41, 0xD9, 0xCD, 0x7A, 0xC0, 0x70, 0x94, 0x6A, 0x88, 0x9D, 0x6B, 0x2D, 0x68, 0xE9, 0xB9, 0x2A, 0x09, 0x56, 0xC2, 0x48, 0x71, 0xD6, 0x37, 0x93, 0xEE, 0x4E, 0xAA, 0x3F, 0xCB]**

**0x3C, 0xEB, 0x06, 0x8D,**

**0x5D, 0x95, 0xD1, 0x78,**

**0xED, 0x9F, 0x65, 0x99,**

**0x43, 0x25, 0x84, 0x8F,**

**0x60, 0x58, 0xA0, 0x62,**

**0xCA, 0x40, 0x36, 0x22,**

**0x23, 0x55, 0x12, 0x4B,**

**0x0A, 0x17, 0x00, 0xE3,**

**0x39, 0x0E, 0xF1, 0x4F,**

**0x4D, 0xC6, 0xDC, 0x89,**

**0xF4, 0xB7, 0x6C, 0x1B,**

**0xF8, 0x87, 0xF0, 0x9A,**

**0xAB, 0x57, 0x3B, 0x15,**

**0x69, 0x1D, 0x16, 0x6E,**

**0xB6, 0xEA, 0x0D, 0x61,**

**0x29, 0xA7, 0xBA, 0x47,**

**for key, new_value in zip(S_BOX.keys(), new_values):**

**FK = (0XA3B1BAC6, 0X56AA3350, 0X677D9197, 0XB27022DC)**

**CK = (0X00070E15, 0X1C232A31, 0X383F464D, 0X545B6269,**

**0X70777E85, 0X8C939AA1, 0XA8AFB6BD, 0XC4CBD2D9, 0XE0E7EEF5, 0XFC030A11, 0X181F262D, 0X343B4249, 0X50575E65, 0X6C737A81, 0X888F969D, 0XA4ABB2B9, 0XC0C7CED5, 0XDCE3EAF1, 0XF8FF060D, 0X141B2229, 0X30373E45, 0X4C535A61, 0X686F767D, 0X848B9299, 0XA0A7AEB5, 0XBCC3CAD1, 0XD8DFE6ED, 0XF4FB0209, 0X10171E25, 0X2C333A41, 0X484F565D, 0X646B7279)**

**SM4_ENCRYPT = 1**

**SM4_DECRYPT = 0**

**BLOCK_BYTE = 16**

**BLOCK_HEX = BLOCK_BYTE * 2**

**def num2hex(num, width=1):**

**return '{:0>{width}}'.format(hex(num)[2:].replace('L'''),**

**width=width)**

**def _byte_unpack(num, byte_n=4):**

**_len = 4**

**step = (byte_n // _len) * 2**

**hex_str = num2hex(num=num, width=byte_n * 2)**

**split_v = list(_range(len(hex_str)))[::step] + [len(hex_str)] return tuple([int(hex_str[s:e], base=16) for s, e in**

**zip(split_v[:-1], split_v[1:])])**

**def _byte_pack(byte_array, byte_n=4): _len = 4**

**if len(byte_array) != _len:**

**raise ValueError('byte_array length must be 4.'return int(''.join([num2hex(num=v, width=width)**

**for v in byte_array]), 16)**

**def _s_box(byte):**

**return S_BOX.get(byte)**

**def _non_linear_map(byte_array):**

**return (_s_box(byte_array[0]), _s_box(byte_array[1]),**

**_s_box(byte_array[2]), _s_box(byte_array[3]))**

**def _linear_map(byte4):**

**_left = loop_left_shift**

**return byte4 ^ _left(byte4, 2) ^ _left(byte4, 10) ^ _left(byte4, 18)**

**^ _left(byte4, 24)**

**def _linear_map_s(byte4):**

**_left = loop_left_shift**

**return byte4 ^ _left(byte4, 13) ^ _left(byte4, 23)**

**def loop_left_shift(num, offset, base=32):**

**bin_str = '{:0>{width}}'.format(bin(num)[2:], width=base) rem = offset % base**

**return int(bin_str[rem:] + bin_str[:rem], 2)**

**def _rep_t(byte4):**

**b_array = _non_linear_map(_byte_unpack(byte4))**

**return _linear_map_s(_byte_pack(b_array))**

**def _round_keys(mk):**

**if _rk_keys is None:**

**mk0, mk1, mk2, mk3 = _byte_unpack(mk, byte_n=16)**

**keys = [mk0 ^ FK[0], mk1 ^ FK[1], mk2 ^ FK[2], mk3 ^ FK[3]] for i in _range(32):**

**rk = keys[i] ^ _rep_t_s(keys[i + 1] ^ keys[i + 2] ^ keys[i +**

**3] ^ CK[i])**

**keys.append(rk) _rk_keys = keys[4:]**

**return _rk_keys**

**def _round_f(byte4_array, rk):**

**x0, x1, x2, x3 = byte4_array**

**return x0 ^ _rep_t(x1 ^ x2 ^ x3 ^ rk)**

**def _crypt(num, mk, mode=SM4_ENCRYPT):**

**x_keys = list(_byte_unpack(num, byte_n=16)) round_keys = _round_keys(mk)**

**if mode == SM4_DECRYPT: round_keys = round_keys[::-1]**

**for i in _range(32):**

**x_keys.append(_round_f(x_keys[i:i + 4], round_keys[i]))**

**return _byte_pack(x_keys[-4:][::-1], byte_n=16)**

**def encrypt(clear_num, mk): """**

**return _crypt(num=clear_num, mk=mk)**

**def decrypt(cipher_num, mk):**

**return _crypt(num=cipher_num, mk=mk, mode=SM4_DECRYPT)**

**key=0x0123456789abcdeffedcba9876543210 cipher = 0x3c76695402bbaac02dd870514abcd0f0 plaintext = decrypt(cipher, key) print(long_to_bytes(plaintext))**

运行即可得出 flag,运行结果如下,flag 为: flag{sboxbroken}

原文始发于微信公众号(攻防SRC):CTF-密码学题目解析之SM4

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月1日14:35:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CTF-密码学题目解析之SM4https://cn-sec.com/archives/2904501.html

发表评论

匿名网友 填写信息