2010-09-14 14 views
12

Sto cercando un modo per creare in modo programmabile i file id_rsa e id_rsa.pub compatibili con ssh in Java.Come generare id_rsa compatibile con ssh (.pub) da Java

ho avuto per quanto riguarda la creazione della coppia di chiavi:

KeyPairGenerator generator; 
generator = KeyPairGenerator.getInstance("RSA"); 
// or: generator = KeyPairGenerator.getInstance("DSA"); 
generator.initialize(2048); 
keyPair = generator.genKeyPair(); 

io non riesco a capire però come creare la rappresentazione String del PrivateKey e PublicKey nella coppia di chiavi.

+0

possibile duplicato di [Dato un Java ssh-rsa PublicKey, come posso creare una chiave pubblica SSH2?] (Http: // stackoverflow.it/questions/3588120/given-a-java-ssh-rsa-publickey-how-can-i-build-an-ssh2-public-key) – erickson

risposta

24

Il formato chiave utilizzato da ssh è definito nello RFC#4253. Il formato per la chiave pubblica RSA è il seguente:

string "ssh-rsa" 
    mpint  e /* key public exponent */ 
    mpint  n /* key modulus */ 

Tutti codifica tipo di dati è definito nella sezione # 5 di RFC#4251. stringa e mpint (precisione multipla interi) tipi sono codificati in questo modo:

4-bytes word: data length (unsigned big-endian 32 bits integer) 
    n bytes  : binary representation of the data 

per esempio, la codifica della stringa "ssh-rsa" è:

byte[] data = new byte[] {0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'}; 

per codificare il pubblico:

public byte[] encodePublicKey(RSAPublicKey key) throws IOException 
    { 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     /* encode the "ssh-rsa" string */ 
     byte[] sshrsa = new byte[] {0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'}; 
     out.write(sshrsa); 
     /* Encode the public exponent */ 
     BigInteger e = key.getPublicExponent(); 
     byte[] data = e.toByteArray(); 
     encodeUInt32(data.length, out); 
     out.write(data); 
     /* Encode the modulus */ 
     BigInteger m = key.getModulus(); 
     data = m.toByteArray(); 
     encodeUInt32(data.length, out); 
     out.write(data); 
     return out.toByteArray(); 
    } 

    public void encodeUInt32(int value, OutputStream out) throws IOException 
    { 
     byte[] tmp = new byte[4]; 
     tmp[0] = (byte)((value >>> 24) & 0xff); 
     tmp[1] = (byte)((value >>> 16) & 0xff); 
     tmp[2] = (byte)((value >>> 8) & 0xff); 
     tmp[3] = (byte)(value & 0xff); 
     out.write(tmp); 
    } 

Per avere una riprésentation della stringa della chiave, è sufficiente codificare la matrice di byte restituita in Base64.

Per la codifica chiave privata ci sono due casi:

  1. la chiave privata non è protetta da una password. In tal caso, la chiave privata viene codificata in base allo standard PKCS # 8 e quindi codificata con Base64. È possibile ottenere la codifica PKCS8 della chiave privata chiamando getEncoded su RSAPrivateKey.
  2. la chiave privata è protetta da una password. In tal caso la codifica della chiave è un formato dedicato OpenSSH. Non so se c'è qualche documentazione su questo formato (eccetto il codice sorgente OpenSSH ovviamente)
+3

Grazie mille. Ho anche trovato jsch (http://www.jcraft.com/jsch/), una libreria gratuita che offre questa funzionalità. – Carsten

+1

sembra essere più semplice da usare: MessageDigest.getInstance ("MD5"). Digest (key.getEncoded()). – Pierre

+1

c'è un modo per convertire a livello di codice [Jsch] (http://www.jcraft.com/jsch/) ssh rsa-keys generate in un formato [Java Cipher] (http://docs.oracle.com/ javase/7/docs/api/javax/crypto/Cipher.html) può essere utilizzato per la crittografia? Per quanto posso dire [che richiede i comandi openssh] (http://stackoverflow.com/a/7473874/1020470). 'openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key_file -nocrypt> pkcs8_key' ma cosa succede se non si ha accesso a openssh? –

1

Come ha accennato Carsten, JSch può generare facilmente quelle chiavi in ​​mano. fare riferimento al suo esempio, KeyGen.java

1

s' gotoalbertoanswer (citato sotto) per una domanda diversa funziona sia per RSA e DSA chiavi:

Se si vuole invertire il processo, cioè codificare un oggetto Java PublicKey in un formato voce per Linux authorized_keys, si può usare questo codice:

/** 
    * Encode PublicKey (DSA or RSA encoded) to authorized_keys like string 
    * 
    * @param publicKey DSA or RSA encoded 
    * @param user username for output authorized_keys like string 
    * @return authorized_keys like string 
    * @throws IOException 
    */ 
    public static String encodePublicKey(PublicKey publicKey, String user) 
      throws IOException { 
     String publicKeyEncoded; 
     if(publicKey.getAlgorithm().equals("RSA")){ 
      RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; 
      ByteArrayOutputStream byteOs = new ByteArrayOutputStream(); 
      DataOutputStream dos = new DataOutputStream(byteOs); 
      dos.writeInt("ssh-rsa".getBytes().length); 
      dos.write("ssh-rsa".getBytes()); 
      dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length); 
      dos.write(rsaPublicKey.getPublicExponent().toByteArray()); 
      dos.writeInt(rsaPublicKey.getModulus().toByteArray().length); 
      dos.write(rsaPublicKey.getModulus().toByteArray()); 
      publicKeyEncoded = new String(
        Base64.encodeBase64(byteOs.toByteArray())); 
      return "ssh-rsa " + publicKeyEncoded + " " + user; 
     } 
     else if(publicKey.getAlgorithm().equals("DSA")){ 
      DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey; 
      DSAParams dsaParams = dsaPublicKey.getParams(); 

      ByteArrayOutputStream byteOs = new ByteArrayOutputStream(); 
      DataOutputStream dos = new DataOutputStream(byteOs); 
      dos.writeInt("ssh-dss".getBytes().length); 
      dos.write("ssh-dss".getBytes()); 
      dos.writeInt(dsaParams.getP().toByteArray().length); 
      dos.write(dsaParams.getP().toByteArray()); 
      dos.writeInt(dsaParams.getQ().toByteArray().length); 
      dos.write(dsaParams.getQ().toByteArray()); 
      dos.writeInt(dsaParams.getG().toByteArray().length); 
      dos.write(dsaParams.getG().toByteArray()); 
      dos.writeInt(dsaPublicKey.getY().toByteArray().length); 
      dos.write(dsaPublicKey.getY().toByteArray()); 
      publicKeyEncoded = new String(
        Base64.encodeBase64(byteOs.toByteArray())); 
      return "ssh-dss " + publicKeyEncoded + " " + user; 
     } 
     else{ 
      throw new IllegalArgumentException(
        "Unknown public key encoding: " + publicKey.getAlgorithm()); 
     } 
    } 
+0

Personalmente, mi piace la risposta di @ ymnk di più, anche se la soluzione di gotoalberto è più accessibile. Complimenti per una delle librerie Java più utili! – user314104

2

La soluzione generica per qualsiasi tipo PublicKey (RSA, DSA, ecc) è di un rivestimento usando SSHJ:

byte[] b = new Buffer.PlainBuffer().putPublicKey(key).getCompactData() 

e quindi codificare utilizzando Base64.getEncoder().encodeToString(b).

Problemi correlati