View Javadoc
1   package de.dlr.shepard.common.util;
2   
3   import io.quarkus.logging.Log;
4   import jakarta.enterprise.context.RequestScoped;
5   import java.io.IOException;
6   import java.nio.file.Files;
7   import java.nio.file.Path;
8   import java.security.KeyFactory;
9   import java.security.KeyPairGenerator;
10  import java.security.NoSuchAlgorithmException;
11  import java.security.PrivateKey;
12  import java.security.PublicKey;
13  import java.security.spec.InvalidKeySpecException;
14  import java.security.spec.PKCS8EncodedKeySpec;
15  import java.security.spec.X509EncodedKeySpec;
16  import lombok.Getter;
17  
18  @RequestScoped
19  public class PKIHelper {
20  
21    private static final String RSA = "RSA";
22  
23    private Path keysDir = Path.of(System.getProperty("user.home"), ".shepard/keys");
24    private Path pubKey = Path.of(keysDir.toString(), "public.key");
25    private Path privKey = Path.of(keysDir.toString(), "private.key");
26  
27    @Getter
28    private PublicKey publicKey;
29  
30    @Getter
31    private PrivateKey privateKey;
32  
33    public void init() {
34      generateKeyPairIfNecessary();
35  
36      try {
37        publicKey = importPublicKey();
38      } catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) {
39        Log.errorf("Exception while reading public key specification: %s", e);
40      }
41  
42      try {
43        privateKey = importPrivateKey();
44      } catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) {
45        Log.errorf("Exception while reading private key specification: %s", e);
46      }
47    }
48  
49    private void generateKeyPairIfNecessary() {
50      if (Files.isRegularFile(keysDir)) {
51        Log.error("keys directory is a file, cannot create keys");
52        return;
53      }
54      if (Files.notExists(keysDir)) {
55        Log.info("keys directory does not exist, creating...");
56        try {
57          Files.createDirectories(keysDir);
58        } catch (IOException e) {
59          Log.errorf("Error while generating keys directory: %s", e.toString());
60          return;
61        }
62      }
63      if (!Files.isReadable(keysDir) || !Files.isWritable(keysDir)) {
64        Log.error("insufficient permissions for the keys directory");
65        return;
66      }
67  
68      if (Files.exists(pubKey) && Files.isRegularFile(pubKey) && Files.exists(privKey) && Files.isRegularFile(privKey)) {
69        Log.info("keys found, importing...");
70        return;
71      }
72      Log.info("No keys available. Generating...");
73      try {
74        generateKeyPair();
75      } catch (NoSuchAlgorithmException | IOException e) {
76        Log.errorf("Error while generating keys: %s", e.toString());
77      }
78    }
79  
80    private PublicKey importPublicKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
81      byte[] key;
82      try (var fis = Files.newInputStream(pubKey)) {
83        key = fis.readAllBytes();
84      }
85  
86      var keyFactory = KeyFactory.getInstance(RSA);
87      var spec = new X509EncodedKeySpec(key);
88      return keyFactory.generatePublic(spec);
89    }
90  
91    private PrivateKey importPrivateKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
92      byte[] key;
93      try (var fis = Files.newInputStream(privKey)) {
94        key = fis.readAllBytes();
95      }
96  
97      var keyFactory = KeyFactory.getInstance(RSA);
98      var spec = new PKCS8EncodedKeySpec(key);
99      return keyFactory.generatePrivate(spec);
100   }
101 
102   private void generateKeyPair() throws NoSuchAlgorithmException, IOException {
103     var kpg = KeyPairGenerator.getInstance(RSA);
104     kpg.initialize(2048);
105     var kp = kpg.generateKeyPair();
106 
107     try (var pubFos = Files.newOutputStream(pubKey); var privFos = Files.newOutputStream(privKey)) {
108       pubFos.write(kp.getPublic().getEncoded());
109       privFos.write(kp.getPrivate().getEncoded());
110     }
111   }
112 }