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.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 }