package com.sshmanager.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.Base64; @Service public class EncryptionService { private static final int GCM_IV_LENGTH = 12; private static final int GCM_TAG_LENGTH = 128; private static final String ALGORITHM = "AES/GCM/NoPadding"; private final byte[] keyBytes; public EncryptionService(@Value("${sshmanager.encryption-key}") String base64Key) { this.keyBytes = Base64.getDecoder().decode(base64Key); if (keyBytes.length != 32) { throw new IllegalArgumentException("Encryption key must be 32 bytes (256 bits)"); } } public String encrypt(String plainText) { if (plainText == null || plainText.isEmpty()) { return null; } try { byte[] iv = new byte[GCM_IV_LENGTH]; new SecureRandom().nextBytes(iv); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec); byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); byte[] combined = new byte[iv.length + encrypted.length]; System.arraycopy(iv, 0, combined, 0, iv.length); System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length); return Base64.getEncoder().encodeToString(combined); } catch (Exception e) { throw new RuntimeException("Encryption failed", e); } } public String decrypt(String encryptedText) { if (encryptedText == null || encryptedText.isEmpty()) { return null; } try { byte[] combined = Base64.getDecoder().decode(encryptedText); byte[] iv = new byte[GCM_IV_LENGTH]; byte[] encrypted = new byte[combined.length - GCM_IV_LENGTH]; System.arraycopy(combined, 0, iv, 0, iv.length); System.arraycopy(combined, iv.length, encrypted, 0, encrypted.length); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); byte[] decrypted = cipher.doFinal(encrypted); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("Decryption failed", e); } } }