DSA-针对随机数K的攻击

目录

基本原理与参数

 针对随机数K的相关攻击

共享k

 jarvisoj  DSA

线性k(k2=ak1+b)

2023年春秋杯网络安全联赛冬季赛 not wiener

关系K(k2=k1^2+b)

 [HZNUCTF 2023 preliminary]easyDSA

 已知部分K(K的部分高位已知)

[NCTF 2021]dsa


基本原理与参数

 针对随机数K的相关攻击

共享k

 jarvisoj  DSA

 解压得到:

DSA的公钥(p,q,g,y)可以从dsa_public.pem文件中提取。

packet1:

 message里面是待签名的信息,sign文件中是已经签名过的文件。可以从sign文件中提取出(r,s)

公钥,r,s的提取:

from Crypto.Util.number import *
import gmpy2
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA1
from Crypto.Util.asn1 import DerSequence

#提取公钥
pubkey=DSA.import_key(open("dsa_public.pem","r").read())
files=[['./packet1/message1', './packet1/sign1.bin'],
       ['./packet2/message2', './packet2/sign2.bin'],
       ['./packet3/message3', './packet3/sign3.bin'],
       ['./packet4/message4', './packet4/sign4.bin']
]
#读取公钥
p=pubkey.p
q=pubkey.q
g=pubkey.g
y=pubkey.y

#创建DSS验证器对象
verifier=DSS.new(pubkey,'fips-186-3','der')

for file in files:
    #SHA1对象
    sha = SHA1.new(open(file[0], 'rb').read())
    signature = open(file[1], 'rb').read()
    #验证
    verifier.verify(sha, signature)
    #从签名中提取r,s
    der_seq = DerSequence().decode(signature, strict=True)
    print("==================")
    print("sha1=",sha.hexdigest())
    print("r=",der_seq[0])
    print("s=",der_seq[1])

 output:

 可以发现,对message3和message4使用了相同的随机数签名,因此可以对message3和message4进行共享k攻击。

from Crypto.Util.number import *
import gmpy2
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA1
from Crypto.Util.asn1 import DerSequence

#获取公钥
pubkey=DSA.import_key(open("dsa_public.pem","r").read())
files=[
        ['./packet3/message3', './packet3/sign3.bin'],
        ['./packet4/message4', './packet4/sign4.bin']
]
p=pubkey.p
q=pubkey.q
g=pubkey.g
y=pubkey.y
#参数列表
h=[]
r=[]
s=[]
for file in files:
    sha=SHA1.new(open(file[0],'rb').read())
    h.append(int(sha.hexdigest(),16))
    signature=open(file[1],'rb').read()
    #提取r,s
    der_sep=DerSequence().decode(signature,strict=True)
    r.append(der_sep[0])
    s.append(der_sep[1])

k=(h[0]-h[1])*(gmpy2.invert(s[0]-s[1],q))%q
x=(s[0]*k-h[0])*(gmpy2.invert(r[0],q))%q
print("x=",x)
print(pow(g,x,p)==y)

 output:

线性k(k2=ak1+b)

2023年春秋杯网络安全联赛冬季赛 not wiener

题目:

from Crypto.Util.number import *
from gmpy2 import *
import random, os
from hashlib import sha1
from random import randrange
flag=b''
x = bytes_to_long(flag)

def gen_key():
    while True:
        q = getPrime(160)
        p = 2 * getPrime(1024-160) * q+1
        if isPrime(p):
            break
    h = random.randint(1, p - 1)
    g = powmod(h,(p-1)//q, p)
    y=pow(g,x,p)
    return p,q,g,y
def cry():
    a =
    p = getPrime(512)
    q = getPrime(512)
    d = getPrime(280)
    n = p * q
    e = inverse(d, (p - 1) * (q - 1))
    c = pow(a, e, n)
    return n,e,c

p,q,g,y=gen_key()
k1 = random.randint(1, q-1)
h1 = bytes_to_long(sha1(os.urandom(20)).digest())
r1 = pow(g, k1, p) % q
s1 = ((h1 + x*r1) * invert(k1, q))% q

n,e,c= cry()

a=
b= 17474742587088593627
k2 = a*k1 + b
h2 = bytes_to_long(sha1(os.urandom(20)).digest())
r2 = pow(g, k2, p) % q
s2 = ((h2 + x*r2) * invert(k2, q)) % q
print(n,e,c)
print(p,q,g,y)
print("h1:%s r1:%s s1:%s"%(h1,r1,s1))
print("h2:%s r2:%s s2:%s"%(h2,r2,s2))


 gen_key函数生成DSA数字签名的公钥。Cry函数使用RSA将a加密了。使用DSA签名了两组信息,且随机数k满足k2=a*k1 + b。解密RSA得到a,b给出了,就可以使用线性k攻击得到DSA的私钥x了。

在RSA给出的n,e中发现n,e都是非常大的数。d是280位,n是1024位,280/1024约等于0.273,因此不能使用Wiener Attack,这里可以使用Boneh-Durfee,因为0.273<0.292。

将m调到7就可以得到d了。

from __future__ import print_function
import time

############################################
# Config
##########################################

"""
Setting debug to true will display more informations
about the lattice, the bounds, the vectors...
"""
debug = True

"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False

"""
This is experimental, but has provided remarkable results
so far. It tries to reduce the lattice as much as it can
while keeping its efficiency. I see no reason not to use
this option, but if things don't work, you should try
disabling it
"""
helpful_only = True
dimension_min = 7 # stop removing if lattice reaches that dimension

############################################
# Functions
##########################################

# display stats on helpful vectors
def helpful_vectors(BB, modulus):
    nothelpful = 0
    for ii in range(BB.dimensions()[0]):
        if BB[ii,ii] >= modulus:
            nothelpful += 1

    print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")

# display matrix picture with 0 and X
def matrix_overview(BB, bound):
    for ii in range(BB.dimensions()[0]):
        a = ('%02d ' % ii)
        for jj in range(BB.dimensions()[1]):
            a += '0' if BB[ii,jj] == 0 else 'X'
            if BB.dimensions()[0] < 60:
                a += ' '
        if BB[ii, ii] >= bound:
            a += '~'
        print(a)

# tries to remove unhelpful vectors
# we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
    # end of our recursive function
    if current == -1 or BB.dimensions()[0] <= dimension_min:
        return BB

    # we start by checking from the end
    for ii in range(current, -1, -1):
        # if it is unhelpful:
        if BB[ii, ii] >= bound:
            affected_vectors = 0
            affected_vector_index = 0
            # let's check if it affects other vectors
            for jj in range(ii + 1, BB.dimensions()[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值