2024春秋杯网络安全联赛夏季赛Crypto(AK)
2024春秋杯网络安全联赛夏季赛Crypto解题思路以及用到的软件
所有题用到的软件
1.vm(虚拟机kali)和Ubuntu,正常配置即可B站有很多。
2.Visual Studio Code(里面要配置python,crypto库和Sagemath数学软件系统Sagemath)。
3.随波逐流工作室 (1o1o.xyz)ctf工具。
ezzzecc
原题代码
pythonp = getPrime(256) a = getPrime(256) b = getPrime(256) E = EllipticCurve(GF(p),[a,b]) m = E.random_point() G = E.random_point() k = getPrime(18) K = k * G r = getPrime(256) c1 = m + r * K c2 = r * G cipher_left = s2n(flag[:len(flag)//2]) * m[0] #flag的前半部分乘m[0],所以只要用密文的除于m[0]即可得到flag前半部分 cipher_right = s2n(flag[len(flag)//2:]) * m[1] #flag的后半部分点乘m[1] p = p的格式为p={p}koZP3YQAklARRNrmYfjxoKIAXegOcG4jMOmKb08uESOkCCn72d6UM2NWgefYPEMq4EJ1M0jKaqt02Guo5Ubccjqg4QZaaHbScREx38UMLQKwG0LcDd8VFX1zkobc1ZQn4L3DhKQrgJZI55todgOdJuHN532bxScAvOF26gJyQclPtRHn3M6SHrRCEXzzmszd68PJlLB6HaabrRrCW9ZoAYSZetM5jDBtNCJLpR0CBZUUk3Oeh2MZQu2vk8DZ1QqNG49hlxGfawp1FXvAZPdMwixzkhEQnbCDcOKzYyT6BZF2Dfd940tazl7HNOswuIpLsqXQ2h56guGngMeYfMXEZV09fsB3TE0N934CLF8TbZnzFzEkOe8TPTK2mWPVSrgmbsGHnxgYWhaRQWg3yosgDfrEa5qfVl9De41PVtTw024gltovypMXK5XMhuhogs0EMN7hkLapLn6lMj K = (49293150360761418309411209621405185437426003792008480206387047056777011104939 : 43598371886286324285673726736628847559547403221353820773139325027318579443479) G = (34031022567935512558184471533035716554557378321289293120392294258731566673565 : 74331715224220154299708533566163247663094029276428146274456519014761122295496) 私钥k小于1000000 c1 = (3315847183153421424358678117707706758962521458183324187760613108746362414091 : 61422809633368910312843316855658127170184420570309973276760547643460231548014) c2 = (12838481482175070256758359669437500951915904121998959094172291545942862161864 : 60841550842604234546787351747017749679783606696419878692095419214989669624971) cipher_left = 75142205156781095042041227504637709079517729950375899059488581605798510465939 cipher_right = 61560856815190247060747741878070276409743228362585436028144398174723191051815
解题思路(先解析给的条件接着再看要求)
确定椭圆曲线参数和点:
- 椭圆曲线的参数 ( p )、( a )、( b ) 已经给出。
- 点 ( G )、( K )、( c1 )、( c2 ) 也已经给出。
计算私钥 ( k ):
- 私钥 ( k ) 是一个小于 1000000 的素数。
- 我们知道 ( K = k \cdot G ),所以可以通过遍历所有可能的 ( k ) 值来找到正确的 ( k )。
计算明文点 ( m ):
- 我们知道 ( c1 = m + r \cdot K ) 和 ( c2 = r \cdot G )。
- 通过 ( c2 = r \cdot G ),我们可以计算出 ( r )。
- 然后使用 ( r ) 和 ( K ) 计算 ( r \cdot K )。
- 最后,通过 ( c1 - r \cdot K ) 计算出 ( m )。
解密 flag:
- 使用 ( m ) 的坐标 ( m[0] ) 和 ( m[1] ) 来解密
cipher_left
和cipher_right
。脚本如下
python#from sage.all import * # 导入SageMath的所有功能,但在此代码中未使用 from Crypto.Util.number import * # 导入Crypto库中的实用函数 # 定义椭圆曲线参数 a = 87425770561190618633288232353256495656281438408946725202136726983601884085917 b = 107879772066707091306779801409109036008421651378615140327877558014536331974777 p = 95258468765219141626168727997935766803481277588106799359407486570046359762703 # 打印p的二进制长度 print(len(bin(p))) # 定义椭圆曲线E E = EllipticCurve(GF(p), [a, b]) # 打印椭圆曲线E的阶(点的数量) print(E.order()) # 定义密文部分 cipher_left = 75142205156781095042041227504637709079517729950375899059488581605798510465939 cipher_right = 61560856815190247060747741878070276409743228362585436028144398174723191051815 # 定义椭圆曲线上的点c1和c2 c1 = E(3315847183153421424358678117707706758962521458183324187760613108746362414091, 61422809633368910312843316855658127170184420570309973276760547643460231548014) c2 = E(12838481482175070256758359669437500951915904121998959094172291545942862161864, 60841550842604234546787351747017749679783606696419878692095419214989669624971) # 尝试不同的k值来解密 for k in range(1000000): m = c1 - k * c2 # 计算m = c1 - k * c2 flag1 = long_to_bytes(int(cipher_left / m[0])) # 将cipher_left除以m的x坐标并转换为字节 flag2 = long_to_bytes(int(cipher_right / m[1])) # 将cipher_right除以m的y坐标并转换为字节 if b'flag' in flag1 or b'ctf' in flag1: # 检查是否包含'flag'或'ctf' print(flag1 + flag2) # 打印解密结果 break # 找到结果后退出循环
解密的关键在于找到一个合适的
k
值,这个k
值的范围是从 0 到 999999。对于每一个k
,我们计算m = c1 - k * c2
。接着,我们把
cipher_left
和cipher_right
分别除以m
的 x 坐标和 y 坐标,得到两个字节串flag1
和flag2
。最后一步,我们检查一下
flag1
里面有没有包含关键字b'flag'
或者b'ctf'
。如果有的话,我们就把flag1
和flag2
拼接起来,输出完整的 flag。
视频讲解:
2024春秋竞赛ezzzecc视频解题思路
flag
happy2024
原题代码1
pythonfrom not2022but2024 import CBC_key # 从not2022but2024模块导入CBC_key from Crypto.Util.Padding import pad # 从Crypto库导入填充函数 flag = b'flag{}' # 定义一个字节串形式的flag from Crypto.Cipher import AES # 从Crypto库导入AES加密模块 from hashlib import sha256 # 从hashlib库导入sha256哈希函数 import random # 导入随机数生成模块 n = 92409623123098901791792363114697204166734358914220895740223341612682462563324908002852969747447253269353656265717157699071118377228204036796781052853910448495779756732335396395768081489079058079814549547598374174800251028951681229956305213989996252604809845148110414284348919868084631304579378411884754210093 m = 80 # 定义一个整数m M = random_prime(2^256) # 生成一个256位的随机素数M As = [random.randrange(0, M) for i in range(n)] # 生成n个在0到M之间的随机数 xs = [random_vector(GF(2), m).change_ring(ZZ) for i in range(n)] # 生成n个随机向量,每个向量有m个元素 Bs = sum([As[_] * vector(Zmod(M), xs[_]) for _ in range(n)]).change_ring(ZZ) # 计算Bs,它是As和xs的线性组合 IV = sha256(str(int(sum(As))).encode()).digest()[:16] # 使用sha256哈希函数生成IV,取前16字节 aes = AES.new(CBC_key, AES.MODE_CBC, iv=IV) # 创建AES加密对象,使用CBC模式和生成的IV cipher = aes.encrypt(pad(flag, 16)) # 使用AES加密flag,并进行填充 print(cipher) # 打印加密后的密文 print(Bs) # 打印Bs的值 print(M) # 打印M的值
原题代码2
pythonfrom Crypto.Util.number import * # 导入Crypto库中的实用函数 CBC_key = b'' # 初始化CBC模式的密钥,目前为空字节串 p,q = getPrime(512),getPrime(512) # 生成两个512位的素数p和q n = p * q # 计算n,即p和q的乘积 N = n**2 + 2024 # 计算N,即n的平方加上2024 hint = (pow(3, 2022, N) * p**2 + pow(5, 2022, N) * q**2) % N # 计算hint,使用3的2022次方模N乘以p的平方加上5的2022次方模N乘以q的平方,然后对N取模 c = pow(bytes_to_long(CBC_key), 65537, n) # 将CBC_key转换为长整数,然后计算其65537次方模n,得到密文c print('n =', n) # 打印n的值 print('h =', hint) # 打印hint的值 print('c =', c) # 打印密文c的值
解题思路(先解析给的条件接着再看要求)
首先,我们需要从打印的输出中获取加密后的密文。这个密文是使用AES加密算法生成的。接下来,我们需要计算初始化向量(IV)。IV是通过对
As
列表中的所有元素求和,并将结果转换为字符串后进行SHA-256哈希,然后取前16字节生成的。我们还需要知道用于加密的密钥(CBC_key)。这个密钥是从not2022but2024
模块中导入的。最后,我们使用AES解密对象和IV来解密密文。创建AES解密对象时,使用CBC模式和生成的IV。然后,使用解密对象对密文进行解密,并去除填充,得到原始的flag。
导入必要的模块和定义变量:
- 从
not2022but2024
模块导入CBC_key
。- 从
Crypto
库导入填充函数pad
。- 定义一个字节串形式的flag:
b'flag{}'
。- 从
Crypto
库导入AES加密模块。- 从
hashlib
库导入sha256
哈希函数。- 导入随机数生成模块
random
。定义一些变量:
n
是一个大整数。m
是一个整数。M
是一个256位的随机素数。As
是一个包含n
个在0到M
之间的随机数的列表。xs
是一个包含n
个随机向量的列表,每个向量有m
个元素。Bs
是As
和xs
的线性组合。生成IV:
- 使用
sha256
哈希函数对sum(As)
进行哈希,取前16字节作为IV。创建AES加密对象并加密flag:
- 使用CBC模式和生成的IV创建AES加密对象。
- 使用AES加密flag,并进行填充。
打印加密后的密文、Bs和M:
- 打印加密后的密文。
- 打印Bs的值。
- 打印M的值。
获取加密后的密文:
- 从打印的输出中获取加密后的密文。
获取IV:
- IV是通过
sha256(str(int(sum(As))).encode()).digest()[:16]
生成的。- 需要知道
As
的值来计算IV。获取CBC_key:
- 需要知道
CBC_key
的值来进行解密。解密密文:
- 使用AES解密对象和IV来解密密文。
解密密文:
- 使用AES解密对象和IV来解密密文。
- 我们已经获取了加密后的密文、IV和CBC_key,我们可以进行以下步骤来解密flag:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad假设我们已经获取了加密后的密文、IV和CBC_key
cipher = b'encrypted_cipher_text' # 替换为实际的加密后的密文
IV = b'generated_IV_here' # 替换为实际的IV
CBC_key = b'CBC_key_here' # 替换为实际的CBC_key创建AES解密对象
aes = AES.new(CBC_key, AES.MODE_CBC, iv=IV)
解密密文
decrypted_padded_flag = aes.decrypt(cipher)
去除填充
flag = unpad(decrypted_padded_flag, 16)
print(flag)
CopyInsert
请确保替换
cipher
、IV
和CBC_key
为实际的值。这样,我们就可以解密并打印出flag。脚本如下
pythonfrom Crypto.Util.number import * # 导入Crypto库中的实用函数 from Crypto.Cipher import AES # 导入AES加密模块 from hashlib import sha256 # 导入SHA-256哈希函数 import random # 导入随机数生成模块 from gmpy2 import * # 导入gmpy2库,用于大数运算 # 已知参数 n = 104765768221225848380273603921218042896496091723683489832860494733817042387427987244507704052637674086899990536096984680534816330245712225302233334574349506189442333792630084535988347790345154447062755551340749218034086168589615547612330724516560147636445207363257849894676399157463355106007051823518400959497 # RSA模数n h = 7203581190271819534576999256270240265858103390821370416379729376339409213191307296184376071456158994788217095325108037303267364174843305521536186849697944281211331950784736288318928189952361923036335642517461830877284034872063160219932835448208223363251605926402262620849157639653619475171619832019229733872640947057355464330411604345531944267500361035919621717525840267577958327357608976854255222991975382510311241178822169596614192650544883130279553265361702184320269130307457859444687753108345652674084307125199795884106515943296997989031669214605935426245922567625294388093837315021593478776527614942368270286385 # 提示值h c = 86362463246536854074326339688321361763048758911466531912202673672708237653371439192187048224837915338789792530365728395528053853409289475258767985600884209642922711705487919620655525967504514849941809227844374505134264182900183853244590113062802667305254224702526621210482746686566770681208335492189720633162 # RSA密文c q = 11846999515401139806618780458482772585816656222161925595380112630854263318903047176862162285755281915011589524788709945023820217521669415569797208065004797 # 素数q p = n // q # 计算素数p # 计算phi和d phi = (p - 1) * (q - 1) # 计算欧拉函数phi(n) d = inverse(65537, phi) # 计算RSA私钥d,即65537在模phi下的逆元 # 解密c得到m m = pow(c, d, n) # 使用私钥d解密密文c print(long_to_bytes(m)) # 将解密得到的整数m转换为字节并打印 # AES解密 CBC_key = b'mylove_in_summer' # AES解密密钥 enc = b'%\x97\xf77\x16.\x83\x99\x06^\xf2h!k\xfaN6\xb0\x19vd]\x04B\x9e&\xc1V\xed\xa3\x08gX\xb2\xe3\x16\xc2y\xf5/\xb1\x1f>\xa1\xa0DO\xc6gy\xf2l\x1e\xe89\xaeU\xf7\x9d\x03\xe5\xcd*{' # AES加密的密文 sum = 1190342683523422755570459424048363591795982274808192123460316142044766104571627 # 用于生成IV的值 IV = sha256(str(sum).encode()).digest()[:16] # 使用SHA-256哈希函数生成IV aes = AES.new(CBC_key, AES.MODE_CBC, iv=IV) # 创建AES CBC模式的解密对象 cipher = aes.decrypt(enc) # 解密AES密文 print(cipher) # 打印解密后的明文
视频讲解 :
2024春秋竞赛happy2024视频解析
flag
Signature
原题代码
pythonimport os import hashlib from Crypto.Util.number import * from Crypto.PublicKey import DSA import random def gen_proof_key(): # 定义一个固定的密码字符串 password = 'happy_the_year_of_loong' getin = '' #定义一个空字符串变量 # 随机将密码字符串中的字符转换为大写或小写 for i in password:#password 字符串中的每个字符进行循环。 if random.randint(0, 1):#生成一个随机整数,如果该整数为 1,则执行下一行代码。 getin += i.lower()#将当前字符转换为小写并添加到 getin 字符串中。 else: getin += i.upper()#将当前字符转换为大写并添加到 getin 字符串中 # 计算转换后字符串的SHA-256哈希值 ans = hashlib.sha256(getin.encode()).hexdigest()#字符串的 SHA-256 哈希值,并将结果存储在 ans 变量中。 return getin, ans#返回包含转换后的字符串 getin 和其 SHA-256 哈希值 ans 的元组。 def gen_key(): # 生成一个私钥,范围在2到q-2之间 pri = random.randint(2, q - 2) # 计算公钥,使用离散对数问题 pub = pow(g, pri, p)#使用离散对数问题计算公钥 pub,即 g 的 pri 次方模 p。 return pri, pub#返回包含私钥 pri 和公钥 pub 的元组。 def sign(m, pri): k = int(hashlib.md5(os.urandom(20)).hexdigest(), 16) # 生成一个随机的k值,用于签名过程 H = int(hashlib.sha256(m).hexdigest(), 16) # 计算消息的SHA-256哈希值 r = pow(g, k, p) % q# 计算签名中的r值 s = pow(k, -1, q) * (H + pri * r) % q# 计算签名中的s值 return r, s def verify(pub, m, signature): r, s = signature # 从签名中提取r和s if r <= 0 or r >= q or s <= 0 or s >= q: # 如果r或s不在有效范围内,返回False return False w = pow(s, -1, q) # 计算s的模逆w,w * s ≡ 1 (mod q) H = int(hashlib.sha256(m).hexdigest(), 16) # 计算消息m的SHA-256哈希值,并转换为整数 # 计算u1和u2 u1 = H * w % q u2 = r * w % q # 计算v值 v = (pow(g, u1, p) * pow(pub, u2, p) % p) % q # 计算v = (g^u1 * pub^u2 mod p) mod q # 验证签名是否正确 return v == r # 如果v等于r,则签名正确,返回True;否则返回False def login(): print('Hello sir, Plz login first')# 打印欢迎信息 # 定义菜单选项 menu = ''' 1. sign 2. verify 3. get my key ''' times = 8# 初始化尝试次数 while True:# 进入循环 print(menu)# 打印菜单 if times < 0: # 检查尝试次数是否用完 print('Timeout!')# 检查尝试次数是否用完 return False choice = int(input('>'))# 获取用户选择 if choice == 1:# 处理用户选择 name = input('Username:').encode()# 获取用户名并编码为字节 if b'admin' in name:# 检查用户名是否包含'admin' print('Get out!') # 打印拒绝信息并返回False return False r, s = sign(name, pri)# 签名用户名 print(f'This is your signature -- > {r},{s}') # 打印签名结果 times -= 1 # 减少尝试次数 elif choice == 2:# 处理用户选择 print('Sure, Plz input your signature') # 提示用户输入签名 r = int(input('r:'))# 获取签名参数r s = int(input('s:'))# 获取签名参数s if verify(pub, b'admin', (r, s)) == True:# 验证签名 print('login success!') return True# 打印登录成功信息并返回True else: print('you are not admin')# 打印登录失败信息并返回False return False elif choice == 3:# 处理用户选择 # 打印密钥信息 print(f'Oh, your key is {(p, q, g)}') getin, ans = gen_proof_key() # 调用函数生成一个随机的字符串及其哈希值 print(f'Your gift --> {ans[:6]}') # 打印哈希值的前6个字符作为礼物 your_token = input('Plz input your token\n>') # 提示用户输入token if your_token != getin: # 检查用户输入的token是否与生成的字符串匹配 print('Get out!') # 如果不匹配,打印拒绝信息 exit(0) # 退出程序 key = DSA.generate(1024)# 生成DSA密钥对、 p, q, g = key.p, key.q, key.g# 获取DSA参数 pri, pub = gen_key()pri, pub = key.key# 获取私钥和公钥 if login() == False:# 进行登录过程 exit(0) print(open('/flag', 'r').read())# 如果登录成功,读取并显示flag文件内容 '''
解题思路
生成正确的 token:
运行 gen_proof_key 函数,获取 getin 和 ans。
使用 getin 作为 token 输入。
获取 DSA 密钥对:
生成 DSA 密钥对,获取 p, q, g, pri, pub。
通过 login 函数的验证:
选择选项 1 签名一个非 admin 的用户名,获取签名 (r, s)。
选择选项 3 获取 (p, q, g)。
使用获取的 (p, q, g) 和签名 (r, s) 来伪造一个 admin 的签名。
伪造 admin 的签名:
由于 k 是随机生成的,且 k 的值可以通过 r 和 s 推导出来(如果 k 被重用),可以尝试重用 k 来伪造 admin 的签名。
由于 k 是随机生成的,且 k 的值可以通过 r 和 s 推导出来(如果 k 被重用),你可以尝试重用 k 来伪造 admin 的签名。
计算 k:
k = (H + pri * r) * inverse(s, q) % q
CopyInsert
使用 k 计算 admin 的签名:
H_admin = int(hashlib.sha256(b'admin').hexdigest(), 16)
r_admin = pow(g, k, p) % q
s_admin = inverse(k, q) * (H_admin + pri * r_admin) % q
CopyInsert
验证 admin 的签名:
选择选项 2,输入伪造的 admin 的签名 (r_admin, s_admin)。
如果验证通过,将成功登录为 admin,并获得 flag。
参考博客
因为我用的是虚拟机 ,题目有容器使用没办法直接做,所以你们可以参考一下这个博主
pythonimport os import hashlib from Crypto.Util.number import * from Crypto.PublicKey import DSA import random def gen_proof_key(): # 定义一个固定的密码字符串 password = 'happy_the_year_of_loong' getin = '' #定义一个空字符串变量 # 随机将密码字符串中的字符转换为大写或小写 for i in password:#password 字符串中的每个字符进行循环。 if random.randint(0, 1):#生成一个随机整数,如果该整数为 1,则执行下一行代码。 getin += i.lower()#将当前字符转换为小写并添加到 getin 字符串中。 else: getin += i.upper()#将当前字符转换为大写并添加到 getin 字符串中 # 计算转换后字符串的SHA-256哈希值 ans = hashlib.sha256(getin.encode()).hexdigest()#字符串的 SHA-256 哈希值,并将结果存储在 ans 变量中。 return getin, ans#返回包含转换后的字符串 getin 和其 SHA-256 哈希值 ans 的元组。 def gen_key(): # 生成一个私钥,范围在2到q-2之间 pri = random.randint(2, q - 2) # 计算公钥,使用离散对数问题 pub = pow(g, pri, p)#使用离散对数问题计算公钥 pub,即 g 的 pri 次方模 p。 return pri, pub#返回包含私钥 pri 和公钥 pub 的元组。 def sign(m, pri): k = int(hashlib.md5(os.urandom(20)).hexdigest(), 16) # 生成一个随机的k值,用于签名过程 H = int(hashlib.sha256(m).hexdigest(), 16) # 计算消息的SHA-256哈希值 r = pow(g, k, p) % q# 计算签名中的r值 s = pow(k, -1, q) * (H + pri * r) % q# 计算签名中的s值 return r, s def verify(pub, m, signature): r, s = signature # 从签名中提取r和s if r <= 0 or r >= q or s <= 0 or s >= q: # 如果r或s不在有效范围内,返回False return False w = pow(s, -1, q) # 计算s的模逆w,w * s ≡ 1 (mod q) H = int(hashlib.sha256(m).hexdigest(), 16) # 计算消息m的SHA-256哈希值,并转换为整数 # 计算u1和u2 u1 = H * w % q u2 = r * w % q # 计算v值 v = (pow(g, u1, p) * pow(pub, u2, p) % p) % q # 计算v = (g^u1 * pub^u2 mod p) mod q # 验证签名是否正确 return v == r # 如果v等于r,则签名正确,返回True;否则返回False def login(): print('Hello sir, Plz login first')# 打印欢迎信息 # 定义菜单选项 menu = ''' 1. sign 2. verify 3. get my key ''' times = 8# 初始化尝试次数 while True:# 进入循环 print(menu)# 打印菜单 if times < 0: # 检查尝试次数是否用完 print('Timeout!')# 检查尝试次数是否用完 return False choice = int(input('>'))# 获取用户选择 if choice == 1:# 处理用户选择 name = input('Username:').encode()# 获取用户名并编码为字节 if b'admin' in name:# 检查用户名是否包含'admin' print('Get out!') # 打印拒绝信息并返回False return False r, s = sign(name, pri)# 签名用户名 print(f'This is your signature -- > {r},{s}') # 打印签名结果 times -= 1 # 减少尝试次数 elif choice == 2:# 处理用户选择 print('Sure, Plz input your signature') # 提示用户输入签名 r = int(input('r:'))# 获取签名参数r s = int(input('s:'))# 获取签名参数s if verify(pub, b'admin', (r, s)) == True:# 验证签名 print('login success!') return True# 打印登录成功信息并返回True else: print('you are not admin')# 打印登录失败信息并返回False return False elif choice == 3:# 处理用户选择 # 打印密钥信息 print(f'Oh, your key is {(p, q, g)}') getin, ans = gen_proof_key() # 调用函数生成一个随机的字符串及其哈希值 print(f'Your gift --> {ans[:6]}') # 打印哈希值的前6个字符作为礼物 your_token = input('Plz input your token\n>') # 提示用户输入token if your_token != getin: # 检查用户输入的token是否与生成的字符串匹配 print('Get out!') # 如果不匹配,打印拒绝信息 exit(0) # 退出程序 key = DSA.generate(1024)# 生成DSA密钥对、 p, q, g = key.p, key.q, key.g# 获取DSA参数 pri, pub = gen_key()pri, pub = key.key# 获取私钥和公钥 if login() == False:# 进行登录过程 exit(0) print(open('/flag', 'r').read())# 如果登录成功,读取并显示flag文件内容 '''
代码实现了一个基于DSA(数字签名算法)的登录系统。主要功能和流程:
生成证明密钥 (gen_proof_key):
生成一个随机的字符串 getin,它是固定密码字符串 'happy_the_year_of_loong' 的随机大小写混合版本。
计算 getin 的 SHA-256 哈希值 ans。
返回 getin 和 ans。
生成密钥对 (gen_key):
生成一个私钥 pri,它是介于 2 和 q - 2 之间的随机整数。
计算公钥 pub,它是 g 的 pri 次方模 p。
返回 pri 和 pub。
签名 (sign):
生成一个随机数 k,它是 20 字节随机数据的 MD5 哈希值的整数表示。
计算消息 m 的 SHA-256 哈希值 H。
计算签名参数 r 和 s。
返回 r 和 s。
验证 (verify):
检查签名参数 r 和 s 是否在有效范围内。
计算 w,它是 s 的模逆。
计算消息 m 的 SHA-256 哈希值 H。
计算 u1 和 u2。
计算 v,它是 g 的 u1 次方和 pub 的 u2 次方模 p 的结果再模 q。
返回 v 是否等于 r。
登录 (login):
提供一个菜单,允许用户选择签名、验证或获取密钥。
用户可以选择签名一个非 admin 的用户名,获取签名 (r, s)。
用户可以选择验证 admin 的签名 (r, s)。
用户可以选择获取密钥 (p, q, g)。
如果验证通过,用户将成功登录为 admin,并获得 flag。
主流程:
生成证明密钥 getin 和 ans。
提示用户输入 token,如果 token 不匹配 getin,则退出。
生成 DSA 密钥对 (p, q, g) 和 (pri, pub)。
调用 login 函数进行登录。
如果登录成功,打印 /flag 文件的内容。
这个系统的主要目的是通过 DSA 签名和验证机制来模拟一个安全的登录过程,确保只有拥有正确签名的人才能以 admin 身份登录并获取 flag
视频讲解 :
2024春秋竞赛夏季赛Signature解题思路