【ctfshow摆烂杯 比烂为主】

本文介绍了在CTF比赛中遇到的一道涉及DSA数字签名算法和UTF-8编码的题目。首先概述了DSA的基本原理和常见攻击方式,强调了控制k值相同对于伪造签名的重要性。接着详细分析了题目中利用n的特殊值(1和q+1)来构造相同k的技巧,以及如何绕过长度限制,成功伪造签名。最后,作者反思了自己的解题过程,认为需要进一步学习和提高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

把ctfshow密码部分向下翻了下,顺手一点,点开了这道题,进去一看好家伙,有点意思…读了代码后发现好像是一个签名和验证的过程,于是想到了DSA,这个之前没怎么看过,所以还去CTF Wiki上去看了下基本的知识。


一、DSA基本原理及常见攻击

具体的内容可以在CTF Wiki上看到,这里简而言之就是DSA是一种数字签名算法,它的密钥生需要满足以下条件:
1.选择一种合适的哈希函数,用于计算签名内容的哈希
2.选择合适的密钥长度L和N(bit),分别对应公钥参数中的p和q,且p-1 是 q 的倍数
3.计算公钥参数g
4.选择私钥 x,0<x<q ,计算y≡gxmodp
于是我们就得到了公钥为 (p,q,g,y),私钥为 (x)
签名和验证过程直接贴CTF Wiki上的截图了:
在这里插入图片描述在这里插入图片描述推导过程就不纠结了,所以基本的攻击思路就是,如果我们能直接拿到私钥x,就可以直接攻破算法,不过很难实现。其次就是两次签名过程使用了同样的k值,这样就会使得两次签名得到的r值是一定相同的,然后在modq的意义下得到:
s1k - xr ≡ H(m1)
s2k - xr ≡ H(m2)
解这个方程组就可以得到k,x,就可以伪造签名了。

二、关于utf-8编码

utf-8编码中字符对应的索引并不一定在256以内,也就是说会出现多个字节表示一个字符的内容,而且在python3中还有str和bytes类型的区别,使得使用utf-8编码的时候长度可能会不一样。

三、题目解析

1.源码

代码如下(示例):

#!/usr/bin/env python
from hashlib import sha256
from Crypto.Util.number import *
from secret import flag, x

never_gonna_give_you_up = getPrime(128)
never_gonna_let_you_down = getPrime(128)
never_gonna_run_around_and_desert_you = getPrime(101)

def sign(message, public_key, private_key, n):
    p, q, g, y = public_key
    x = private_key
    k = pow(n * never_gonna_give_you_up + never_gonna_let_you_down, never_gonna_run_around_and_desert_you, q)
    r = pow(g, k, p) % q
    h = int(sha256(message).digest().hex(),16)
    s = (h + x * r) * inverse(k, q) % q
    return (r, s)

def verify(message, signature, public_key):
    p, q, g, y = public_key
    r, s = signature
    r %= q
    s %= q
    assert (r != 0 and s != 0), "NAIVE!"
    w = inverse(s,q)
    h = int(sha256(message).digest().hex(),16)
    u1 = (h * w) % q
    u2 = (r * w) % q
    v = ((pow(g,u1,p
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值