2015-08-20 71 views
6

Mam plik zawierający publiczny klucz RSA (wygenerowany przy użyciu ssh-keygen). Chciałbym przeczytać plik i wygenerować obiekt PublicKey.Jak wygenerować obiekt PublicKey z pliku w Javie

Wcześniej I konwertowane pliku, ponieważ czytanie oryginalnych plików wydaje się niemożliwe:

# http://unix.stackexchange.com/questions/220354/how-to-convert-public-key-from-pem-to-der-format/220356#220356 
ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PEM > ~/.ssh/id_rsa.pub.pem 
openssl rsa -RSAPublicKey_in -in ~/.ssh/id_rsa.pub.pem -inform PEM -outform DER -out ~/.ssh/id_rsa.pub.der -RSAPublicKey_out 

Od Java - Encrypt String with existing public key file zdefiniowałem funkcję readFileBytes:

public static byte[] readFileBytes(String filename) throws IOException { 
    Path path = Paths.get(System.getProperty("user.home") + filename); 
    return Files.readAllBytes(path); 
} 

Teraz chciałabym przeczytaj plik i wygeneruj obiekt PublicKey, ale nie mogłem znaleźć sposobu na jego wykonanie; java.security.spec.RSAPublicKeySpec nie zapewnia konstruktora montażu i java.security.spec.X509EncodedKeySpec zgłasza błąd java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence:

//RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(readFileBytes("/.ssh/id_rsa.pub.der")); 
// No fitting construktor 

X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(readFileBytes("/.ssh/id_rsa.pub.der")); 
// Gives: "algid parse error, not a sequence" 

Odpowiedz

5

miałem projekt, w którym (RSA) szyfrowanie było konieczne, to jak ja przebudował publicKey biorąc pod uwagę publicKey „s byte tablicę, że został właśnie odczytany z pliku.

public PublicKey reconstruct_public_key(String algorithm, byte[] pub_key) { 
    PublicKey public_key = null; 

    try { 
     KeyFactory kf = KeyFactory.getInstance(algorithm); 
     EncodedKeySpec pub_key_spec = new X509EncodedKeySpec(pub_key); 
     public_key = kf.generatePublic(pub_key_spec); 
    } catch(NoSuchAlgorithmException e) { 
     System.out.println("Could not reconstruct the public key, the given algorithm oculd not be found."); 
    } catch(InvalidKeySpecException e) { 
     System.out.println("Could not reconstruct the public key"); 
    } 

    return public_key; 
} 

Następnie można wywołać procedurę podobną do tej rozmowy, reconstruct_public_key("RSA", readFileBytes("path/to/your/publicKey/file"));

EDIT: Próbowałem zrobić to sam (zapis klucza publicznego do pliku, odczytać ten plik i odtworzyć klucza). To działa:

public static void main(String args[]) { 
    String path = "./pub_key_test.txt"; 

    // Generate a keypair to write to file 
    KeyPair kp = generate_key(); 
    PublicKey pub_key = kp.getPublic(); 
    File file = new File(path); 

    try { 
     // Write to file 
     file.createNewFile(); 
     FileOutputStream out = new FileOutputStream(path); 

     out.write(pub_key.getEncoded()); // Write public key to the file 
     out.close(); 

     // Read from file 
     FileInputStream in = new FileInputStream(path); 
     byte[] pub_key_arr = new byte[in.available()]; 
     in.read(pub_key_arr, 0, in.available()); 
     in.close(); 

     // Reconstruct public key 
     PublicKey reconstructed_pub_key = reconstruct_public_key("RSA", pub_key_arr); 
    } catch(IOException e) { 
     System.out.println("Could not open the file : " + e.getStackTrace()); 
    } 
} 

I to jest procedura generate_key:

public KeyPair generate_key() { 
    while(true) { // Else the compiler will complain that this procedure does not always return a "KeyPair" 
     try { 
      final KeyPairGenerator key_generator = KeyPairGenerator.getInstance("RSA"); 
      key_generator.initialize(2048); // Keys of 2048 bits (minimum key length for RSA keys) are safe enough (according to the slides 128bit keys > 16 years to brute force it) 

      final KeyPair keys = key_generator.generateKeyPair(); 
      return keys; 
     } catch(NoSuchAlgorithmException e) { 
      System.out.println("The given encryption algorithm (RSA) does not exist. -- generate_key() - Cryptography."); 
     } 
    } 
} 

Jeśli to sprawdzić, widać, że publicKey jest zrekonstruowany pomyślnie.

EDYCJA: Próbowałem zrobić to sam, używając narzędzia ssh-keygen. To co zrobiłem:

  • Najpierw wygenerowany klucz prywatny RSA (format .PEM)
  • wyprowadzane kluczową część publicznego do formatu .DER, dzięki czemu może być używany przez Java.

ten sposób zrobiłem konwersję, który jest nieco inny od Ciebie:

openssl rsa -in private_key_file.pem -pubout -outform DER -out java_readable_file.der 

I zrobiłem plik czytanie jak here, który nie różni się wiele od Ciebie. Przetestowałem to i Java z powodzeniem zrekonstruowała klucz publiczny.

+0

Cóż, niż ja zawsze „Nie można odtworzyć klucza publicznego” - ale ja nadal nie wiem dlaczego klucz publiczny nie może być odtworzone, ... Może coś poszło nie tak podczas conversion- proces, ale co? Byłoby również świetnie mieć sposób na odczytanie bezpośrednio wygenerowanych plików 'ssh-keygen', bez ręcznej konwersji w terminalu. – Edward

+0

@Edward Edytowałem swoją odpowiedź, aby odpowiedzieć na twoje pytanie. – HyperZ

+0

Próbuję odczytać istniejące klucze, które zostały wygenerowane za pomocą narzędzia 'ssh-keygen' (zazwyczaj w' ~/.ssh/id_rsa.pub'). Wydają się być w formacie "PEM". Udało mi się odczytać klucz prywatny z '~/.ssh/id_rsa', ale czytanie klucza publicznego nie działa. To naprawdę wydaje się być problemem z plikami wygenerowanymi przez 'ssh-keygen' (mam nadzieję, że teraz jest jasne). [+1 na Twój przykład] – Edward

4

Tworzenie RSA klucz prywatny

openssl genrsa -out rsaprivkey.pem 1024

Generuje klucza publicznego w formacie DER.

openssl rsa -in rsaprivkey.pem -pubout -outform DER -out rsapubkey.der

Używamy ten kod wydobywa klucz publiczny RSA lub DSA z certyfikatu X.509.

import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.security.KeyFactory; 
import java.security.NoSuchAlgorithmException; 
import java.security.PublicKey; 
import java.security.cert.CertificateException; 
import java.security.cert.CertificateFactory; 
import java.security.cert.X509Certificate; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.X509EncodedKeySpec; 

/** 
* This class is capable of extracting a public key from a X.509 certficate 
* and returning the PublicKey representation from a referenced byte array. 
* 
*/ 
public class ExtractPublicKey { 

    // Certificate Filename (Including Path Info) 
    private static final String certFilename = "cacert.pem"; 

    // Public Key Filename (Including Path Info) 
    private static final String pubKeyFilename = "rsapublic.key"; 

    public static PublicKey generatePublicKey(byte[] encodedKey) 
     throws NoSuchAlgorithmException, InvalidKeySpecException { 

    X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(encodedKey); 
    boolean isSupportedKey = false; 
    KeyFactory factory; 
    PublicKey retKey = null; 

    //first try the DSA alg 
    try { 
     factory = KeyFactory.getInstance("DSA"); 
     retKey = factory.generatePublic(pubSpec); 
     isSupportedKey = true; 
    } catch (InvalidKeySpecException e) { 
     System.out.println("Could not create DSA Public Key: " + e.toString());  
    } 

    //if DSA didnt work, then try RSA  
    if (!isSupportedKey) { 
     try { 
     factory = KeyFactory.getInstance("RSA"); 
     retKey = factory.generatePublic(pubSpec); 
     isSupportedKey = true; 
     } catch (InvalidKeySpecException e) { 
     System.out.println("Could not create RSA Public Key: " + e.toString()); 
     }  
    } 

    // if not DSA or RSA 
    if (!isSupportedKey) { 
     throw new InvalidKeySpecException("Unsupported key spec: Not RSA or DSA"); 
    } 

    return retKey; 
    } 

} 
+0

Zapewniamy SSO dla aplikacji Google i do wydobywania klucza publicznego z x509 używamy powyższego kodu. I to jest kod Java, a nie kod aplikacji Google. Działa to również dobrze w naszym drugim projekcie. Jeśli chcesz uzyskać więcej informacji Jak wyodrębnić LUB Jak wygenerować klucz Sprawdź ten link. https://developers.google.com/google-apps/help/articles/sso-keygen#creating-rsa-key-pairs –