3 import java
.io
.IOException
;
4 import java
.io
.InputStreamReader
;
6 import java
.io
.StringReader
;
7 import java
.io
.StringWriter
;
8 import java
.nio
.charset
.StandardCharsets
;
9 import java
.nio
.file
.Files
;
10 import java
.nio
.file
.Path
;
11 import java
.nio
.file
.Paths
;
12 import java
.security
.GeneralSecurityException
;
13 import java
.security
.KeyFactory
;
14 import java
.security
.KeyPair
;
15 import java
.security
.PrivateKey
;
16 import java
.security
.PublicKey
;
17 import java
.security
.interfaces
.RSAPrivateCrtKey
;
18 import java
.security
.spec
.RSAPublicKeySpec
;
20 import org
.apache
.sshd
.common
.config
.keys
.KeyUtils
;
21 import org
.apache
.sshd
.common
.config
.keys
.PublicKeyEntry
;
22 import org
.bouncycastle
.asn1
.pkcs
.PrivateKeyInfo
;
23 import org
.bouncycastle
.openssl
.PEMKeyPair
;
24 import org
.bouncycastle
.openssl
.PEMParser
;
25 import org
.bouncycastle
.openssl
.PKCS8Generator
;
26 import org
.bouncycastle
.openssl
.jcajce
.JcaPEMKeyConverter
;
27 import org
.bouncycastle
.openssl
.jcajce
.JcaPEMWriter
;
28 import org
.bouncycastle
.openssl
.jcajce
.JcaPKCS8Generator
;
29 import org
.bouncycastle
.openssl
.jcajce
.JceOpenSSLPKCS8DecryptorProviderBuilder
;
30 import org
.bouncycastle
.openssl
.jcajce
.JceOpenSSLPKCS8EncryptorBuilder
;
31 import org
.bouncycastle
.operator
.InputDecryptorProvider
;
32 import org
.bouncycastle
.operator
.OutputEncryptor
;
33 import org
.bouncycastle
.pkcs
.PKCS8EncryptedPrivateKeyInfo
;
35 @SuppressWarnings("restriction")
36 public class SshKeyPair
{
37 public final static String RSA_KEY_TYPE
= "ssh-rsa";
39 private PublicKey publicKey
;
40 private PrivateKey privateKey
;
41 private KeyPair keyPair
;
43 public SshKeyPair(KeyPair keyPair
) {
45 this.publicKey
= keyPair
.getPublic();
46 this.privateKey
= keyPair
.getPrivate();
47 this.keyPair
= keyPair
;
50 public SshKeyPair(PublicKey publicKey
, PrivateKey privateKey
) {
52 this.publicKey
= publicKey
;
53 this.privateKey
= privateKey
;
54 this.keyPair
= new KeyPair(publicKey
, privateKey
);
57 public KeyPair
asKeyPair() {
61 public String
getPublicKeyAsOpenSshString() {
62 return PublicKeyEntry
.toString(publicKey
);
65 public String
getPrivateKeyAsPemString(char[] password
) {
69 if (password
!= null) {
70 JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder
= new JceOpenSSLPKCS8EncryptorBuilder(
71 PKCS8Generator
.PBE_SHA1_3DES
);
72 encryptorBuilder
.setPasssword(password
);
73 OutputEncryptor oe
= encryptorBuilder
.build();
74 JcaPKCS8Generator gen
= new JcaPKCS8Generator(privateKey
, oe
);
80 StringWriter sw
= new StringWriter();
81 JcaPEMWriter pemWrt
= new JcaPEMWriter(sw
);
82 pemWrt
.writeObject(obj
);
85 } catch (Exception e
) {
86 throw new RuntimeException("Cannot convert private key", e
);
90 public static SshKeyPair
loadOrGenerate(Path privateKeyPath
, int size
, char[] password
) {
92 SshKeyPair sshKeyPair
;
93 if (Files
.exists(privateKeyPath
)) {
94 // String privateKeyStr = new String(Files.readAllBytes(privateKeyPath), StandardCharsets.US_ASCII);
96 new InputStreamReader(Files
.newInputStream(privateKeyPath
), StandardCharsets
.US_ASCII
),
98 // TOD make sure public key is consistemt
100 sshKeyPair
= generate(size
);
101 Files
.write(privateKeyPath
,
102 sshKeyPair
.getPrivateKeyAsPemString(password
).getBytes(StandardCharsets
.US_ASCII
));
103 Path publicKeyPath
= privateKeyPath
.resolveSibling(privateKeyPath
.getFileName() + ".pub");
104 Files
.write(publicKeyPath
,
105 sshKeyPair
.getPublicKeyAsOpenSshString().getBytes(StandardCharsets
.US_ASCII
));
108 } catch (IOException e
) {
109 throw new RuntimeException("Cannot read or write private key " + privateKeyPath
, e
);
113 public static SshKeyPair
generate(int size
) {
114 return generate(RSA_KEY_TYPE
, size
);
117 public static SshKeyPair
generate(String keyType
, int size
) {
119 KeyPair keyPair
= KeyUtils
.generateKeyPair(keyType
, size
);
120 PublicKey publicKey
= keyPair
.getPublic();
121 PrivateKey privateKey
= keyPair
.getPrivate();
122 return new SshKeyPair(publicKey
, privateKey
);
123 } catch (GeneralSecurityException e
) {
124 throw new RuntimeException("Cannot generate SSH key", e
);
128 public static SshKeyPair
load(Reader reader
, char[] password
) {
129 try (PEMParser pemParser
= new PEMParser(reader
)) {
130 Object object
= pemParser
.readObject();
131 JcaPEMKeyConverter converter
= new JcaPEMKeyConverter();// .setProvider("BC");
133 if (object
instanceof PKCS8EncryptedPrivateKeyInfo
) {
134 // Encrypted key - we will use provided password
135 PKCS8EncryptedPrivateKeyInfo ckp
= (PKCS8EncryptedPrivateKeyInfo
) object
;
136 // PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password);
137 InputDecryptorProvider inputDecryptorProvider
= new JceOpenSSLPKCS8DecryptorProviderBuilder()
139 PrivateKeyInfo pkInfo
= ckp
.decryptPrivateKeyInfo(inputDecryptorProvider
);
140 PrivateKey privateKey
= converter
.getPrivateKey(pkInfo
);
142 // generate public key
143 RSAPrivateCrtKey privk
= (RSAPrivateCrtKey
) privateKey
;
144 RSAPublicKeySpec publicKeySpec
= new java
.security
.spec
.RSAPublicKeySpec(privk
.getModulus(),
145 privk
.getPublicExponent());
146 KeyFactory keyFactory
= KeyFactory
.getInstance("RSA");
147 PublicKey publicKey
= keyFactory
.generatePublic(publicKeySpec
);
149 kp
= new KeyPair(publicKey
, privateKey
);
151 // Unencrypted key - no password needed
152 // PKCS8EncryptedPrivateKeyInfo ukp = (PKCS8EncryptedPrivateKeyInfo) object;
153 PEMKeyPair pemKp
= (PEMKeyPair
) object
;
154 kp
= converter
.getKeyPair(pemKp
);
156 return new SshKeyPair(kp
);
157 } catch (Exception e
) {
158 throw new RuntimeException("Cannot load private key", e
);
162 public static void main(String args
[]) {
163 Path privateKeyPath
= Paths
.get(System
.getProperty("user.dir") + "/id_rsa");
164 SshKeyPair skp
= SshKeyPair
.loadOrGenerate(privateKeyPath
, 1024, null);
165 System
.out
.println("Public:\n" + skp
.getPublicKeyAsOpenSshString());
166 System
.out
.println("Private (plain):\n" + skp
.getPrivateKeyAsPemString(null));
167 System
.out
.println("Private (encrypted):\n" + skp
.getPrivateKeyAsPemString("demo".toCharArray()));
169 StringReader reader
= new StringReader(skp
.getPrivateKeyAsPemString(null));
170 skp
= SshKeyPair
.load(reader
, null);
171 System
.out
.println("Public:\n" + skp
.getPublicKeyAsOpenSshString());
172 System
.out
.println("Private (plain):\n" + skp
.getPrivateKeyAsPemString(null));
173 System
.out
.println("Private (encrypted):\n" + skp
.getPrivateKeyAsPemString("demo".toCharArray()));
175 reader
= new StringReader(skp
.getPrivateKeyAsPemString("demo".toCharArray()));
176 skp
= SshKeyPair
.load(reader
, "demo".toCharArray());
177 System
.out
.println("Public:\n" + skp
.getPublicKeyAsOpenSshString());
178 System
.out
.println("Private (plain):\n" + skp
.getPrivateKeyAsPemString(null));
179 System
.out
.println("Private (encrypted):\n" + skp
.getPrivateKeyAsPemString("demo".toCharArray()));