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