网安实践(三)- WP

Crypto

格密码

from Crypto.Util.number import *
from gmpy2 import invert
from flag import flag
flag = flag.encode("utf-8")
m = bytes_to_long(flag)


def strongGenerate():
    P = getStrongPrime(4096)
    while True:
        a = getRandomNBitInteger(1024)
        g = getStrongPrime(768)
        h = invert(a, P) * g % P
        return P, h, a


def strongEncrypt(p, h, a):
    random_int = getRandomNBitInteger(1000)
    cipher = (h * random_int + m * a) % p
    return cipher


p, h, a = strongGenerate()
c = strongEncrypt(p, h, a)
print("h=", h)
print("p=", p)
print("c=", c)
"""
h= 311970364425799366998489758816351964614898164597015962390522858760089331210269507769408330245745888541705059882396722340774681935443615888403494901415226651295201132556613291289590900246992553502513664561058230713840616052310750850144077552701142563872837663789636304968423919464707545482008647087312063949024744195318160335652074407874634742273493108112212110123691909346846612115479023950119286716243604630664235633831784083300431161225131883065150778501178458601885263943907964612851841356128492283759401129349655263360496418606534637831065564054627124545266130146585012568948018083420026867791483624987951876329968315410612748989452628410331813540143425873481351220499681815979569479285905651270208308396719282247586008816711527598915797885618862654168623002012746684102245733757428828517277952675441290263051618987121956646671901357370585784409633697165339182406341764320293630983680416055584947772382282259966044517683538433409836256995980804901093405108581243143413703339657071622279140236369465154220363993923085583049720512383384577159975134910449465903227555419552492606439149153015674603047695345700309870206034743317361786333732070962362572427411597266252707397451423195512449103367120235737550650354427690243524900449675
p= 958396606448120961344481821891302529131234571519205540072533929007120447482644938027839069855225984909598017115601687321093037138370623689366302399472755221666720998204960391688686871213784218139146955110040572010513513710257471193690475085340782434134757767894370195789546551282060123540167285748706110004061656181247087025993389812671658906912145384679566372037915179523706023309666826191629634851598509448675340758156737530185937223948687001934035933966720541257653562031308634592003639145311246147664928094381997264652669457904886666262851691565920076364034433600062253014377522558972668765617631467665085324790312091927917199333642804731490452686230714946707520153374983386856748968281865500447110447064499127304576389450231449458997253721401398074788997192735673939296531420329207264490272774186484762804708405995307032141715953080254098506768585899454119852852002578252291310329200959476618660765556861112558404254680356703540148703891793429589128285327230398620737214653509556883409293525132433655639546382948760666188308135216174434756100646981938900940757869329579150360836505992616459066632938605335205569767007863591747811468281490752448411521431430302168214014717351186242150709061058943921599462022604009950194741903607
c= 767158168672362136291238223905378538545444315829681403660668665037917788547250510431680762324989504337886911129872811283399423182492713085621340850466620775416712732614020830060267436728824312319343522189998875569791210615658554329492772575522352284894778864900683043087475949382767603528807809596004213194946687583749277851731545121301799909443549367647188538291294493900118514585149301404415365107375148502163345229200555520367376148986792681776613941685900525114359918025093194374564154918465789098039688273260831196880453048787881692220588699313824407443049610470566611891830120455606865304514498141918370250200060333776115471607369861567714061571248634366226901360555240991881037749649258353302128601187117945261098036478588953880956746052307508140721683848770369771427200654010686745459084737649483182116223928908511586372587312845173805333061611628627699056444060210866689908925857413693914088384801590539118419817748706914585535977225375257595014121709225398146804929559026288825337416874187757876993164395155899845807880799091660701491902131855351054079661782867046531376623992742661604584530403794933640735943298254524984623808363772872836875750554022138997087590785362832339405833456398277842368920260448389099114876068641
"""

根据加密代码,有如下关系式$$ \left\{ \begin{align} h & \equiv a^{-1} \cdot g \mod P \\ c & \equiv (r \cdot h + m \cdot a) \mod P \end{align} \right.$$ $$ \begin{bmatrix} k & a \end{bmatrix} \begin{bmatrix}p & 0 \\ h & 1\end{bmatrix} = \begin{bmatrix} g & a \end{bmatrix}$$

可化为$ g = a \cdot h + k \cdot P$,根据此式构建格。但需要确定k还是a作为第二个参数。转化一下求密文c的公式。

$$c \cdot a \equiv (r \cdot g + m \cdot a^2)\ mod \ P \\m \cdot a^2 \equiv ((c \cdot a) \ mod P \ )\ mod\ g \\m \equiv ((c \cdot a) \ mod P \ ) \cdot a^{-2} mod\ g$$

我们选定a。构建格$$ \begin{bmatrix} k & a \end{bmatrix} \begin{bmatrix}p & 0 \\ h & 1\end{bmatrix} = \begin{bmatrix} g & a \end{bmatrix}$$

m = Matrix([[p, 0], [h, 1]])  
g, a = m.LLL()[0]  
f = (a * c % p) * inverse_mod(a^2, g) % g  
  
print(bytes.fromhex(hex(f)[2:]))

DSA签名

from multiprocessing import Process  
import os  
import random  
import socket  
from ecdsa import ecdsa as ec   
from datetime import datetime  
RNG = random.Random()  
import hashlib  
  
g = ec.generator_192  
N = g.order()  
secret = RNG.randrange(1, N)  
PUBKEY = ec.Public_key(g, g * secret)  
PRIVKEY = ec.Private_key(PUBKEY, secret)  
  
BANNER = """  
Welcome to Hust Signer. What do you want to do?  
1) Make signature  
2) Get the flag >"""  
  
def read_line(s):  
    body = b""  
    while True:  
        ch = s.recv(1)  
        if ch == b"\n":  
            break  
        body = body + ch  
    return body  
  
  
  
def go(s):  
    try:  
        s.send(BANNER.encode())  
        line = read_line(s)  
        if line == b"1":  
            now = datetime.now()  
            time = now.strftime("%H:%M:%S")  
            random_data = f"{RNG.getrandbits(512):x}"  
            hash = int(hashlib.md5(f"{time}:{random_data}".encode()).hexdigest(), 16)  
            nonce = RNG.randrange(1, N)  
            signature = PRIVKEY.sign(hash, nonce)  
            s.send(f"{signature.r}, {signature.s}, {hash}\n".encode())  
        elif line == b"2":  
            now = datetime.now()  
            time = now.strftime("%H:%M:%S")  
            to_check = int(hashlib.md5(f"{time}:get_flag".encode()).hexdigest(), 16)  
            s.send(f"Get signature for md5(\"{time}:get_flag\")\n".encode())  
            try:   
                sig_line = read_line(s).decode().split(",")  
            except ValueError:  
                s.send("Error!".encode())  
            sig = ec.Signature(int(sig_line[0]), int(sig_line[1]))  
            if PUBKEY.verifies( to_check, sig ):  
                s.send(b"Congratulation! Here is your flag:")  
                f = open("/flag", "r")  
                flag = f.read()  
                f.close()  
                s.send(flag.encode())  
            else:  
                s.send(b"Failed!\n")  
        else:  
            s.send(b"What?")  
    except socket.timeout:  
        print("Exit via timeout!")  
    finally:  
        s.close()  
      
if __name__ == '__main__':  
    s = socket.socket()  
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  
    s.bind(("0.0.0.0", 8000))  
    s.listen(10)  
    while True:  
        client, addr = s.accept()  
        print(f"Got connect from {addr}")  
        p = Process(target=go, args=(client,))  
        p.daemon = True  
        p.start()  
        client.close()

ECDSA中r由随机数k以及生成元G生成。
注意到每次生辰signature所给的r相同。这说明随机值k相同。

即r相同
我们获取两次signature,来破解k与d
再申请下一次签名所用的时间,生成签名


import hashlib

from Crypto.Util.number import inverse

r = 4672667200964722149623422575414394567666891392104258711792  
s1 = 1380082547722347378199432499915005653260602000840320490370  
h1 = 265628125087488969453564701837010287748  
  
  
s2 = 6206469118472605849488707538555465546857317706194151509947  
h2 = 284612552192339916331883431288259294492  
n = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831  # ECDSA 使用的 n 值  
# 根据公式计算私钥 dnumerator = (h1 - h2) % n  
denominator = (s1 - s2) % n  
k = (numerator * inverse(denominator, n)) % n  
print(f"[+] Recovered k: {k}")  
  
# 利用 k 计算私钥 dd = ((s1 * k - h1) * inverse(r, n)) % n  
print(f"[+] Recovered private key d: {d}")

time = "20:36:14"  
to_check = int(hashlib.md5(f"{time}:get_flag".encode()).hexdigest(), 16)  
  
s_new = (inverse(k, n) * (to_check + d * r)) % n  
print(f"[+] New signature: r = {r}, s = {s_new}")

简单RSA

from Crypto.Util.number import getPrime,bytes_to_long
with open("flag.txt","rb") as f:
    flag = f.read().strip()
m = bytes_to_long(flag)
e = 65537


for x in range(10):
    p = getPrime(1024)
    q = getPrime(1024)
    n = p * q
    c = pow(m, e, n)

    print("n =", n)
    print("c =", c)

多组n,c且使用相同e进行加密。提取不同n的公因子。

import sys
from functools import reduce

import gmpy2
import libnum
from Crypto.Util.number import getPrime, bytes_to_long, inverse, long_to_bytes
from gmpy2 import *

n = [n0, n1, n2, n3, n4, n5, n6, n7, n8, n9]
c = [c0, c1, c2, c3, c4, c5, c6, c7, c8, c9]

for i in range(len(n)):
    for j in range(len(n)):
        if(i!=j):
            if(gmpy2.gcd(n[i],n[j])!=1):   #求出最大公约数(p)
                print(i,j)                 
                p = gmpy2.gcd(n[i],n[j])
                print("p = ",p)
                q = n[i] // p
                print("q = ",q)
                d = gmpy2.invert(e , (p-1)*(q-1))
                print("d = ",d)
                m = pow(c[i],d,n[i])
                print("m = ",m)
                print(libnum.n2s(int(m)))

分组密码工作模式

import os
import socket
from multiprocessing import Process
from Crypto.Cipher import AES
auth_key = os.urandom(16)


def getFlag():
    try:
        with open("/flag","r") as f:
            flag = f.read()
        f.close
    except Exception:
        return "error"
    return flag


MENU = """
Enter your choice:
1) Create HUSTCTFer Account
2) Create Admin Account
3) Login
4) Exit
"""

def read_line(s):
    body = b""
    while True:
        ch = s.recv(1)
        if ch == b"\n":
            break
        body = body + ch
    return body

def go(s):
    try:
        s.send("Only admin can get the flag ! \n".encode())
        while True:
            s.send(MENU.encode())
            line = read_line(s)
            if line == b"1":
                token = b'HUSTCTFer!______'
                user_key = os.urandom(16)
                cipher = AES.new(auth_key, AES.MODE_CBC, user_key)
                code = cipher.encrypt(token)
                s.send(f'here is your token: {user_key.hex() + code.hex()} \n'.encode())
            elif line == b"2":
                s.send('Not Admin !!!!!!'.encode())
            elif line == b"3":
                s.send("Enter your token > \n".encode())
                try:
                    authcode = read_line(s).decode()
                    user_key = bytes.fromhex(authcode)[:16]
                    code = bytes.fromhex(authcode)[16:]
                    cipher = AES.new(auth_key, AES.MODE_CBC, user_key)
                    token = cipher.decrypt(code)
                except Exception as e:
                    s.send("Decrypt error\n".encode())
                    break
                if token == b'AdminAdmin!_____':
                    s.send("Hello Admin! Here is your FLAG: ".encode())
                    flag = getFlag()
                    s.send(flag.encode())
                    break
                elif token == b'HUSTCTFer!______':
                    s.send('Have fun!!\n'.encode())
                    break
                else:
                    s.send('Who are you?\n'.encode())
                    break
            elif line == b"4":
                s.send('ByeBye\n'.encode())
                break
            else:
                s.send('WTF\n'.encode())
        s.close()
    except socket.timeout:
        print("Exit for timeout!")
    finally:
        s.close()


if __name__ == '__main__':
    s = socket.socket()
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(("0.0.0.0", 7000))
    s.listen(10)
    while True:
        client, addr = s.accept()
        print(f"Got connect from {addr}")
        p = Process(target=go, args=(client,))
        p.daemon = True
        p.start()
        client.close()

CBC模式前一个密文分组与之后的明文异或后在加密成密文。本质上将“HUSTCTFer!______”形成的密文机密后以“AdminAdmin!_____”为明文(都是16字节,恰好一个组)。利用字节反转攻击,我们可以将user_key(初始向量,可看作前一组密文)与这两个明文异或,重新生成token。这样解密时code相当于与自身以及“AdminAdmin!_____”异或,得到AdminAdmin!_____。

token = "230b1db61e3a087d391317067431636216ecb4e238d34c110b08c7137808aa4a"
iv = bytes.fromhex(token[:32])

t1 = b'HUSTCTFer!______'
t2 = b'AdminAdmin!_____'

iv2 = b''

for i in range(16):
    k = t1[i]^t2[i]^iv[i]
    iv2 += k.to_bytes(1, "big")
iv = iv2
token = iv.hex() + token[32:]
print(token)、

古典密码破译

已知一个密码体制是$Z^{127}$​上的三阶Hill密码,明密文空间均为ASCII码为0-126的字符,短块处理方式为:如果明文是3的整数倍,则补充3个空格’\x20’;如果明文不是3的整数倍,那么就补充1到2个空格直到明文总长度为3的倍数。现在已知一密文为
>u\x10l9\npI,0\x04^J\x00ib\x03\x0c\x158d\x1f\x08Ixk\nF\x19fz\x14PT\x04\x03>R~

它是对’vmc{}’型flag加密的结果,那么flag= ?

我们只考虑明文的其中3行,即第一行(全已知),第二行(2个未知),最后一行(0~2个已知)。

以最后一行125 32 32 为例(暴力枚举两个元素,如x 125 32需暴力3个),枚举后首先检查是否可逆,可逆通过解线性方程求出密钥矩阵k,再对密文解密查看是否符合明文标准(全字符字母)。剩余可自行修改数据尝试。

  
from Crypto.Util.number import *  
  
r = b'>u\x10l9\npI,0\x04^J\x00ib\x03\x0c\x158d\x1f\x08Ixk\nF\x19fz\x14PT\x04\x03>R~'  
a = [int(x) for x in r]  
  
print(a)  
elements = [118, 109, 99, 123, 0, 0, 125, 32, 32]  
p = matrix(Zmod(127), 3, 3, elements)  
  
elements = [62, 117, 16, 108, 57, 10, 62, 82, 126]  
  
c = matrix(Zmod(127), 3, 3, elements)  
  
for i in range(0, 127):  
    for j in range(127):  
        p[1, 1] = j  
        p[1, 2] = i  
        f = True  
        if p.is_invertible() is True:  
            k = p.solve_right(c)  # pk = c
            d = ''  
            for kk in range(13):  
                tmp = matrix(Zmod(127), 1, 3, a[kk * 3 : (kk + 1) * 3])  
                A = k.solve_left(tmp)  
                for l in range(3):  
                    char = chr(A[0, l])  
                    if not char ==' ' and not char.isprintable():  
                        f = False  
                        break                    d += char  
                if f is False:  
                    break  
            if f is True:  
                print(f'123 {i} {j} | {d}')

RSA加密算法

from Crypto.Util.number import *
from sympy import nextprime

flag = 'vmc{****************}'

part1 = flag[:19]
part2 = flag[19:]
assert (len(flag) == 37)

p1 = getStrongPrime(1152)
p2 = nextprime(p1)
try:
    if p2 - p1 > 1000:
        raise Exception("Error")
except:
    exit()

q1 = getStrongPrime(512)
q2 = nextprime(q1)

n1 = p1 * p1 * q1
e1 = getStrongPrime(1024)
msg1 = bytes_to_long(part1.encode())
c1 = pow(msg1, e1, n1)

n2 = p2 * p2 * q2
e2 = nextprime(e1)
msg2 = bytes_to_long(part2.encode())
c2 = pow(msg2, e2, n2)

output = open('secret.txt', 'w')
output.write('n1=' + str(n1) + '\n')
output.write('c1=' + str(c1) + '\n')
output.write('e1=' + str(e1) + '\n')
output.write('n2=' + str(n2) + '\n')
output.write('c2=' + str(c2) + '\n')
output.write('e2=' + str(e2) + '\n')
output.close()

将flag分成两部分进行加密。生成两个大素数(非常接近)p1, p2
生成两个较小素数(非常接近)q1,q2
$n_1 = p_1^2\cdot q_1$$n_2 = p_2^2 \cdot q_2$
之后用两个相近素数e加密。和普通wiener-attack不同的是,e和n没有近到相除约为1的地步,相差还是很大,即 解密指数d也许很大,解不出来。

e和n的关系不符合利用条件,但是$n_1$ 和 $n_2$的关系却符合。
$\frac{n_1}{n_2} = (\frac{p_1}{p_2})^2 \cdot \frac{q_1}{q_2}$

显然$\frac{n_1}{n_2} < \frac{q_1}{q_2}$
所以q1/q2在区间(N1/N2,1)之间。尝试对N1/N2进行连分数展开并求其各项渐进分数

import gmpy2
from Crypto.Util.number import *
import sympy
def continuedFra(x, y):
    cf = []
    while y:
        cf.append(x // y)
        x, y = y, x % y
    return cf
def gradualFra(cf):
    numerator = 0 # 分子
    denominator = 1 # 分母
    for x in cf[::-1]:
        numerator, denominator = denominator, x * denominator + numerator
    return numerator, denominator

def getGradualFra(cf):
    gf = []
    for i in range(1, len(cf) + 1):
        gf.append(gradualFra(cf[:i]))
    return gf

def wienerAttack(e, n):
    cf = continuedFra(e, n)
    gf = getGradualFra(cf)
    for q2,q1 in gf:
        if q1 == 0: continue
        if N2 % q2 == 0 and q2 != 1:# 此处也可写成 N1 % q1 == 0 and q1 != 1
            return q2


N1=27682578737141139764880192910976946263355689816882797515059917479242862799083599745594956880258244112867559722435850732812023189662581052511287867553308318268020022386306820424829898858029986193412922645944359409248568131057377380697236238480724883073062491532254626363468032145049953168789073328812076794158602028961853986034378144749656228541552641207393473830715156452473432130040360471566096165146087202836036783304640579183082301858529818598032339821237841219774124710789761912675044056265735587753304064079484844965820681168729776560497921764083742448045654891113500035063474318442078036531813957551086231747079155691690001433127187382636049871228279519466735719768798574776353687049667125384146566107739705553580693984918816215940308884007192621418304753551998125658993859095063641090798574130161651257890916914325076137436869018454577522833
c1=14360977893873474578201937159000122429359790977572665232657843468076201963407780015131857192621550737338805880514393357390576423731328871867241029260294051045710144482989801857054158816998897546124709802730198690244128545073634486145786763294634081834588146373913232490890078533918320777534358739106486350300547206365723045306767038214923412032633833255742963954701475401704385045019069883734625251436409851588044241336835452728962860280865504000103361559688861149086469939940113748174610019620309023214292662384279070127090992947332945432141695583191136521301940116585610033790348125114471980285332011918355578839128892075058698885319243593345096734776497817461251643381989958326810478500026684389358920342021836572511688796450072700142033952403561408907486022094802237175920044147084170050294965826258250618675638343726352907476393474128674488943
E1=138906518221471521524404330039616633297752765534176570868900039237133419857485415639423196636068397237296224442083213768630488100717977884415342104239280950424735129147986053115335928783190377695248250926374734988108972136349625965753649992146322810352768246041575396721661142246729747572832017510241749082431
N2=27682578737141139764880192910976946263355689816882797515059917479242862799083599745594956880258244112867559722435850732812023189662581052511287867553308576254232706953290519059976159239205559295965110148734449650209977235953163255494808056707188551192674128213090005439928085856216617642935948961573449294338310127166077195263402939848861686214485115686799032901147314759348481062418109120418661302585413868782602282463165171129063197961455779193665041902822948963032580054067050227612838335828201043413949164885293325493829570131849345344856137656453666135670724974184749115550720826497558763320127218251970576144750319782121194483563545371157323166968983176013145267856898865437101799958588342741257457472036311490402279982286349929050116350394664561659857216725849236910894778018502118673902399095646487808462155207034764432342699549109080808769
c2=11293777290569693972360166961981727494638218221438571150393361751316389824613571820229370915191500766619410597117671232443452691634734112652285521806824284959073558010661204730954928847260946403867297932862687770449632506087883187920107766050673462588812979708792790888354008526054467620780053118019643408427959406056087370960170992834047890080269663747877143270683069575318397144844481262382463469080755423097527007161449411933936669451476467352049264455203632729909164666006688294056405955940041007137719228484035343153943155100892867641033645111253109951972003798413524003505574000784399458705347262353155363413513341797868942085136977548116650815336000627353933708913237438841909324920070013498153627767891674969586034872104569344923832761239959420543717354211689339868787331074579605476477152218068810732089913023456240425720821047030224659918
E2=138906518221471521524404330039616633297752765534176570868900039237133419857485415639423196636068397237296224442083213768630488100717977884415342104239280950424735129147986053115335928783190377695248250926374734988108972136349625965753649992146322810352768246041575396721661142246729747572832017510241749082619
Q2=wienerAttack(N1,N2)
Q1 = sympy.prevprime(Q2)
P1 = gmpy2.iroot(N1 // Q1,2)[0]
P2 = sympy.nextprime(P1)
phi1 = P1 * (P1 - 1) * (Q1 - 1)
phi2 = P2 * (P2 - 1) * (Q2 - 1)
d1 = gmpy2.invert(E1,phi1)
d2 = gmpy2.invert(E2,phi2)
m1 = pow(c1,d1,N1)
m2 = pow(c2,d2,N2)
print(long_to_bytes(m1))
print(long_to_bytes(m2))

LFSR

from Crypto.Util.number import *  
from gmpy2 import *  
from SECRET import key  
import string  
import random  
  
FLAG = b"vmc{*****************************}"  
  
def get_random_flag(flag):  
    table = string.ascii_letters+string.digits  
    for _ in range(50-len(FLAG)):  
        flag += random.choice(table).encode()  
    return flag  
  
FLAG = get_random_flag(FLAG)  
print(len(FLAG))  # 50  
print(len(key))   # 5  
  
class LFSR:  
    def __init__(self):  
        self.msg = list(map(int,list(bin(bytes_to_long(FLAG))[2:].rjust(400,'0'))))  
        for _ in range(2024):  
            self.run()  
  
    def run(self):  
        bit = self.msg[0]  
        new = 0  
        for i in key:  
            new ^= self.msg[i]  
        self.msg = self.msg[1:] + [new]  
        return bit  
  
ILOVEHUST = LFSR()  
for _ in range(2024):  
    print(ILOVEHUST.run(), end='')  
  

加密首先将flag填充至50长度。将FLAG的二进制表示转换为一个长度为400的整数列表,其中每个整数要么是0要么是1,代表二进制位。

LFSR我们知道2*n长度的密文,则可以构建矩阵求解(因为矩阵在模二情况下不可逆,我们用求解线性方程的方式求解C)

#sage
binary_str = ""  
  
# Step 2: 构造 400x400 的 LFSR 解密矩阵 X,使用 GF(2) 模  
n = 400  
X = Matrix(GF(2), n, n, lambda i, j: int(binary_str[i + j]))  
  
  
S_401 = vector(GF(2), [int(binary_str[i]) for i in range(400, 800)])  
  
    # Step 4: 解线性方程组 X * result = S_401try:  
    result = X.solve_right(S_401)  
    print("解密后的向量:", result)  
except ValueError as e:  
    print("无法解方程组:", e)  
  
one_positions = [i for i in range(len(result)) if result[i] == 1]  
print("解密向量中 1 的位置:", one_positions)

逆向运行2024次,得到初始msg

class LFSR:  
    def __init__(self, key, output_sequence):  
        self.key = key  
        # 假设从输出序列反推得到的状态  
        # 为了简化,这里初始化一个与输出序列长度相同的状态列表(实际情况中要从输出序列推算)  
        self.msg = [int(bit) for bit in output_sequence]  # 初始化为输出序列  
        for _ in range(2024):  
            self.run()  
  
    def run(self):  
        # 获取当前 LFSR 状态  
        bit = self.msg[399]  
        new = 0  
        # 根据 key 索引计算反馈值  
  
        new ^= self.msg[14]  
        new ^= self.msg[105]  
        new ^= self.msg[202]  
        new ^= self.msg[351]  
        new ^= self.msg[391]  
        # 更新 LFSR 状态  
        self.msg = [new] + self.msg[:-1]  
        #print(new)  
  
  
  
# 初始化LFSR并进行回推  
lfsr = LFSR(key, output_sequence)  
print(lfsr.msg)
msg = []
  
  
binary_string = ''.join(map(str, msg))  # 先将二进制列表拼接成一个字符串  
  
# 将二进制字符串转为整数  
integer_value = int(binary_string, 2)  
print(integer_value)  
print(long_to_bytes(integer_value))

flag还原开头字母不是v,不影响,改成v后提交。

D-H密钥交换

def generate_key(p):  
    pri_key = getrandbits(1024)  
    pub_key = pow(7, pri_key, p)  
    return pri_key,pub_key  
  
def diffie_hellman(p, flag):  
    a,A = generate_key(p)  
    b,B = generate_key(p)  
  
    superkey = pow(B, a, p)  
    m = bytes_to_long(flag)  
    return (m * superkey) % p, A, B  
  
  
def go(input:Callable[[str],None], print:Callable[[str],None]):  
    p = int(input("P = "))  
    if isPrime(p) and p.bit_length() >= 1024:  
        c, a_pubKey, b_pubKey = diffie_hellman(p, getFlag())  
        print("Alice公钥: {}".format(a_pubKey))  
        print("Bob公钥: {}".format(b_pubKey))  
        print("密文: {}".format(c))  
    else:  
        print("非法 P")

p我们自选,可以构造平滑数来使离散对数问题易解。

注意生成的是1024位,不符合的重新生成。

from Crypto.Util import number  
import random  
  
def generate_smooth_prime(bits=1024):  
    # 预先选择一组较小的质数  
    small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]  
    p = 1  
  
    # 构造 p-1,使得它由多个小质数因数组成  
    while p.bit_length() < bits - 1:  
        prime = random.choice(small_primes)  
        p *= prime  
  
    # 调整 p 使其接近 1023 位  
    remaining_bits = bits - p.bit_length()  
    if remaining_bits > 0:  
        p *= random.getrandbits(remaining_bits) | 1  # 确保生成的数字为奇数  
    p += 1  # 令 p-1 满足条件  
  
    # 检查 p 是否为素数  
    if number.isPrime(p):  
        return p  
    else:  
        return generate_smooth_prime(bits)  
  
# 生成一个符合条件的 1024 位素数  
p = generate_smooth_prime(1024)  
print("生成的素数 p:", p)  
print("p 的位数:", p.bit_length())

暴力求解

from sympy import factorint, mod_inverse, discrete_log  
  
# 给定的 p, g, A
p = 
g = 7  
A =   
  
# 使用 SymPy 库进行离散对数计算  
try:  
    a = discrete_log(p, A, g)  
    print(f"求得 a = {a}")  
except ValueError as e:  
    print("无法快速求解离散对数:", e)

正常解flag

from Crypto.Util.number import inverse, long_to_bytes  
  
p = 
g =   
A = 
B =  
c = 
  
a = 
sk = pow(B, a, p)  
  
d = inverse(sk, p)  
m = (c * d) % p  
print(long_to_bytes(m))

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇