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ć.
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
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.
Dla RSA nie da się wykonać takiej operacji.
:press_x_to_doubt:
- W praktyce używa się
e=3
alboe=65537
więc w 99% przypadków da się wygenerować klucz publiczny z prywatnego biorąc sobien
. - 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. - Co prawda sam klucz prywatny to
d,n
ale większość formatów przechowywania klucza ma tam teżp
iq
(a dla formatu RSA-CRT jeszczedp
,dq
iqinv
), a mającp
iq
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?
@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)?
Zarejestruj się i dołącz do największej społeczności programistów w Polsce.
Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.