2009-10-16 14 views
13

Próbuję użyć certyfikatu PEM (X.509) (przechowywanego w pliku privateKey.pem na dysku) do podpisywania wiadomości wysyłanych przez gniazda w języku Java, ale mam dużo problemów ze znalezieniem przykładu, który jest blisko. Zwykle jestem facetem w C++, który właśnie wkracza do pomocy przy tym projekcie, więc było mi trochę trudniej złożyć to wszystko razem w kod, który działa, gdy nie jestem zaznajomiony z interfejsami API.Używanie zakodowanego, zaszyfrowanego klucza prywatnego PEM do podpisania wiadomości natywnie

Niestety, jestem ograniczony do metod, które są standardowo w Javie (1.6.0 Aktualizacja 16), więc chociaż znalazłem podobny przykład przy użyciu PEMReader, to nie pomogło wiele w tym konkretnym projekcie.

klucz

My privateKey.pem jest hasło chronione, w postaci:

-----BEGIN RSA PRIVATE KEY----- 
Proc-Type: 4,ENCRYPTED DEK-Info: 
DES-EDE3-CBC,63A862F284B1280B 
[...] 
tsjQI4H8lhOBuk+NelHu7h2+uqbBQzwkPoA8IqbPXUz+B/MAGhoTGl4AKPjfm9gu 
OqEorRU2vGiSaUPgDaRhdPKK0stxMxbByUi8xQ2156d/Ipk2IPLSEZDXONrB/4O5 
[...] 
-----END RSA PRIVATE KEY----- 

one klucz został wygenerowany przy użyciu OpenSSL:

openssl.exe genrsa -out private_key.pem 4096 

jestem w stanie przekształcić ten klucz do DER lub inny format przed uruchomieniem, wszelkie niezbędne konwersje będą musiały być wykonane wewnętrznie w kodzie, ponieważ klucz musi być łatwo wymienny, a format pozostanie PEM.

Słyszałem mieszankę rzeczy, których nie jestem do końca pewny, i miałem nadzieję, że zbiorowe umysły tutaj w SO mogą pomóc zebrać kawałki razem.


Słyszałem, że powiedział, że certyfikat PEM wymaga dekodowania Base64 w celu przekształcenia go w certyfikat DER, który może być używany. Mam narzędzie dekodowania Base64 o nazwie MiGBase64, ale nie jestem całkowicie pewny, jak/kiedy to dekodowanie wymaga.


Zgubiłem się w dokumentach API Java próbujących wyśledzić 15 różnych rodzajów kluczy, kluczyków, kluczowych generatorów, certyfikatów itp., Ale nie jestem dostatecznie zaznajomiony z żadnym z nich, aby prawidłowo zidentyfikować których muszę używać i jak z nich korzystać.


Algorytm podstawowy wydaje się dość prosta, dlatego został on szczególnie frustrujące, że nie byłem w stanie napisać równie prosty realizacji:

1) Przeczytaj privateKey.pem z pliku
2) Załaduj prywatny klucz do klasy XXX, stosując hasło dostępu do odszyfrowania klucza
3) za pomocą klucza obiektu z klasą podpis do podpisania wiadomości



w tym pomóc, Espec przykładowy kod jest bardzo doceniany. Starałem się znaleźć użyteczne przykłady tego problemu, ponieważ większość "zamkniętych" przykładów generuje nowe klucze, używając BouncyCastle, lub po prostu używa innych form kluczy/klas, które nie mają tutaj zastosowania.

To wydaje się być naprawdę prostym problemem, ale doprowadza mnie to do szału, czy naprawdę proste odpowiedzi?

Odpowiedz

19

Jeśli używasz BouncyCastle, spróbuj wykonać następujące czynności:

import java.io.File; 
import java.io.FileReader; 
import java.io.IOException; 
import java.security.KeyPair; 
import java.security.Security; 
import java.security.Signature; 
import java.util.Arrays; 

import org.bouncycastle.jce.provider.BouncyCastleProvider; 
import org.bouncycastle.openssl.PEMReader; 
import org.bouncycastle.openssl.PasswordFinder; 
import org.bouncycastle.util.encoders.Hex; 

public class SignatureExample { 

    public static void main(String [] args) throws Exception { 
     Security.addProvider(new BouncyCastleProvider()); 

     String message = "hello world"; 
     File privateKey = new File("private.pem"); 
     KeyPair keyPair = readKeyPair(privateKey, "password".toCharArray()); 

     Signature signature = Signature.getInstance("SHA256WithRSAEncryption"); 
     signature.initSign(keyPair.getPrivate()); 
     signature.update(message.getBytes()); 
     byte [] signatureBytes = signature.sign(); 
     System.out.println(new String(Hex.encode(signatureBytes))); 

     Signature verifier = Signature.getInstance("SHA256WithRSAEncryption"); 
     verifier.initVerify(keyPair.getPublic()); 
     verifier.update(message.getBytes()); 
     if (verifier.verify(signatureBytes)) { 
      System.out.println("Signature is valid"); 
     } else { 
      System.out.println("Signature is invalid"); 
     } 
    } 

    private static KeyPair readKeyPair(File privateKey, char [] keyPassword) throws IOException { 
     FileReader fileReader = new FileReader(privateKey); 
     PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword)); 
     try { 
      return (KeyPair) r.readObject(); 
     } catch (IOException ex) { 
      throw new IOException("The private key could not be decrypted", ex); 
     } finally { 
      r.close(); 
      fileReader.close(); 
     } 
    } 

    private static class DefaultPasswordFinder implements PasswordFinder { 

     private final char [] password; 

     private DefaultPasswordFinder(char [] password) { 
      this.password = password; 
     } 

     @Override 
     public char[] getPassword() { 
      return Arrays.copyOf(password, password.length); 
     } 
    } 
} 
+0

Dzięki za czas i wysiłek, który poszedł do swojej odpowiedzi. Musiałem wprowadzić kilka modyfikacji, aby działało to z moimi kluczami, ale ty prowadzisz. Bardzo doceniane! – KevenK

+1

@KevenK Dobrze słyszeć. Jakie modyfikacje były konieczne? – Kevin

4

Komenda OpenSSL generowania pary kluczy i koduje je w formacie PKCS # 1. Jeśli nie używasz szyfrowania (nie dostarczyłeś hasła do polecenia), PEM jest po prostu DER zakodowany w Base64 dla klucza RSAPrivateKey PKCS # 1.

Niestety, firma Sun's JCE nie udostępnia publicznego interfejsu do odczytu klucza w tym formacie. Masz 2 opcje,

  1. Zaimportuj klucz do magazynu kluczy, z którego możesz go odczytać. Keytool nie pozwala na importowanie kluczy prywatnych. Możesz znaleźć inne narzędzia do tego.

  2. Biblioteka OAuth ma do tego funkcję. Spójrz na kod tutaj,

http://oauth.googlecode.com/svn/code/java/core/commons/src/main/java/net/oauth/signature/pem/PKCS1EncodedKeySpec.java

+0

Przydatne informacje, dziękuję za poświęcenie czasu na odpowiedź :) Poszedłem z BouncyCastle, ponieważ wydawało się, że pasuje do mojego konkretnego zastosowania, ale doceniam pomoc. Dzięki – KevenK

Powiązane problemy