很好,属于是来重庆旅游来了,先爆一下战绩,初始谜题做了一个,差点爆零(bushi)

去年还能做两个初始谜题,后面的夺旗闯关还能有点思路,就是不会写而已

今年的夺旗闯关就真不会了,看得懂一点,但具体不知道要干嘛,证书 sm4 sm2 什么的不会啊

Rank: 90+/205,去年好像也是90多,但今年参赛队伍多了不少,难度也难了不少,都没人AK了(),去年四五支队伍AK,我那一列就两三个……

初始谜题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 encode


class 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 OID
namedtype.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算法OID
namedtype.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) #填充模式 nopadding
encryptor = cipher.encryptor()
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
return ciphertext

def 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 ciphertext

def sm3_hash(text:bytes):
hash_value = sm3.sm3_hash(func.bytes_to_list(text))
return hash_value

def read_key_from_file(file_path):
try:
with open(file_path, 'r') as file:
key = file.read().strip()
return key
except 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
# sm4
envelope = EnvelopedData()
plaintext_bytes = plaintext.encode('utf-8')
ciphertext = sm4_cbc_encrypt(plaintext_bytes,sm4_key,bytes.fromhex(sm4_iv))

# sm2
encrypted_key = sm2_encrypt(sm4_key,bytes.fromhex(sm2_public_key))

# sm3
digest = 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)
# sm2
sm2_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()

# sm4
sm4_algorithm = str(enveloped_data['encryptedData']['algorithm'])
sm4_iv = enveloped_data['encryptedData']['iv'].asOctets().hex()
sm4_cipherText = enveloped_data['encryptedData']['cipherText'].asOctets().hex()

# sm3
digestAlgorithm = 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())

初始谜题2*

# sm2_verify.py
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 useful


class ECPrimeFieldConfig(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('fieldType', univ.ObjectIdentifier('1.2.840.10045.1.1')), # Prime field OID
namedtype.NamedType('prime', univ.Integer()), # Prime number p
)


class ECCurveParameters(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('coefficientA', univ.OctetString()), # Curve coefficient a
namedtype.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,p
namedtype.NamedType('curveParameters', ECCurveParameters()), # Curve parameters 包含参数a,b
namedtype.NamedType('basePoint', univ.OctetString()), # Base point G 基点
namedtype.NamedType('order', univ.Integer()), # Order n of base point 参数n
namedtype.NamedType('cofactor', univ.Integer(1)), # Cofactor 余因子 固定值为1
)


class SM2SignatureValue(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('r', univ.Integer()), # First part of signature
namedtype.NamedType('s', univ.Integer()), # Second part of signature
)


class SM2SignedData(univ.Sequence):
componentType = namedtype.NamedTypes(
# version
namedtype.NamedType('version', univ.Integer()),
# 哈希算法 OID(SM3)
namedtype.NamedType('digestAlgorithms', univ.ObjectIdentifier()),
# 签名值 r, s
namedtype.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()
# version
sm2_signed_data['version'] = version
# 哈希算法 OID(SM3)
sm2_signed_data['digestAlgorithms'] = oid
# 签名值 r, s
sm2_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))

@staticmethod
def 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_bytes

def 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_time

def 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 False
return True


class 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 g
self.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())

@staticmethod
def 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

@staticmethod
def 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)}")

@staticmethod
def 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 or
str(self.sm2_signed_data['digestAlgorithms']) != '1.2.156.10197.1.401.1' or
str(self.sm2_signed_data['timestamp']) != "20250520101000Z"):
return False
return True

# sm2验签
def verify(self, data):
valid = self.verify_misc()
if not valid:
return valid
valid = self.sm2_crypt.verify_with_sm3(self.sign, data)
return valid


# 通过该函数可以产生一个合法的SM2SignedData
def generateSM2SignedDataExample():
# 版本
version = 1
# 哈希算法oid
oid = '1.2.156.10197.1.401.1'
# 签名值r, s
signature = '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)
"""
308202CD02010106092A811CCF5501831101304502206F8EAFF551D0F3FA6DE74B75B33E1E58F9FDB4DC58E61C82E11E717FFCF168C4022100DB3D5A90FF3625D12B8B658F8DBAB34340C278B412B3AFF25489E7FEB1C755983081E0020101302C06072A8648CE3D0101022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF30440420FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC042028E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E9304410432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0022100FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123020101048201803082017C30820122A003020102020D00947C8427D3E849B48A7E5136300A06082A811CCF550183753036310B300906035504061302434E31133011060355040A130A5368616E674D6942656931123010060355040313095368616E674D694341301E170D3235303532303035353330365A170D3330303531393035353330365A304D310B300906035504061302434E3110300E060355040A1307496E746572434131173015060355040B130E5368616E674D6942656932303235311330110603550403130A7368616E676D696265693059301306072A8648CE3D020106082A811CCF5501822D03420004CECC0005AED684A1E7E39C316E7F3F39BDD0490936BC0E1AFDDC1B9627A05B4418809E5327746EE1977913F036EF0A9A255C27D73C00E45D0BB205B34D2C80D4300A06082A811CCF5501837503480030450220360779CBF5AA6E5E9CC073D95E22C52C09E81CFC06A3916559063A3C8C1DFDE6022100ED0E5E5E51F3894A3EAC11F247739D9F6A88C961D89F68337972BC3CC6BB6706180F32303235303532303130313030305A
"""

"""
待签名消息(字符串):
TYTNGLNVKYDLVCGTUYUARFLEFKLAKAZO
"""

初始谜题3

from typing import List, Callable
from hashlib import sha256


def 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 = w
if 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_count
self.hashfunction = hashfunction
self.digestsize = digestsize
self.pubkey = pubkey

@staticmethod
def number_to_base(num: int, base: int) -> List[int]:
if num == 0:
return [0] # 如果数字是 0,直接返回 0

digits = [] # 存储转换后的数字位
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 value

def 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_sign

def 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 result

def verify(self, digest: bytes, signature: List[bytes]) -> bool:
pubkey = self.get_pubkey_from_signature(digest, signature)
return True if pubkey == self.pubkey else False


if __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)

十六进制的签名signature_hex经过hex_to_32byte_chunks被分成了八组
消息摘要的主要用途是计算这八组数据的sha256迭代次数,如果消息摘要是8xxxx,那么第一次迭代次数就是7次,因为w-1=15 [8:15)步长为7
最后会将哈希迭代之后的八组数据进行拼接,从而生成pubkey
通过verify认证函数判断提交的摘要和签名所生成的pubkey是否和环境生成的pubkey一样

所以,思路很明确,既然哈希反向解密很难,因为这里必须得经过迭代,那么如果我迭代次数为零呢?这样我的签名通过get_pubkey_from_signature就会得到环境的公钥,我们直接让摘要为ffffffff,签名为环境提供的公钥,就可以通过验证了


还得是中科大,7分51秒拿下了一血,算上下载附件的时间,他们就做了5分钟
不过,这题确实不难,但他们代码审的好快啊O^O,我在那磨磨蹭蹭做了一个小时这样

夺旗闯关*

gitea服务器*

# login.go
package service

import (
"crypto/ecdsa"
"encoding/asn1"
"encoding/hex"
"errors"
"fmt"
"github.com/tjfoc/gmsm/sm2"
"math/big"
)

func (s *LoginService) Login(username, authInfo, certStr string) (token string, err error) {
// 读取用户证书
cert, err := s.CertService.LoadCertificate(certStr)
if err != nil {
return "", err
}

if err := s.CertService.ValidateCertificate(cert, RootCert); err != nil {
return "", err
}

// 校验用户名
if cert.Subject.CommonName != username {
err = errors.New("username is not valid")
}

// 判断是否挑战成功(随机字符串的签名能否用证书中的公钥验签过)
ecdsaPubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
return "", errors.New("public key in cert is not sm2")
}
sm2PubKey := sm2.PublicKey{
Curve: ecdsaPubKey.Curve,
X: ecdsaPubKey.X,
Y: ecdsaPubKey.Y,
}

// 从 authInfo 中提取 randomStr 和 signature
if len(authInfo) != 256 {
return "", errors.New("鉴别信息格式有误")
}
randomStr := authInfo[0:128]
signature := authInfo[128:]

_, err = ValidateSignature(randomStr, signature, &sm2PubKey)
if err != nil {
return "", err
}
return s.generateToken(username)
}

// 验证签名
func ValidateSignature(messageHex, signatureHex string, publicKey *sm2.PublicKey) (bool, error) {
msg, err := hex.DecodeString(messageHex)
if err != nil {
return false, errors.New("挑战值格式有误")
}

if len(signatureHex) != 128 {
return false, errors.New("签名值格式有误")
}

r, ok := big.NewInt(0).SetString(signatureHex[:64], 16)
if !ok {
return false, errors.New("签名值格式有误")
}
s, ok := big.NewInt(0).SetString(signatureHex[64:], 16)
if !ok {
return false, errors.New("签名值格式有误")
}

signature, err := asn1.Marshal(struct{ R, S *big.Int }{r, s})
if err != nil {
return false, errors.New("签名值格式有误")
}

isValid := publicKey.Verify(msg, signature)
if isValid {
return true, nil
} else {
return false, fmt.Errorf("签名无效")
}
}

下半场直接摆烂睡觉了,本来是准备刷一下渗透靶机的,发现解压密码在微信聊天记录里面。。。。。

断网啊,哥们,我玩牛魔……

玩!