2009-10-16 2 views
13

Sto provando a utilizzare un certificato PEM (X.509) (memorizzato in un file privateKey.pem sul disco) per firmare i messaggi inviati tramite socket in Java, ma sto avendo molti problemi a trovare un esempio così vicino. Normalmente sono un ragazzo C++ che sta solo intervenendo per aiutare in questo progetto, quindi è stato un po 'difficile per me mettere tutto insieme in un codice che funzioni quando non ho familiarità con le API.Utilizzo di una chiave privata codificata PEM codificata per firmare un messaggio in modo nativo

Sfortunatamente, sono limitato ai metodi che vengono forniti standard con Java (1.6.0 Aggiornamento 16), quindi sebbene abbia trovato un esempio simile usando BouncyCastle di PEMReader, non ha aiutato molto questo particolare progetto.

chiave

mio privateKey.pem è passphrase protetta, sotto forma di: utilizzare

-----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----- 

Essi chiave è stato generato OpenSSL:

openssl.exe genrsa -out private_key.pem 4096 

non sono in grado di convertire questo tasto per un DER o altro formato prima del runtime, tutte le conversioni necessarie dovranno essere eseguite internamente nel codice, in quanto la chiave deve essere facilmente sostituibile e il formato rimarrà PEM.

Ho sentito un mix di cose di cui non sono completamente sicuro e speravo che le menti collettive qui in SO potessero aiutare a mettere insieme i pezzi.



Ho sentito dire che il certificato PEM necessita Base64 Decodificato per convertirlo in un certificato DER che può essere utilizzato. Ho uno strumento di decodifica Base64 chiamato MiGBase64 ma non sono completamente sicuro di come/quando questa decodifica deve essere eseguita.


Mi sono perso nei documenti API Java cercando di rintracciare i 15 diversi tipi di chiavi, KeyStores, KeyGenerator, certificati, ecc che esistono, ma non ho familiarità con nessuno di loro per identificare correttamente che devo usare e come usarli insieme.


L'algoritmo di base sembra abbastanza semplice, è per questo che è stato particolarmente frustrante che non sono stato in grado di scrivere un altrettanto semplice implementazione:

1) Leggere il privateKey.pem da file
2) Caricare la chiave privata in classe XXX, utilizzando la passphrase per decifrare la chiave
3) utilizzare l'oggetto chiave con la classe firma per firmare il messaggio



Aiuto di questa, espec codice di esempio, è molto apprezzato. Ho faticato a trovare utili esempi per questo problema, in quanto molti esempi "vicini" generano nuove chiavi, utilizzando BouncyCastle o semplicemente utilizzando forme diverse di chiavi/classi non applicabili qui.

Questo sembra un problema davvero semplice ma mi sta facendo impazzire, qualche risposta davvero semplice?

risposta

19

Se stai usando BouncyCastle, provare quanto segue:

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

Grazie per il tempo e lo sforzo che è andato in vostra risposta. Ho dovuto apportare alcune modifiche per farlo funzionare con le mie chiavi, ma tu sei il leader. Molto apprezzato! – KevenK

+1

@KevenK Buono a sapersi. Quali modifiche erano necessarie? – Kevin

4

Il comando OpenSSL generare coppia di chiavi e di codifica in formato PKCS # 1. Se non si utilizza la crittografia (non ha fornito la password per il comando), il PEM è semplicemente DER codificato Base64 per PKCS # 1 RSAPrivateKey.

Sfortunatamente, JCE di Sun non fornisce un'interfaccia pubblica per leggere la chiave in questo formato. Hai 2 opzioni,

  1. Importa la chiave nella chiavi e si può leggere da lì. Keytool non consente l'importazione di chiavi private. Puoi trovare altri strumenti per farlo.

  2. La libreria OAuth ha una funzione per gestirlo. Guardate il codice qui,

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

+0

Informazioni utili, grazie per aver trovato il tempo di rispondere :) Sono andato con BouncyCastle perché sembrava adattarsi al mio uso particolare, ma apprezzo l'aiuto. Grazie – KevenK