当前位置: 首页 > news >正文

2025熵密杯 -- 初始谜题 -- Reproducibility

2025熵密杯 – 初始谜题 – Reproducibility

前言

本文记录2025熵密杯初始谜题赛题复现过程,参考languag3师傅的熵密杯题解博客。膜拜大佬~

https://languag3.github.io/

初始谜题1

sm4_encrypt.py

import binascii
from pyasn1.codec.der.decoder import decode
from pyasn1.type import univ, namedtype
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from gmssl import sm3, func, sm2
from pyasn1.codec.der.encoder import encodeclass SM2Cipher(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('xCoordinate', univ.Integer()), # -- x 分量namedtype.NamedType('yCoordinate', univ.Integer()),             # -- y 分量namedtype.NamedType('hash', univ.OctetString()),                # --哈希值namedtype.NamedType('cipherText', univ.OctetString())           # -- SM4密钥密文)class EncryptedData(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('algorithm', univ.ObjectIdentifier('1.2.156.10197.1.104.2')), # -- SM4-CBC OIDnamedtype.NamedType('iv', univ.OctetString()),                                                # -- SM4-CBC加密使用的初始化向量(IV)namedtype.NamedType('cipherText', univ.OctetString())                                         # -- SM4加密的密文)class EnvelopedData(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('encryptedKey', SM2Cipher()),                           # -- 使用SM2公钥加密SM4密钥的密文namedtype.NamedType('encryptedData', EncryptedData()),                                  #  -- 使用SM4密钥对明文加密的密文namedtype.NamedType('digestAlgorithm', univ.ObjectIdentifier('1.2.156.10197.1.401.1')), # -- SM3算法OIDnamedtype.NamedType('digest', univ.OctetString())                                       # -- 对明文计算的摘要值)def sm4_cbc_encrypt(plaintext: bytes, key: bytes, iv: bytes):backend = default_backend()cipher = Cipher(algorithms.SM4(key), modes.CBC(iv), backend=backend) #填充模式 nopaddingencryptor = cipher.encryptor()ciphertext = encryptor.update(plaintext) + encryptor.finalize()return ciphertextdef sm2_encrypt(plaintext: bytes,public_key:bytes) -> bytes:sm2_crypt = sm2.CryptSM2(private_key="",public_key=public_key.hex())ciphertext = sm2_crypt.encrypt(plaintext)return ciphertextdef sm3_hash(text:bytes):hash_value = sm3.sm3_hash(func.bytes_to_list(text))return hash_valuedef read_key_from_file(file_path):try:with open(file_path, 'r') as file:key = file.read().strip()return keyexcept FileNotFoundError:print(f"错误: 文件 {file_path} 未找到。")except Exception as e:print(f"错误: 发生了未知错误 {e}。")return None# 对由abcd组成的字符串加密的方法
def sm4_encrypt(plaintext:str,sm2_public_key: str,sm4_iv:str):sm4_key = bytes.fromhex(read_key_from_file("key.txt")) #从文件读取固定的key# sm4envelope = EnvelopedData()plaintext_bytes = plaintext.encode('utf-8')ciphertext = sm4_cbc_encrypt(plaintext_bytes,sm4_key,bytes.fromhex(sm4_iv))# sm2encrypted_key = sm2_encrypt(sm4_key,bytes.fromhex(sm2_public_key))# sm3digest = sm3_hash(plaintext_bytes)envelope['encryptedData'] = EncryptedData()envelope['encryptedData']['iv'] = univ.OctetString(bytes.fromhex(sm4_iv))envelope['encryptedData']['cipherText'] = univ.OctetString(ciphertext)envelope['encryptedKey'] = SM2Cipher()envelope['encryptedKey']['xCoordinate'] = univ.Integer(int.from_bytes(encrypted_key[:32], 'big'))envelope['encryptedKey']['yCoordinate'] = univ.Integer(int.from_bytes(encrypted_key[32:64], 'big'))envelope['encryptedKey']['hash'] = univ.OctetString(encrypted_key[64:96])envelope['encryptedKey']['cipherText'] = univ.OctetString(encrypted_key[96:])envelope['digest'] = univ.OctetString(bytes.fromhex(digest))return encode(envelope).hex()# 从asn1格式的16进制字符串提取参数
def asn1_parse(asn1_hex_str:str,asn1_spec):# 将16进制字符串转换为字节der_bytes = binascii.unhexlify(asn1_hex_str)# 解码为ASN.1对象enveloped_data, _ = decode(der_bytes, asn1Spec=asn1_spec)# sm2sm2_x = hex(int(enveloped_data['encryptedKey']['xCoordinate']))[2:]sm2_y = hex(int(enveloped_data['encryptedKey']['yCoordinate']))[2:]sm2_hash = enveloped_data['encryptedKey']['hash'].asOctets().hex()sm2_ciphertext = enveloped_data['encryptedKey']['cipherText'].asOctets().hex()# sm4sm4_algorithm = str(enveloped_data['encryptedData']['algorithm'])sm4_iv = enveloped_data['encryptedData']['iv'].asOctets().hex()sm4_cipherText = enveloped_data['encryptedData']['cipherText'].asOctets().hex()# sm3digestAlgorithm = str(enveloped_data['digestAlgorithm'])digest = enveloped_data['digest'].asOctets().hex()# 输出提取的值print("asn1格式的16进制字符串:")print(f"  asn1: {asn1_hex_str}")print("SM2参数:")print(f"  xCoordinate: {sm2_x}")print(f"  yCoordinate: {sm2_y}")print(f"  hash: {sm2_hash}")print(f"  cipherText: {sm2_ciphertext}")print("SM4参数:")print(f"  algorithm: {sm4_algorithm}")print(f"  iv: {sm4_iv}")print(f"  cipherText: {sm4_cipherText}")print("SM3参数:")print(f"  digestAlgorithm: {digestAlgorithm}")print(f"  digest: {digest}")if __name__ == "__main__":plaintext = "6163616263626161626461646464636361626263626464626361616164636462636462646461646461626462646361636264616364646462646462626261636261646163626463636262616462646462616362616363646463646361616263646261636164636263646163646161636164646364646261626463636462636162636162646261626163636161616463616261646264616162646162626162626462616363616161636362616461626463616462646261626264626464626262636363636162616261626163616164616462626163636164646161646361626363646462626261636261636164646262646362616263636363626461636164646261636361646463616161626164626461636163636461646164616161616163616164636164646261646163626163636164616162636263616461636261646264626263626264636164646263616164626463626461646364616362626261616262616264616361626264636264616461646163626364626462636161636262636163616261616262626362636463616263616364616363626163636363636262646363616464626461616363646361626162636261636364646362626462616364626462626161616264636162626263626462626264646162626462616261616264626161616363636364616263626461636162616462616363616461646363636261636363616162646164626361616464646463646263646363636164626164646463646361636364616261626261646461646463626161616361626161626362626262636164626463636163626163616163636262646463646162616363616364636164646364626464626164626162636161616263646164636461626161636262646463636462646161636462626264626463646364636362626264616362646462636263616361626262616464636263616464616363646163616262616162626261626261616461636361636164636162626461646264636162646363636263616363646161636464626161616462636464646164616361646264616361626263646264616162636164636462616164646163616461646362626464"sm2_key = "044f66804d1d30f4499377b96dc8e18faab8300ebddf3eb0fa2065214c260d64c08c6dfe7d9923d6d5baa3a0512a2ede03357c723230ebf77906f82dc1b0fccc1e"iv = "43d4192f9f74e90543d4192f9f74e905"asn1_hex_str = sm4_encrypt(bytes.fromhex(plaintext).decode('utf-8'),sm2_key,iv)asn1_parse(asn1_hex_str,EnvelopedData())
(m, c) = (6362646264646264646361636463646261636164626362646264616161636162636261616461646263626362626264636163616264626164616161616361616161636163636361626463616361626263626263646462626261616462646362626162646162646461646264626361646264636164626262626264646464626362626462626364646463636362636264616161636461626363626362616263636264636164636261646262626161636161616461616163616461626461646464616363646462636464646464636462636264636464636162616461646263646264636363616263616164646263646362646161616361646261616161626261626462636261646362626362626462636463616164636263646164636461646364646464616461626463616463636362626464646463636461626264636363636263646463626163636362646264616261636464626164646363626164626264616462626264646463646163646162626364616264646163636362646164616263616461626164636261646361636162616162646161646162636364646162626361646362646361626463616262646362636261616464626162636161616362616464616261626363616464626164616362616262616463626364646461636461636164636261626364646362626263636164626161636264646261636264626164626264636463616263646462646464636461626264626262626263626362636463636362636264646262626162626364616363636264626462636163646361636163616464626361616262646361626261646364646461636164626164646361626264616364626361636163626163636363626464626462646364646364616461616161616361646264626364636364626261636363636361616264636262646262616263636361616361616261616162636163646363646264636364616362626362626463616264646261626164646263646164646264616463646462626261616461636461626262636462646163636461646362616363616163616361626162636462616362636361646363626161636362636361616261636362636463, 308203ec30790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f576503082034006082a811ccf550168020410f414bdfbca9d9e902114536a3b9c443204820320d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f947706092a811ccf5501831101042024d458eef08943e27b496fd180de68c18f467bee9d3c802bb56d607a364ddc70)
c = 3081e830790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f57650303e06082a811ccf550168020410b63a85e103d362fb6247c19e324e97c4042098fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea0010706092a811ccf55018311010420aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79

analysis

  • 基于当时现场的分析,该题目实现了当前通信中常用的数字信封,使用对称密码加密明文信息,使用非对称密码加密对称密码所使用的密钥,同时利用杂凑函数计算相应的信息摘要。体现在这道题中就是SM4-CBC加密明文信息,SM2加密SM4-CBC密钥,SM3计算消息杂凑值。

  • 本题目中将以下参数加入到asn1证书中,同时明文信息为abcd的组合。

    1. SM2的公钥以及SM2针对于SM4-CBC密钥加密后的密文
    2. SM4-CBC使用的iv以及对明文加密之后的密文
    3. SM3针对于明文进行的杂凑值
    4. 交互得到的一对(m, c)和待解密密文
  • asn1解析结果如下:

    from sm4_encrypt import asn1_parse, EnvelopedDataprint("#########################c1 asn_parse")
    c1 = ...
    asn1_parse(c1, EnvelopedData())
    print("#########################c asn_parse")
    c = ...
    asn1_parse(c, EnvelopedData())"""
    #########################c1 asn_parse
    asn1格式的16进制字符串:asn1: 308203ec30790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f576503082034006082a811ccf550168020410f414bdfbca9d9e902114536a3b9c443204820320d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f947706092a811ccf5501831101042024d458eef08943e27b496fd180de68c18f467bee9d3c802bb56d607a364ddc70
    SM2参数:xCoordinate: 467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da405yCoordinate: 99f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d8hash: 4452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714bcipherText: 443c9a3f4f7b0083ddd323d6a1f57650
    SM4参数:algorithm: 1.2.156.10197.1.104.2iv: f414bdfbca9d9e902114536a3b9c4432cipherText: d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f9477
    SM3参数:digestAlgorithm: 1.2.156.10197.1.401.1digest: 24d458eef08943e27b496fd180de68c18f467bee9d3c802bb56d607a364ddc70
    #########################c asn_parse
    asn1格式的16进制字符串:asn1: 3081e830790220467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da40502210099f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d804204452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714b0410443c9a3f4f7b0083ddd323d6a1f57650303e06082a811ccf550168020410b63a85e103d362fb6247c19e324e97c4042098fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea0010706092a811ccf55018311010420aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79
    SM2参数:xCoordinate: 467b2389364b2ebd2eadfa624d668c9b0d530b89edbaf9676c1d7db18c7da405yCoordinate: 99f160a4fc540baa3c316e0b28db789f366fc4c84ba1a98e3aaf0806667a82d8hash: 4452c9104b87f44ac026d449cb5b5b5f306b2deab5187db7b3cb845659b1714bcipherText: 443c9a3f4f7b0083ddd323d6a1f57650
    SM4参数:algorithm: 1.2.156.10197.1.104.2iv: b63a85e103d362fb6247c19e324e97c4cipherText: 98fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea00107
    SM3参数:digestAlgorithm: 1.2.156.10197.1.401.1digest: aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79
    """
    
  • 针对于此等加密,刚学完课程《密码学概论》的我,当前安全且高效的通信加密技术,赛场上看着这道题非常怅惘。后续看到大佬的解题思路如下:针对于国密算法以及数字信封的实现上而言,我们很难找到其漏洞点,但是出了穷举攻击以外,可能出现的漏洞点就在于分组密码的CBC工作模式。由于给出的明密文对的长度很长,而我们要恢复的密文却很短。cipherText = "98fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea00107"

  • 看到languag3师傅的博客,同时验证待解密密文的第一组密文在明密文对的密文中存在,那么可以判断此处在黑盒处理之前,两者对应的分组的keyinput是相同的,则通过异或处理可以恢复明文的第一块。但是并不能推出该组黑盒使用的key以及其他分组的keyinput的关系。

  • 此后怎对于后续的16字节进行爆破,即为32bit的abcd爆破。

exp

# part1 Solve
from pwn import xor
m1 = "6362646264646264646361636463646261636164626362646264616161636162636261616461646263626362626264636163616264626164616161616361616161636163636361626463616361626263626263646462626261616462646362626162646162646461646264626361646264636164626262626264646464626362626462626364646463636362636264616161636461626363626362616263636264636164636261646262626161636161616461616163616461626461646464616363646462636464646464636462636264636464636162616461646263646264636363616263616164646263646362646161616361646261616161626261626462636261646362626362626462636463616164636263646164636461646364646464616461626463616463636362626464646463636461626264636363636263646463626163636362646264616261636464626164646363626164626264616462626264646463646163646162626364616264646163636362646164616263616461626164636261646361636162616162646161646162636364646162626361646362646361626463616262646362636261616464626162636161616362616464616261626363616464626164616362616262616463626364646461636461636164636261626364646362626263636164626161636264646261636264626164626264636463616263646462646464636461626264626262626263626362636463636362636264646262626162626364616363636264626462636163646361636163616464626361616262646361626261646364646461636164626164646361626264616364626361636163626163636363626464626462646364646364616461616161616361646264626364636364626261636363636361616264636262646262616263636361616361616261616162636163646363646264636364616362626362626463616264646261626164646263646164646264616463646462626261616461636461626262636462646163636461646362616363616163616361626162636462616362636361646363626161636362636361616261636362636463"
c1 = "d76516cc03294caaa08df866f53ac3ddc8331f5aa82c09d1ae49c41746165293d70f8d2e7578e4a6c59c9a2adb7b446fd7139e6e1d9f4fef7dca09425b574dfd30c24d773c59bcd86384f013439e7b0f61439192f9b7889a72d4fb59d20eaa7dc7191594aa5cdb855410f0b6be69cb5eb5f303a605300d48c8ca0b86549ba2c586009fa7a24e4b71a2c304aa34f9a6cb45d1e5d97e6d768dd63a1bfbe7a975be13585742aed7e3e606450530c05c0cd1c41dea44603f628bc2398cdd706abb66ca964178122b99c879bf1ded48268f662cbb1d06798e19ecb61c5719fd85b4bf72b25226778632e4510009f101a50fc66ef8f12088357ccac4749262f2eb07b6ea6d800ed3897a02d530b0e6f22b378354edddd8bf4a8df07d020986c1f49570853f4875e00fac96b2f8054288ebebb4d86ebfb644f53b1195fc2ff04effe18d419da605ba949ff7a3cc3624fdb71af173a8b8e0c721ff0095f1cfb08d1f236835013811502da499408de1ed0d329027d65b62790043f0b2f67a71f2056ca1c2e431147b145d8817b86a49d08e82c5d710e999078fa8bc1144bb77654a53d91591522540f3ac835ad1df444f94db2c07f223be6db215034ef39c2123690d0457877c40ea91f5662f2efb57cefa4d8b3bb6ce18bed2de4de3c8d53c9bd2f0be84471a88719f74a3e2193915db3c455c597e897ada24e6c3e628e03416a759ed1a7886525569a2b7e7431311504e27add6b43d85e704d364fe6446c29c314e95c498fea6b8123d811480a1add915a34d4ffeda304e0ee8456f842786a385eaac42c0beec3b37d30906a982340a1a9a0151eca11040fd2c467a8a014e2db9ccec96f0d927208de545fddd0cae8b7da3ce113d0ac95fb84ec74ed266ae8676ac662f21bb93034064a043e5969c378e825b3751d6c54e9d8d79a905c942857103564ce7ed5c61c899420d02170f42e41e3193cd5de116701c59043fc42ec596fc8cd05c75ed9fd514c9323ce01143b84080cc2d81ac477c7c2a9ef97ea0b76159fc2ea24e18c8511046f4e500d1653b16b71f0a1028155173a11c55e777dd13c23e67f9fa5e6a8c32162dcf01b09a3c50c106c63d13ce2a9e2fff014665ec490f9477"
c = "98fea6b8123d811480a1add915a34d4fdbbfd86515a457e1b20bf4751ea00107"
iv1 = "f414bdfbca9d9e902114536a3b9c4432"
iv = "b63a85e103d362fb6247c19e324e97c4"
# print(len(c)) 64 -- 分组后为2组
c_list = [c[32 * i:32 * (i + 1)] for i in range(2)]
# print(c_list)
# print(c1.index(c_list[0])); print(c1.index(c_list[1])) 1088 Error
# Black Cipher Encrypt之前的结果相同
temp = bytes.fromhex(m1[1088:1088 + 32])
c1_block = bytes.fromhex(c1[1088 - 32:1088])
iv = bytes.fromhex(iv)
m_part1 = xor(xor(c1_block, temp), iv)
# print(m_part1) adcddbbadcacabad
// part2 Solve
#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <chrono>
#include <cstring>
#include <openssl/evp.h>
#include <mutex>
#include <condition_variable>using namespace std;// 线程通信全局变量
bool found = false;
mutex mtx; // 信号量
condition_variable cv;// 字符集以及前16个字节内容固定
const unsigned char char_set[] = "adcddbbadcacabad";
const unsigned char char_map[] = "abcd";
const string tar_hex = "aab05fca300811223b3b957bfe33130770fb7a6b55b030a5809c559344f66f79";// 生成索引对应的16字节字符
void index_to_char(uint64_t index, unsigned char *result)
{int len = 0;while (len < 15){result[len++] = char_map[index % 4];index /= 4;}result[len] = char_map[index];
}// 有结果后终止线程
bool should_terminate()
{lock_guard<mutex> lock(mtx);return found;
}// 线程
void thread_worker(uint64_t j)
{const size_t prefix_len = strlen(reinterpret_cast<const char *>(char_set));vector<unsigned char> data(prefix_len + 16);memcpy(data.data(), char_set, prefix_len);unsigned char hash[32];char hash_hex[65];hash_hex[64] = '\0';for (uint64_t i = 0; i <= 0xffffff; ++i){if (should_terminate()){return;}const uint64_t index = (j << 24) + i;unsigned char suffix[16];index_to_char(index, suffix);memcpy(data.data() + prefix_len, suffix, 16);// 计算SM3哈希EVP_MD_CTX *ctx = EVP_MD_CTX_new();EVP_DigestInit_ex(ctx, EVP_sm3(), nullptr);EVP_DigestUpdate(ctx, data.data(), data.size());EVP_DigestFinal_ex(ctx, hash, nullptr);EVP_MD_CTX_free(ctx);// 转换哈希结果为十六进制字符串for (int k = 0; k < 32; ++k){snprintf(hash_hex + 2 * k, 3, "%02x", hash[k]);}// 检查是否匹配目标哈希if (tar_hex == hash_hex){// 找到匹配项,设置全局标志并通知主线程{lock_guard<mutex> lock(mtx);found = true;cout << "Found: " << string(reinterpret_cast<char *>(data.data()), data.size()) << endl;}cv.notify_one(); // 通知主线程return;}}
}int main()
{auto start_time = chrono::high_resolution_clock::now();vector<thread> threads;threads.reserve(256);// 创建线程for (uint64_t j = 0; j <= 0xff; ++j){threads.emplace_back(thread_worker, j);}// 等待找到结果或所有线程完成unique_lock<mutex> lock(mtx);cv.wait(lock, []{ return found; });// 找到结果后终止线程for (auto &t : threads){if (t.joinable()){t.join();}}// 计算并输出耗时auto end_time = chrono::high_resolution_clock::now();chrono::duration<double> elapsed = end_time - start_time;cout << "Time taken: " << elapsed.count() << " seconds" << endl;return 0;
}
// flag{adcddbbadcacabadcbbbbaaaabcbcabd}

初始谜题2

sm2_verify

import binascii
from datetime import datetime
from pyasn1.type import univ, namedtype
from pyasn1.codec.der.encoder import encode
from pyasn1.codec.der.decoder import decode
from gmssl import sm2
from pyasn1.codec.der import decoder, encoder
from pyasn1_modules import rfc2459
from gmssl.sm2 import CryptSM2
from pyasn1.type.useful import GeneralizedTime
from pyasn1.type.univ import Sequence
from pyasn1.type import usefulclass ECPrimeFieldConfig(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('fieldType', univ.ObjectIdentifier('1.2.840.10045.1.1')),  # Prime field OIDnamedtype.NamedType('prime', univ.Integer()),  # Prime number p)class ECCurveParameters(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('coefficientA', univ.OctetString()),  # Curve coefficient anamedtype.NamedType('coefficientB', univ.OctetString()),  # Curve coefficient b)class ECDomainParameters(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('version', univ.Integer(1)),  # Version number (1)namedtype.NamedType('fieldParameters', ECPrimeFieldConfig()),  # Field parameters 包含参数oid,pnamedtype.NamedType('curveParameters', ECCurveParameters()),  # Curve parameters 包含参数a,bnamedtype.NamedType('basePoint', univ.OctetString()),  # Base point G 基点namedtype.NamedType('order', univ.Integer()),  # Order n of base point 参数nnamedtype.NamedType('cofactor', univ.Integer(1)),  # Cofactor 余因子 固定值为1)class SM2SignatureValue(univ.Sequence):componentType = namedtype.NamedTypes(namedtype.NamedType('r', univ.Integer()),  # First part of signaturenamedtype.NamedType('s', univ.Integer()),  # Second part of signature)class SM2SignedData(univ.Sequence):componentType = namedtype.NamedTypes(# versionnamedtype.NamedType('version', univ.Integer()),# 哈希算法 OID(SM3)namedtype.NamedType('digestAlgorithms', univ.ObjectIdentifier()),# 签名值 r, snamedtype.NamedType('sm2Signature', SM2SignatureValue()),# 曲线参数namedtype.NamedType('ecDomainParameters', ECDomainParameters()),# 证书namedtype.NamedType('certificate', univ.OctetString()),# 签名时间namedtype.NamedType('timestamp', GeneralizedTime()),)# 输入值全部为16进制字符串,g为x,y坐标的16进制字符串进行拼接
# p,a,b,n,g对应曲线参数;r,s为签名值的两部分
def asn1_package(version, oid, signature, curve_params, cert_hex, time_stamp):sm2_signed_data = SM2SignedData()# versionsm2_signed_data['version'] = version# 哈希算法 OID(SM3)sm2_signed_data['digestAlgorithms'] = oid# 签名值 r, ssm2_signed_data["sm2Signature"] = SM2SignatureValue()sm2_signed_data["sm2Signature"]['r'] = int(signature[:64], 16)sm2_signed_data["sm2Signature"]['s'] = int(signature[64:], 16)# 曲线参数sm2_signed_data["ecDomainParameters"] = ECDomainParameters()sm2_signed_data["ecDomainParameters"]["fieldParameters"] = ECPrimeFieldConfig()sm2_signed_data["ecDomainParameters"]["fieldParameters"]["prime"] = int(curve_params['p'], 16)sm2_signed_data["ecDomainParameters"]["curveParameters"] = ECCurveParameters()sm2_signed_data["ecDomainParameters"]["curveParameters"]["coefficientA"] = univ.OctetString(bytes.fromhex(curve_params['a']))sm2_signed_data["ecDomainParameters"]["curveParameters"]["coefficientB"] = univ.OctetString(bytes.fromhex(curve_params['b']))sm2_signed_data["ecDomainParameters"]['basePoint'] = univ.OctetString(bytes.fromhex('04' + curve_params['g']))sm2_signed_data["ecDomainParameters"]['order'] = int(curve_params['n'], 16)# 证书sm2_signed_data["certificate"] = univ.OctetString(bytes.fromhex(cert_hex))# 时间dt = datetime.strptime(time_stamp, "%Y-%m-%d %H:%M:%S")asn1_time_str = dt.strftime("%Y%m%d%H%M%SZ")sm2_signed_data["timestamp"] = GeneralizedTime(asn1_time_str)return encode(sm2_signed_data).hex()class Sm2CertVerifier:def __init__(self, cert_hex: str):ca_pubkey = "8E1860588D9900C16BD19A0FE0A5ACC600224DBD794FFD34179E03698D52421F46E6D8C6E8AADE512C7B543395AC39C76384726C7F8BA537ABCA0C129ECD9882"self.sm2_crypt = sm2.CryptSM2(public_key=ca_pubkey, private_key=None)self.cert_tbs, self.signature_bytes, self.cert = self.parse_cert(bytes.fromhex(cert_hex))@staticmethoddef parse_cert(cert_der_bytes: bytes):cert, _ = decoder.decode(cert_der_bytes, asn1Spec=rfc2459.Certificate())tbs = cert.getComponentByName('tbsCertificate')signature_bytes = cert.getComponentByName('signatureValue').asOctets()return tbs, signature_bytes, cert# 获取签名值def decode_rs_from_der(self, signature: bytes) -> bytes:seq, _ = decode(signature, asn1Spec=Sequence())r = int(seq[0])s = int(seq[1])r_bytes = r.to_bytes(32, byteorder='big')s_bytes = s.to_bytes(32, byteorder='big')return r_bytes + s_bytesdef verify_signature(self, signature: bytes, tbs: str):inter_cert_tbs_der = encoder.encode(tbs)inter_signature = self.decode_rs_from_der(signature)# 验证签名(tbs_der必须完整,签名必须64字节)return self.sm2_crypt.verify_with_sm3(inter_signature.hex(), inter_cert_tbs_der)def verify_certificate_expiration_date(self, tbs):validity = tbs.getComponentByName('validity')not_before = validity.getComponentByName('notBefore').getComponent()not_after = validity.getComponentByName('notAfter').getComponent()# 处理 UTCTime 和 GeneralizedTime 两种类型if isinstance(not_before, useful.UTCTime):not_before_time = datetime.strptime(str(not_before), "%y%m%d%H%M%SZ")elif isinstance(not_before, useful.GeneralizedTime):not_before_time = datetime.strptime(str(not_before), "%Y%m%d%H%M%SZ")else:raise ValueError("Unsupported notBefore time format")if isinstance(not_after, useful.UTCTime):not_after_time = datetime.strptime(str(not_after), "%y%m%d%H%M%SZ")elif isinstance(not_after, useful.GeneralizedTime):not_after_time = datetime.strptime(str(not_after), "%Y%m%d%H%M%SZ")else:raise ValueError("Unsupported notAfter time format")now = datetime.now()return not_before_time <= now <= not_after_timedef verify(self):# 验证中间证书有效期if not self.verify_certificate_expiration_date(self.cert_tbs):print("证书已过期或尚未生效")return False# 验证中间证书签名if not self.verify_signature(self.signature_bytes, self.cert_tbs):print("证书验证未通过")return Falsereturn Trueclass SM2Config:# sm2参数初始化def __init__(self, asn1_str):self.sm2_signed_data,asn1_acess = self.hex_to_asn1(asn1_str, SM2SignedData())if len(asn1_acess) != 0:raise ValueError("asn1长度有问题")cert_hex = self.get_hex_value(self.sm2_signed_data['certificate'])sm2_cert_verifier = Sm2CertVerifier(cert_hex)valid = sm2_cert_verifier.verify()if not valid:raise TypeError("证书验证不通过")g = self.get_hex_value(self.sm2_signed_data['ecDomainParameters']['basePoint'])g = g[2:] if g.startswith("04") else gself.ecc_table = {'n': self.get_hex_value(self.sm2_signed_data['ecDomainParameters']['order']),'p': self.get_hex_value(self.sm2_signed_data['ecDomainParameters']['fieldParameters']['prime']),'g': g,'a': self.get_hex_value(self.sm2_signed_data['ecDomainParameters']['curveParameters']['coefficientA']),'b': self.get_hex_value(self.sm2_signed_data['ecDomainParameters']['curveParameters']['coefficientB']),}public_key = self.extract_public_key(sm2_cert_verifier.cert_tbs)self.sm2_crypt = CryptSM2(private_key="",public_key=public_key,ecc_table=self.ecc_table)self.sign = (int(self.sm2_signed_data['sm2Signature']['r']).to_bytes(32, 'big').hex().upper() +int(self.sm2_signed_data['sm2Signature']['s']).to_bytes(32, 'big').hex().upper())@staticmethoddef hex_to_asn1(hex_str, asn1_spec):"""将16进制字符串转换回ASN.1对象:param hex_str: 16进制字符串:param asn1_spec: ASN.1结构定义:return: ASN.1对象"""# 将16进制字符串转换为字节der_bytes = binascii.unhexlify(hex_str)# 解码为ASN.1对象asn1_object, excess = decode(der_bytes, asn1Spec=asn1_spec)return asn1_object,excess@staticmethoddef get_hex_value(value):"""通用转换函数:将 ASN.1 值转换为 16 进制字符串(大写,无前缀)"""if isinstance(value, univ.Integer):return format(int(value), 'X')  # Integer -> 直接转十六进制elif isinstance(value, univ.OctetString):return value.asOctets().hex().upper()  # OctetString -> 字节转十六进制else:raise TypeError(f"Unsupported type: {type(value)}")@staticmethoddef extract_public_key(tbs):spki = tbs.getComponentByName('subjectPublicKeyInfo')public_key_bitstring = spki.getComponentByName('subjectPublicKey')# 提取位串内容(包含开头的 0x04)pubkey_bytes = bytearray(public_key_bitstring.asOctets())# 转成十六进制字符串return pubkey_bytes.hex()def verify_misc(self):if (int(self.sm2_signed_data['version']) != 1 orstr(self.sm2_signed_data['digestAlgorithms']) != '1.2.156.10197.1.401.1' orstr(self.sm2_signed_data['timestamp']) != "20250520101000Z"):return Falsereturn True# sm2验签def verify(self, data):valid = self.verify_misc()if not valid:return validvalid = self.sm2_crypt.verify_with_sm3(self.sign, data)return valid# 通过该函数可以产生一个合法的SM2SignedData
def generateSM2SignedDataExample():# 版本version = 1# 哈希算法oidoid = '1.2.156.10197.1.401.1'# 签名值r, ssignature = '6f8eaff551d0f3fa6de74b75b33e1e58f9fdb4dc58e61c82e11e717ffcf168c4db3d5a90ff3625d12b8b658f8dbab34340c278b412b3aff25489e7feb1c75598'r = signature[:64]s = signature[64:]# 曲线参数curve_params = {"n": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',"p": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF',"g": '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0',"a": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',"b": '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',}# 证书cert_hex = '3082017C30820122A003020102020D00947C8427D3E849B48A7E5136300A06082A811CCF550183753036310B300906035504061302434E31133011060355040A130A5368616E674D6942656931123010060355040313095368616E674D694341301E170D3235303532303035353330365A170D3330303531393035353330365A304D310B300906035504061302434E3110300E060355040A1307496E746572434131173015060355040B130E5368616E674D6942656932303235311330110603550403130A7368616E676D696265693059301306072A8648CE3D020106082A811CCF5501822D03420004CECC0005AED684A1E7E39C316E7F3F39BDD0490936BC0E1AFDDC1B9627A05B4418809E5327746EE1977913F036EF0A9A255C27D73C00E45D0BB205B34D2C80D4300A06082A811CCF5501837503480030450220360779CBF5AA6E5E9CC073D95E22C52C09E81CFC06A3916559063A3C8C1DFDE6022100ED0E5E5E51F3894A3EAC11F247739D9F6A88C961D89F68337972BC3CC6BB6706'  # 证书16进制格式# 时间time_stamp = '2025-05-20 10:10:00'# asn1封装asn1_package_hex = asn1_package(version, oid, signature, curve_params, cert_hex, time_stamp)return(asn1_package_hex)if __name__ == '__main__':# 验签data = b"Hello, CryptoCup!"asn1_package_hex = generateSM2SignedDataExample()sm2_config = SM2Config(asn1_package_hex)result = sm2_config.verify(data)print(result)

SM2SignedData

308202CD02010106092A811CCF5501831101304502206F8EAFF551D0F3FA6DE74B75B33E1E58F9FDB4DC58E61C82E11E717FFCF168C4022100DB3D5A90FF3625D12B8B658F8DBAB34340C278B412B3AFF25489E7FEB1C755983081E0020101302C06072A8648CE3D0101022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF30440420FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC042028E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E9304410432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123020101048201803082017C30820122A003020102020D00947C8427D3E849B48A7E5136300A06082A811CCF550183753036310B300906035504061302434E31133011060355040A130A5368616E674D6942656931123010060355040313095368616E674D694341301E170D3235303532303035353330365A170D3330303531393035353330365A304D310B300906035504061302434E3110300E060355040A1307496E746572434131173015060355040B130E5368616E674D6942656932303235311330110603550403130A7368616E676D696265693059301306072A8648CE3D020106082A811CCF5501822D03420004CECC0005AED684A1E7E39C316E7F3F39BDD0490936BC0E1AFDDC1B9627A05B4418809E5327746EE1977913F036EF0A9A255C27D73C00E45D0BB205B34D2C80D4300A06082A811CCF5501837503480030450220360779CBF5AA6E5E9CC073D95E22C52C09E81CFC06A3916559063A3C8C1DFDE6022100ED0E5E5E51F3894A3EAC11F247739D9F6A88C961D89F68337972BC3CC6BB6706180F32303235303532303130313030305A

analysis

  • 题目中实现了一个SM2的签名系统,而我们获取得到flag的关键就在于对指定信息进行签名通过交互验签程序的比对。因此task就转移到我们怎么写一个能通过验签函数的签名函数。注:证书为固定内容,也就意味着公钥固定不能进行修改。

  • 针对于签名函数而言,我们查看gmssl.sm2源码之后发现,签名需要找到私钥,但是目前我们只知道公钥以及其签名时使用的基点G以及经过私钥计算之后的公钥,根据sm2的签名过程中的密钥生成方式:
    确定a,b,p后选择点P作为基点,选择d且计算Q=d∗P,其中d为私钥,P为公钥。 确定a,b,p后选择点P作为基点,选择d且计算Q=d*P,其中d为私钥,P为公钥。 确定a,b,p后选择点P作为基点,选择d且计算Q=dP,其中d为私钥,P为公钥。

  • 因此我们自己伪造私钥即可,但是需要满足私钥和公钥的关系,那么我们在曲线上找到我们所选择的私钥d的逆元点即可进行签名验证。

exp

# 伪造私钥,确定相应私钥的基点
from sage.all import *curve_params = {"n": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',"p": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF',"a": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',"b": '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
}pk = "8E1860588D9900C16BD19A0FE0A5ACC600224DBD794FFD34179E03698D52421F46E6D8C6E8AADE512C7B543395AC39C76384726C7F8BA537ABCA0C129ECD9882"p = int(curve_params['p'], 16)
a = int(curve_params['a'], 16)
b = int(curve_params['b'], 16)
n = int(curve_params['n'], 16)
E = EllipticCurve(GF(p), [a, b])Q = E(int(pk[:64], 16), int(pk[64:], 16))sk = 2
G = Q * inverse_mod(sk, n)print(G)
# (69820663585833773923605819432869967907739933733211104912986148573209369246123 : 76928629769251499992251494960564507419350106546363535365017317636758007136702 : 1)
# 利用伪造私钥和基点仿造签名
from gmssl.sm2 import CryptSM2curve_params = {"n": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',"p": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF',"g": "9a5d185c2d305a22641a68c2c637924ae27921e02019213d08788bffa8bff9abaa140fbb0a66d0166463e801113b9ef38198f2918e053902bb67b018476341be","a": 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',"b": '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
}sm2_crypt = CryptSM2(private_key = "2", public_key = "cecc0005aed684a1e7e39c316e7f3f39bdd0490936bc0e1afddc1b9627a05b4418809e5327746ee1977913f036ef0a9a255c27d73c00e45d0bb205b34d2c80d4", ecc_table=curve_params)data = b'EUWJSFTFHGQEQVRXZHJYKPUXDPUMRDQQ'
signature = sm2_crypt.sign_with_sm3(data)
print(f"signature: {signature}")
# signature: c0f36fe86a81a061139252f518b51651397d517799f30e3dece0acb762f497c3693297c721cbb0d778856e2c2b4cea9cfe0af6a4548f4c29be03688f071fe4f6

初始谜题3

xmss_verify.py

from typing import List, Callable
from hashlib import sha256def hex_to_32byte_chunks(hex_str):# 确保十六进制字符串长度是64的倍数(因为32字节 = 64个十六进制字符)if len(hex_str) % 64 != 0:raise ValueError("十六进制字符串长度必须是64的倍数")# 每64个字符分割一次,并转换为字节return [bytes.fromhex(hex_str[i:i + 64]) for i in range(0, len(hex_str), 64)]def openssl_sha256(message: bytes) -> bytes:return sha256(message).digest()class WOTSPLUS:def __init__(self,w: int = 16,  # Winternitz 参数,控制空间与时间的复杂度hashfunction: Callable = openssl_sha256,  # 哈希函数digestsize: int = 256,  # 摘要大小,单位为比特pubkey: List[bytes] = None,) -> None:self.w = wif not (2 <= w <= (1 << digestsize)):raise ValueError("规则错误:2 <= w <= 2^digestsize")# 消息摘要所需的密钥数量(默认8个)self.msg_key_count = 8# 校验和密钥数量self.cs_key_count = 0# 总密钥数量 = 消息密钥 + 校验和密钥self.key_count = self.msg_key_count + self.cs_key_countself.hashfunction = hashfunctionself.digestsize = digestsizeself.pubkey = pubkey@staticmethoddef number_to_base(num: int, base: int) -> List[int]:if num == 0:return [0]  # 如果数字是 0,直接返回 0digits = []  # 存储转换后的数字位while num:digits.append(int(num % base))  # 获取当前数字在目标进制下的个位,并添加到结果列表num //= base  # 对数字进行整除,处理下一位return digits[::-1]  # 返回按顺序排列的结果def _chain(self, value: bytes, startidx: int, endidx: int) -> bytes:for i in range(startidx, endidx):value = self.hashfunction(value)  # 每次迭代对当前哈希值进行哈希操作return valuedef get_signature_base_message(self, msghash: bytes) -> List[int]:# 将消息哈希从字节转换为整数msgnum = int.from_bytes(msghash, "big")# 将消息的数字表示转换为特定进制下的比特组表示msg_to_sign = self.number_to_base(msgnum, self.w)# 校验消息比特组的数量是否符合预期if len(msg_to_sign) > self.msg_key_count:err = ("The fingerprint of the message could not be split into the"+ " expected amount of bitgroups. This is most likely "+ "because the digestsize specified does not match to the "+ " real digestsize of the specified hashfunction Excepted:"+ " {} bitgroups\nGot: {} bitgroups")raise IndexError(err.format(self.msg_key_count, len(msg_to_sign)))return msg_to_signdef get_pubkey_from_signature(self, digest: bytes, signature: List[bytes]) -> List[bytes]:msg_to_verify = self.get_signature_base_message(digest)result = []for idx, val in enumerate(msg_to_verify):sig_part = signature[idx]chained_val = self._chain(sig_part, val, self.w - 1)result.append(chained_val)return resultdef verify(self, digest: bytes, signature: List[bytes]) -> bool:pubkey = self.get_pubkey_from_signature(digest, signature)return True if pubkey == self.pubkey else Falseif __name__ == "__main__":pubkey_hex = "5057432973dc856a7a00272d83ea1c14de52b5eb3ba8b70b373db8204eb2f902450e38dbade5e9b8c2c3f8258edc4b7e8101e94ac86e4b3cba92ddf3d5de2a2b454c067a995060d1664669b45974b15b3423cec342024fe9ccd4936670ec3abaae4f6b97279bd8eb26463a8cb3112e6dcbf6301e4142b9cdc4adfb644c7b114af4f0cf8f80e22c3975ba477dc4769c3ef67ffdf2090735d81d07bc2e6235af1ee41ef332215422d31208c2bc2163d6690bd32f4926b2858ca41c12eec88c0a300571901a3f674288e4a623220fb6b70e558d9819d2f23da6d897278f4056c346d7f729f5f70805ad4e5bd25cfa502c0625ac02185e014cf36db4ebcdb3ed1a38"pubkey_list_bytes = hex_to_32byte_chunks(pubkey_hex)wots = WOTSPLUS(pubkey = pubkey_list_bytes)digest_hex = "84ffb82e"signature_hex = "25d5a0e650d683506bfe9d2eca6a3a99b547a4b99398622f6666ce10131e971b6bd36841c9074fe9b4de2900ebe3fadb3202a173be486da6cf8f3d8c699c95c3454c067a995060d1664669b45974b15b3423cec342024fe9ccd4936670ec3abaae4f6b97279bd8eb26463a8cb3112e6dcbf6301e4142b9cdc4adfb644c7b114a4966398a789b56bdb09ea195925e7e8cde372305d244604c48db08f08a6e8a38951030deb25a7aaf1c07152a302ebc07d5d0893b5e9a5953f3b8500179d138b9aa90c0aaacea0c23d22a25a86c0b747c561b480175b548fcb1f4ad1153413bc74d9c049d43ffe18ceee31e5be8bdb9968103ef32fb4054a4a23c400bbfe0d89f"digest_bytes = bytes.fromhex(digest_hex)signature = hex_to_32byte_chunks(signature_hex)valid = wots.verify(digest_bytes,signature)print(valid)

analysis

  • 针对于这道题而言,从wots.verify一步步跟进发现这道题,给出公钥,输入信息摘要以及其针对于该信息的签名值。
  • 跟进get_pubkey_from_signature发现该签名的流程是对sig_part进行x次的哈希,返回的结果作为签名值。这里考虑到哈希函数的不可逆性,所以我们就要把思路转换到恶意伪造签名上而非进行由公钥进行求解私钥再进行计算。
  • 随之发现其中_chain操作的次数与所传入的参数信息摘要的每一位有关,可以输出其中的参数msg_to_verify进行验证。
  • 因此,我们可以恶意伪造信息摘要为ffffffff,使其_chain操作次数均为0,那么签名值就是未经操作的公钥,伪造成功交互获取flag即可。
  • 看到languag3师傅的wp才知晓该签名验签程序为OTS签名,更能明白些许原理以及这样考虑的思路,更具指导性。

写在最后

  • 第一次参加熵密杯,题目质量很高,比起以往的CTF中的密码学方向的题目而言,课本上的知识得到了时间并且针对于加密算法的漏洞攻击而言,更加使用的签名和实用化的场景下进行的题目更加具有实际意义。
  • 本次比赛只解出了初始谜题3,第一次使用gmsll库,发现了该库简直是密码学应用的天然宝库。但是由于自己太菜了,没有享受到密码学的快乐,坐牢ed.
  • 因为比赛时全程都在看初始谜题,flag也因为实力太弱没能求解,同时对于Go的审计能力几乎为0,后续题解就不再记录,留个坑。还得xue…
http://www.lryc.cn/news/607801.html

相关文章:

  • 进阶向:自动化天气查询工具(API调用)
  • stm32是如何实现电源控制的?
  • 【7.5 Unity AssetPostprocessor】
  • 2-5 Dify案例实践—利用RAG技术构建企业私有知识库
  • 【最新区块链论文录用资讯】CCF A--WWW 2025 23篇
  • 第三章 用户和权限
  • 【C++】第二十一节—一文详解 | 红黑树实现(规则+效率+结构+插入+查找+验证)
  • 【RK3568 RTC 驱动开发详解】
  • 网安-中间件(updating..)
  • jenkins从入门到精通-P1—九五小庞
  • 【机器学习】非线性分类算法详解(下):决策树(最佳分裂特征选择的艺术)与支持向量机(最大间隔和核技巧)
  • Docker 的网络模式
  • OTC焊接机器人节能技巧
  • Python 第一阶段测试题 答案及解析
  • 机器学习【五】decision_making tree
  • 高性能MCP服务器架构设计:并发、缓存与监控
  • 淘宝小程序的坑
  • Clickhouse#表记录转换为insert语句
  • 【机器学习】“回归“算法模型的三个评估指标:MAE(衡量预测准确性)、MSE(放大大误差)、R²(说明模型解释能力)
  • Human Brain Mapping:静息态功能磁共振成像的回归动态因果建模
  • C语言(长期更新)第7讲:VS实用调试技巧
  • ADB 底层原理
  • Android 运行 deno 的新方法 (3): Termux 胖喵安初
  • 【Leetcode hot 100】49.字母异位词分组
  • [mssql] 分析SQL Server中执行效率较低的SQL语句
  • imx6ull-驱动开发篇6——Linux 设备树语法
  • 快速了解决策树
  • 四、Portainer图形化管理实战与Docker镜像原理
  • 音视频学习(四十五):声音的产生
  • 图漾相机-ROS1_SDK_ubuntu 4.X.X版本编译