Czy można podpisać plik za pomocą klucza ssh?

36

Używam SSH (a dokładniej OpenSSH 5.5p1 w systemie Linux). Mam klucz, na którym mam hasło. Używam tego do zwykłego logowania do komputera.

Czy mogę go również używać do podpisywania plików?

Jak rozumiem, klucz SSH jest kluczem RSA (lub DSA), a podczas procesu logowania SSH służy do podpisywania wiadomości wysyłanych na serwer. Tak więc w zasadzie i w praktyce można go używać do podpisywania rzeczy - w rzeczywistości jest to jego jedyny cel.

Ale o ile widzę, nie ma sposobu, aby użyć klucza do podpisania dowolnego pliku (tak jak w przypadku PGP, powiedzmy). Czy jest jakiś sposób, aby to zrobić?

Tom Anderson
źródło
Czy OpenSSH nie używa Ed25519 jako protokołu danych ? To tylko kwestia narzędzi.
Pablo A

Odpowiedzi:

24

Może nie być sposobu, aby to zrobić za pomocą samych narzędzi OpenSSH.

Ale można to zrobić dość łatwo za pomocą narzędzi OpenSSL. W rzeczywistości istnieją co najmniej dwa sposoby, aby to zrobić. W poniższych przykładach ~/.ssh/id_rsajest twój klucz prywatny.

Jednym ze sposobów jest użycie dgst :

openssl dgst -sign ~/.ssh/id_rsa some-file

Drugi używa pkeyutl :

openssl pkeyutl -sign -inkey ~/.ssh/id_rsa -in some-file

Oba zapisują binarny podpis na standardowe wyjście. dgst wybiera -hexopcję, aby wydrukować reprezentację tekstową z pewnymi szczegółami dotyczącymi formy podpisu. pkeyutl ma -hexdumpopcję, która jest nieco mniej przydatna. Oba zaakceptują zarówno klucze RSA, jak i DSA. Nie mam pojęcia, jaki jest format wyjściowy. Oba polecenia tworzą różne formaty. Mam wrażenie, że pkeyutl jest uważany za bardziej nowoczesny niż dgst .

Aby zweryfikować te podpisy:

openssl dgst -verify $PUBLIC_KEY_FILE -signature signature-file some-file

i:

openssl pkeyutl -verify -inkey $PUBLIC_KEY_FILE -sigfile signature-file -in some-file

Problem jest tutaj $PUBLIC_KEY_FILE. OpenSSL nie może odczytać formatu klucza publicznego OpenSSH, więc nie możesz po prostu używać id_rsa.pub. Masz kilka opcji, żadna idealna.

Jeśli masz wersję OpenSSH w wersji 5.6 lub nowszej, najwyraźniej możesz to zrobić:

ssh-keygen -e -f ~/.ssh/id_rsa.pub -m pem

Który zapisze klucz publiczny na standardowym wyjściu w formacie PEM, który OpenSSL może odczytać.

Jeśli masz klucz prywatny i jest to klucz RSA, możesz z niego wyodrębnić klucz publiczny (zakładam, że plik klucza prywatnego zakodowany w PEM zawiera kopię klucza publicznego, ponieważ nie można uzyskać klucza publicznego z samego klucza prywatnego) i użyj tego:

openssl rsa -in ~/.ssh/id_rsa -pubout

Nie wiem, czy istnieje odpowiednik DSA. Zauważ, że takie podejście wymaga pewnej współpracy ze strony właściciela klucza prywatnego, który będzie musiał wyodrębnić klucz publiczny i wysłać go do potencjalnego weryfikatora.

Na koniec możesz użyć programu w języku Python napisanego przez faceta o nazwie Lars, aby przekonwertować klucz publiczny z OpenSSH na format OpenSSL.

Tom Anderson
źródło
1
Chciałbym tylko zauważyć, że „nie można uzyskać klucza publicznego z samego klucza prywatnego” nie jest prawdą. W praktyce (to znaczy we wszystkich faktycznie używanych kryptosystemach) klucz publiczny jest łatwo uzyskiwany z klucza prywatnego przez większość czasu.
kirelagin
@kirelagin: Nie wiedziałem tego. Czy możesz mi powiedzieć lub link do mnie, aby uzyskać więcej informacji o tym, jak to zrobić?
Tom Anderson
1
Nie jestem pewien, czy jest jakaś konkretna lektura na ten temat… Zastanówmy się. Weź dowolny dyskretny system kryptograficzny (ElGamal). W tym przypadku klucz prywatny to (rozmiar grupy, generator, moc), a klucz publiczny to (rozmiar grupy, generator, moc generatora). Więc log jest trudny, ale moc nie jest, po prostu go obliczasz.
kirelagin
W przypadku RSA ta inwersja jest w rzeczywistości trudna, ale tutaj sytuacja jest nieco inna. Klucz publiczny to (n, d), a klucz prywatny to (n, d ^ (- 1) mod phi (n)). Odwrócenie d byłoby również trudne, gdybyś nie zapisał phi (n), ale oto sztuczka: prawie wszyscy używają e = 65537 (podczas generowania klucza istnieje możliwość zmiany tego ustawienia domyślnego, ale nigdy nie widziałem każdy, kto go używa, ponieważ nie ma to praktycznego sensu), więc uzyskanie klucza publicznego od prywatnego jest banalne.
kirelagin
W przypadku krzywych eliptycznych jest tak samo jak w przypadku dyskretnego logu i mocy, odwracanie jest łatwe. To powiedziawszy, nie jestem pewien co do innych kryptosystemów, ale te trzy są tymi, które są używane w praktyce.
kirelagin
10

@ Odpowiedź Toma pomogła mi zacząć, ale nie wyszła z pudełka.

Te polecenia będą działać z:

  • OpenSSL 1.0.1 14 marca 2012
  • OpenSSH_5.9p1

Korzystanie z pkeyutl

# openssl pkeyutl -sign -inkey ~/.ssh/id_sample -in $1 > $1.sig
# ssh-keygen -e -f ~/.ssh/id_sample.pub -m PKCS8 > pub
# openssl pkeyutl -verify -pubin -inkey pub -in $1 -sigfile $1.sig
Signature Verified Successfully

Korzystanie z dgst

# openssl dgst -sign ~/.ssh/id_sample $1 > $1.sig
# ssh-keygen -e -f ~/.ssh/id_sample.pub -m PKCS8 > pub
# openssl dgst -verify pub -signature $1.sig $1
Verified OK

Wersja pkeyutl może podpisywać tylko małe pliki. Podczas gdy dgst może podpisywać dowolnie duże pliki, ponieważ wymaga podpisu przed podpisaniem wyniku.

stephen.z
źródło
Dla mnie również odpowiedź Stephen.z działała od razu po wyjęciu z pudełka. Najpierw bawiłem się przez chwilę odpowiedzią Toma i wreszcie znalazłem odpowiedź Stephen.z, która działa idealnie dla mnie. Dzięki Stephen.z!
Grzegorz Wierzowiecki
PS Tutaj udostępniłem moje fragmenty: gist.github.com/gwpl/2c7636f0b200cbfbe82cc9d4f6338585
Grzegorz
Czy próbowałeś użyć pkeyutl do podpisania tylko skrótu pliku?
Gaia,
-3

Aby zweryfikować te podpisy - łatwiejsze rozwiązanie:

Łatwiejszym sposobem upewnienia się, że podpisany dokument jest taki sam, jest ponowne wygenerowanie pliku podpisu cyfrowego, a następnie użycie mechanizmu różnicowego do sprawdzenia, czy dwa pliki podpisu są takie same.

Ehrhardt Le Grange
źródło
3
Myślisz o hashach , a nie o podpisach . Podobne, ale nie to samo: skrót tylko sprawdza, czy plik się nie zmienił; podpis weryfikuje również, skąd przyszedł.
Piskvor