Blockchain. Generowanie klucza publicznego i prywatnego

0

Piszę sobie blockchaina w Java. Nie jestem specjalistą od blockchaina i mam takie pytanko. Każdy portfel ma swój klucz publiczny i klucz prywatny, przez który ma się dostęp. Oprogramowałem już generowanie bloków, nadawanie im hashów, wykonywanie transakcji, które mają również hashe i przesyłanie krypto poprzez te transakcje, które umieszczam w blokach. Jednak do tej pory ustawiałem na sztywno klucz publiczny, jakiś byle jaki ciąg znaków, żeby te transakcje miały nadawcę i odbiorcę. Teraz chciałbym napisać już algorytm do generowania klucza publicznego i prywatnego. Nie wiem czy te dwa klucze muszę być generowanie z siebie, czy nie mają nic wspólnego lub jaki algorytm hashowania użyć.

1

Nie wiem czy te dwa klucze muszę być generowanie z siebie, czy nie mają nic wspólnego lub jaki algorytm hashowania użyć.

No muszą być z siebie bo to jest para kluczy. O to właśnie w tym wszystkim chodzi, że publiczny możesz udostępnić każdemu i ktoś zaszyfruje nim jakąś wiadomość, ale odczyta ją tylko posiadacz klucza prywatnego.

Nie wiem jaki algorytm bo się nie znam na kryptografii ale możesz zobaczyć jak to jest zrobione w innych projektach. W Bitcoinie na pewno była używana arytmetyka krzywych eliptycznych. O takie coś: https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm

Do poczytania jeszcze fajna książka o Bitcoinie właśnie. Tutaj rozdział "Keys, Addresses" gdzie wszystko jest opisane:
https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc

2

Zależy jakiego algorytmu szyfrowania użyjesz. Dla krzywych eliptycznych możliwe jest wygenerowanie klucza publicznego z klucza prywatnego. Dla RSA nie da się wykonać takiej operacji.
Algorytm hashowania to osobna kwestia od samego podpisu / szyfrowania. Dla potwierdzenia, że jakaś porcja danych jest "podpisana" nie potrzebowałbyś jej hasha, bo można ją podpisać w całości (np. szyfrując kluczem prywatnym RSA), ale wtedy podpis zajmowałby ~tyle co dane, w dodatku asymetryczne metody szyfrowania są wolne. Dlatego stosuje się skrócenie danych do sygnatury (np. SHA256), otrzymujesz 8 bajtów, które podpisujesz. i w efekcie dostajesz podobnej długości sygnaturę.

Użycie funkcji hash jest okupione wystawieniem się na atak na tę część podpisu, bo skoro masz np. 10kB lub więcej danych, a skróty tych danych to jedynie 8 bajtów, to istnieje nieskończona liczba różnych danych, które dadzą ten sam wynik funkcji hashującej. Atakujący może więc przygotować porcję danych, którą chce podpisać, następnie zmieniać nieistotne z jego punktu widzenia jej części, tak długo jak uzyska taki sam hash jak w oryginalnym wpisie. Obchodzi się to poprzez zwielokrotnienie liczby rund hashujących. Czyli tworzysz sobie ciąg n = hash(n-1) i im on jest dłuższy, tym dłużej potrwa wykonanie skutecznego ataku przy założeniu użycia takiej samej mocy obliczeniowej.

Z praktycznej strony - użytkownik jest w stanie przechowywać w głowie jedynie hasło. W przypadku krzywych eliptycznych (ECC) można na podstawie tego hasła wygenerować klucz prywatny a z niego klucz publiczny, nie ma więc potrzeby bezpiecznego przechowywania czegokolwiek innego niż właśnie hasło.
W przypadku RSA potrzebujesz znaleźć 2 duże liczby pierwsze (nie do zapamiętania) na ich podstawie wygenerować klucz prywatny i klucz publiczny (też nie do zapamiętania), klucz prywatny musisz trzymać w bezpiecznym miejscu (np. w formie zaszyfrowanej na dysku). Do podpisania danych w przypadku ECC potrzebujesz jedynie użytkownika, który nie zapomniał hasła, do podpisu opartego na RSA potrzebujesz już danych, które musisz "gdzieś" przechowywać. W Java masz gotowe do użycia algorytmy szyfrujące oparte zarówno o RSA, jak i ECC.

Disclajmer - moja wiedza o kryptografii jest dość pobieżna, a i to, głównie od praktycznej strony. Jeżeli napisałem tu jakieś kompletne głupoty, to będę wdzięczny za ich wytknięcie, a gdyby ktoś faktycznie chciał zrobić "coś", gdzie bezpieczeństwo ma znaczenie, to polecam poszukać i skonsultować swój pomysł z jakimiś specjalistami konkretnie w tej dziedzinie. O ile można sobie skorzystać z gotowych algorytmów dostępnych w bibliotekach, to już łączenie ich w jakiś spójny system potrafi wygenerować sporo luk.

0

@piotrpo:

Dla RSA nie da się wykonać takiej operacji.

:press_x_to_doubt:

  1. W praktyce używa się e=3 albo e=65537 więc w 99% przypadków da się wygenerować klucz publiczny z prywatnego biorąc sobie n.
  2. Nawet jeśli użyje się innego e to zwykle jest bardzo małe więc można by je policzyć za pomocą ataku Wienera.
  3. Co prawda sam klucz prywatny to d,n ale większość formatów przechowywania klucza ma tam też p i q (a dla formatu RSA-CRT jeszcze dp, dq i qinv), a mając p i q można sobie policzyć e = modinv(phi(n)) bez problemu.

Niemniej faktycznie w przypadku ogólnym, mając tylko modulus i jedną z eksponent nie da się wyliczyć drugiej eksponenty.

bo można ją podpisać w całości (np. szyfrując kluczem prywatnym RSA), ale wtedy podpis zajmowałby ~tyle co dane, w dodatku asymetryczne metody szyfrowania są wolne

Nie, nie mógłbyś, bo RSA co do zasady pozwala pracować z danymi mniejszymi niż n. Wiec to nie problem rozmiaru podpisu, co problem rozmiaru klucza.

@Jonki1997: nie do końca rozumiem co chcesz zrobić tutaj. Chcesz napisać sobie obsługę jakiegoś istniejącego blockchaina czy napisać od zera własny?

0

@Shalom: Pierwsze uwaga ok, druga - każdy (współczesny) szyfr ma jakiś maksymalny rozmiar obsługiwanego bloku danych. Co stoi na przeszkodzie podzielić sobie dane na części i każdą z nich zaszyfrować w ten sam sposób RSA? Piszę czysto teoretycznie, bo o potencjalnym osłabieniu bezpieczeństwa przez występowanie tożsamych zaszyfrowanych bloków wiem, jak również zgadzam się, że nie ma możliwości wykorzystania mechanizmów typowych dla symetrycznych szyfrów blokowych (typu CBC, czy CTR)?

1 użytkowników online, w tym zalogowanych: 0, gości: 1