1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.crypt;
20
21 import java.io.IOException;
22 import java.nio.charset.StandardCharsets;
23 import java.nio.file.FileAlreadyExistsException;
24 import java.nio.file.FileSystems;
25 import java.nio.file.Files;
26 import java.nio.file.NoSuchFileException;
27 import java.nio.file.Path;
28 import java.nio.file.StandardOpenOption;
29 import java.security.InvalidKeyException;
30 import java.security.NoSuchAlgorithmException;
31
32 import javax.crypto.BadPaddingException;
33 import javax.crypto.Cipher;
34 import javax.crypto.IllegalBlockSizeException;
35 import javax.crypto.KeyGenerator;
36 import javax.crypto.NoSuchPaddingException;
37 import javax.crypto.SecretKey;
38 import javax.crypto.spec.SecretKeySpec;
39
40 import org.apache.logging.log4j.LogManager;
41 import org.apache.logging.log4j.Logger;
42 import org.mycore.common.MCRException;
43 import org.mycore.common.config.annotation.MCRProperty;
44
45 public class MCRAESCipher extends MCRCipher {
46
47 private static final Logger LOGGER = LogManager.getLogger();
48
49 private String keyFile;
50 private SecretKey secretKey;
51 private Cipher encryptCipher;
52 private Cipher decryptCipher;
53
54 @MCRProperty(name = "KeyFile", required = true)
55 public void setKeyFile(String path) {
56 keyFile = path;
57 }
58
59 public MCRAESCipher() {
60 secretKey = null;
61 encryptCipher = null;
62 decryptCipher = null;
63 }
64
65 public void init(String id) throws MCRCryptKeyFileNotFoundException, InvalidKeyException {
66 cipherID = id;
67
68 String encodedKey = null;
69 try {
70 LOGGER.info("Get key from file {}.", keyFile);
71 encodedKey = Files.readString(FileSystems.getDefault().getPath(keyFile));
72 byte[] decodedKey = java.util.Base64.getDecoder().decode(encodedKey);
73 LOGGER.info("Set secret key");
74 secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
75 encryptCipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
76 encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey);
77 decryptCipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
78 decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
79 } catch (NoSuchFileException e) {
80 throw new MCRCryptKeyFileNotFoundException(
81 "Keyfile " + keyFile
82 + " not found. Generate new one with cli command or copy file to path.");
83 } catch (IllegalArgumentException e) {
84 throw new InvalidKeyException("Error while decoding key from keyFile " + keyFile + "!", e);
85 } catch (IOException e) {
86 throw new MCRException("Can't read keyFile " + keyFile + ".", e);
87 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
88 throw new MCRCryptCipherConfigurationException(
89 "The algorithm AES/ECB/PKCS5PADDING ist not provided by this javaversion."
90 + "Update Java or configure an other chipher in mycore.properties.",
91 e);
92 }
93 }
94
95 public boolean isInitialized() {
96 return (secretKey != null && encryptCipher != null && decryptCipher != null);
97 }
98
99 public void reset() {
100 secretKey = null;
101 encryptCipher = null;
102 decryptCipher = null;
103 }
104
105 public void generateKeyFile() throws FileAlreadyExistsException {
106 try {
107 LOGGER.info("generate Key File");
108 String cryptKey = generateKey();
109 Path keyPath = FileSystems.getDefault().getPath(keyFile);
110 Files.createDirectories(keyPath.getParent());
111 Files.writeString(keyPath, cryptKey, StandardOpenOption.CREATE_NEW);
112 } catch (NoSuchAlgorithmException e) {
113 throw new MCRCryptCipherConfigurationException(
114 "Error while generating keyfile: The configured algorithm is not available.", e);
115 } catch (FileAlreadyExistsException e) {
116 throw new FileAlreadyExistsException(keyFile, null,
117 "A crypt key shouldn't be generated if it allready exists. "
118 + " If you aware of the consequences use overwriteKeyFile().");
119 } catch (IOException e) {
120 throw new MCRException("Error while write key to file.", e);
121 }
122 }
123
124 public void overwriteKeyFile() {
125 try {
126 LOGGER.info("overwrite Key File");
127 String cryptKey = generateKey();
128 Path keyPath = FileSystems.getDefault().getPath(keyFile);
129 Files.createDirectories(keyPath.getParent());
130 Files.writeString(keyPath, cryptKey);
131 } catch (NoSuchAlgorithmException e) {
132 throw new MCRCryptCipherConfigurationException(
133 "Error while generating keyfile. The configured algorithm is not available.", e);
134 } catch (IOException e) {
135 throw new MCRException("Error while write key to file.", e);
136 }
137 }
138
139 private String generateKey() throws NoSuchAlgorithmException {
140 SecretKey tmpSecretKey = KeyGenerator.getInstance("AES").generateKey();
141 return java.util.Base64.getEncoder().encodeToString(tmpSecretKey.getEncoded());
142 }
143
144 protected String encryptImpl(String text) throws MCRCryptCipherConfigurationException {
145 byte[] encryptedBytes = encryptImpl(text.getBytes(StandardCharsets.UTF_8));
146 String encryptedString = java.util.Base64.getEncoder().encodeToString(encryptedBytes);
147 return encryptedString;
148 }
149
150 protected String decryptImpl(String text) throws MCRCryptCipherConfigurationException {
151 byte[] encryptedBytes = java.util.Base64.getDecoder().decode(text);
152 byte[] decryptedBytes = decryptImpl(encryptedBytes);
153 String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
154 return decryptedText;
155 }
156
157 protected byte[] encryptImpl(byte[] bytes) throws MCRCryptCipherConfigurationException {
158 try {
159 byte[] encryptedBytes = encryptCipher.doFinal(bytes);
160 return encryptedBytes;
161 } catch (BadPaddingException | IllegalBlockSizeException e) {
162 throw new MCRCryptCipherConfigurationException("Can't encrypt value - wrong configuration.", e);
163 }
164 }
165
166 protected byte[] decryptImpl(byte[] bytes) throws MCRCryptCipherConfigurationException {
167 try {
168 byte[] decryptedBytes = decryptCipher.doFinal(bytes);
169 return decryptedBytes;
170 } catch (BadPaddingException | IllegalBlockSizeException e) {
171 throw new MCRCryptCipherConfigurationException("Can't decrypt value - "
172 + " possible issues: corrupted crypted value, wrong configuration or bad key.", e);
173 }
174 }
175
176 }