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 }