Puncte:0

Ajută la spargerea ECDSA cu non-uri părtinitoare

drapel cn

În prezent încerc să fac Provocarea criptopalilor 62, rupând ECDSA cu non-uri părtinitoare, cu ajutorul acelor două legături (1 2) care descriu cu exactitate atacul. Cu toate acestea, după aproximativ 15 ore, încă nu pot să funcționeze și nu am absolut nicio idee unde am greșit.

Iată cum am făcut-o (folosind Python 3.6): În primul rând, pentru a genera semnăturile cu nonces defecte (am luat același model ca cel pe care îl folosesc acele linkuri, deci cei 8 biți LSB sunt zero):

import ecdsa
de la import aleatoriu randint

gen = ecdsa.SECP256k1.generator
ordine = gen.order()
d = randint(1, ordine)

pub = ecdsa.ecdsa.Public_key(gen, gen*d)
priv = ecdsa.ecdsa.Private_key(pub, d)

R = []
S = []

pentru i în interval (100):
    nonce = randint(1, ordine)
    nonce ^= (nonce și 0xff)
    semnat = priv.sign(h, nonce)
    R.apend(semnat.r)
    S.apend(semnat.s)

apoi atacul propriu-zis, care este destul de scurt: calculăm câteva numere, construim o matrice cu ele, apelăm algoritmul LLL și ar trebui să găsim în baza redusă valoarea -d*ct chiar lângă a cu unul, conform link-urilor:

Construirea matricei:

h = 1337
N_SIGNATURE = 100

M = [[0 pentru i în interval (N_SIGNATURE + 2)] pentru j în interval (N_SIGNATURE + 2)]

pentru i în interval (N_SIGNATURE):
    M[i][i] = ordin

ct = gmpy2.invert(256, ordine) # 2**l cu l = biți cunoscuți
cu = ordin * ct
M[-2][-2] = int(ct)
M[-1][-1] = int(cu)

pentru i în interval (N_SIGNATURE):
    M[-2][i] = int(R[i] * gmpy2.invert(S[i] * 256, ordine)) % ordine # t_i
    M[-1][i] = int( -h * gmpy2.invert(S[i] * 256, ordine)) % ordine # u_i

Folosind foarte eficient fplll lib (această parte este un pic neplăcută și va fi rescrisă folosind Sage, dar funcționează. Aici, fac în principal formatarea pe matrice, astfel încât să poată fi introdusă pentru fplll și convertesc rezultatul înapoi într-o matrice):

str_M = str(M).replace(",", "")
os.system("echo " + str_M + " | fplll -a lll -m dovedit -f mpfr > rezultat.txt")

matrice_nouă = [[0 pentru i în interval (N_SIGNATURE+2)] pentru j în interval (N_SIGNATURE+2)]

cu open("result.txt", "r") ca fișierul meu:
    conținut = myfile.read()
    contents = contents.replace("[", "").replace("]", "").replace("\n", "").split(" ")
    conținut = conținut[:-1] # există o linie goală la sfârșit

    assert(len(conținut) == pow(N_SIGNATURE + 2, 2))

    i = 0
    j = 0
    pentru v în conținut:
        matrice_nouă[i][j] = int(v)
        j += 1
        dacă j == N_SEMNATURĂ + 2:
            j = 0
            i += 1

Obținerea d:

pentru rândul din new_matrix:
    if(rând[-1] == cu):
        d2 = (-row[-2] * gmpy2.invert(ct, order)) % ordin
        
        dacă(d2 == d):
            print("Cheie secretă recuperată")


Cu toate acestea, indiferent câte variabile ajust și lucruri pe care le încerc, nu pot obține un rezultat. De asemenea, am încercat să scanez întreaga matrice în loc de ultimele elemente, fără succes. Am făcut o greșeală prostească pe care nu am observat-o sau este ceva destul de greșit în codul meu?

Notă: următorul rând din linkul 2:

Am uitat să menționez: veți dori să vă scrieți implementarea pentru a lucra pe vectori de raționali. Dacă aveți flotoare de precizie infinită, și acestea vor funcționa.

mi-a atras atenția, dar mpfr argumentul fplll ar trebui să se potrivească cu ceea ce este necesar aici.Și în caz că nu, am încercat și eu să folosesc o matrice Sage definită peste QQ, dar nu funcționează mai bine.

Puncte:3
drapel ph

Trebuie să fii puțin atent la mai multe lucruri:

  1. numărul fracționar $\frac{1}{2^l}$ nu este inversul ordinului mod 2^l.

  2. după reducerea rețelei, intrările din matricea de bază ar putea fi valori negative, astfel încât afirmația if(row[-1] == cu) ar putea să nu fie complet corectă.

  3. rețineți că ordinea - d este, de asemenea, o soluție a inegalităților HNP, deci ar putea fi sigur să le verificați pe ambele. De obicei, reducerea rețelei va duce la cea mai mică dintre d și ordinul - d.

  4. vectorul dorit s-ar putea să nu fie primul vector al bazei reduse, așa că puteți verifica toate rândurile.

Pentru ECDSA de 256 de biți cu scurgeri de 8 biți, cred că 50 (chiar 40) este suficient.

Katoptriss avatar
drapel cn
Iti multumesc foarte mult pentru raspunsul tau. Doar repararea punctului 1 a făcut ca totul să funcționeze imediat. Nu aș fi ghicit niciodată că este nevoie de o fracție obișnuită aici, deoarece totul este modulo ordine și diviziunile sunt calculate cu inversul modular.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.