1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.preference;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
21 import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactory;
22 import io.github.tonywasher.joceanus.gordianknot.api.factory.GordianFactoryType;
23 import io.github.tonywasher.joceanus.gordianknot.api.keyset.GordianKeySet;
24 import io.github.tonywasher.joceanus.gordianknot.api.keyset.spec.GordianKeySetSpec;
25 import io.github.tonywasher.joceanus.gordianknot.api.keyset.spec.GordianKeySetSpecBuilder;
26 import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianKeySetLock;
27 import io.github.tonywasher.joceanus.gordianknot.api.lock.GordianLockFactory;
28 import io.github.tonywasher.joceanus.gordianknot.api.lock.spec.GordianPasswordLockSpec;
29 import io.github.tonywasher.joceanus.gordianknot.util.GordianGenerator;
30 import io.github.tonywasher.joceanus.gordianknot.util.GordianUtilities;
31 import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceKey;
32 import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceManager;
33 import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceParams;
34 import io.github.tonywasher.joceanus.metis.preference.MetisPreferenceResource;
35 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
36 import io.github.tonywasher.joceanus.oceanus.convert.OceanusDataConverter;
37 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogManager;
38 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogger;
39 import io.github.tonywasher.joceanus.prometheus.exc.PrometheusSecurityException;
40
41 import java.net.InetAddress;
42 import java.net.UnknownHostException;
43 import java.util.EnumSet;
44 import java.util.Set;
45
46
47
48
49 public class PrometheusPreferenceSecurity
50 implements PrometheusPreferenceEncryptor {
51
52
53
54 private static final OceanusLogger LOGGER = OceanusLogManager.getLogger(PrometheusPreferenceSecurity.class);
55
56
57
58
59 private static final GordianLength DEFAULT_KEYLEN = GordianLength.LEN_256;
60
61
62
63
64 private final GordianKeySet theKeySet;
65
66
67
68
69
70
71
72 PrometheusPreferenceSecurity(final MetisPreferenceManager pManager) throws OceanusException {
73
74 try {
75
76 final GordianFactory myFactory = GordianGenerator.createFactory(GordianFactoryType.BC);
77 final GordianLockFactory myLocks = myFactory.getLockFactory();
78
79
80 final PrometheusBaseSecurityPreferences myPrefs = pManager.getPreferenceSet(PrometheusBaseSecurityPreferences.class);
81 final byte[] myLock = myPrefs.getByteArrayValue(PrometheusSecurityPreferenceKey.LOCK);
82
83
84 final char[] myHost = getHostName();
85 final char[] myUser = System.getProperty("user.name").toCharArray();
86 final char[] myPassword = new char[myHost.length + myUser.length];
87 System.arraycopy(myHost, 0, myPassword, 0, myHost.length);
88 System.arraycopy(myUser, 0, myPassword, myHost.length, myUser.length);
89
90
91 final GordianKeySetLock myKeySetLock = myLock == null
92 ? myLocks.newKeySetLock(GordianUtilities.newPasswordLockSpecBuilder().passwordLock(), myPassword)
93 : myLocks.resolveKeySetLock(myLock, myPassword);
94
95
96 theKeySet = myKeySetLock.getKeySet();
97
98
99 if (myLock == null) {
100
101 myPrefs.setHash(myKeySetLock.getLockBytes());
102 myPrefs.storeChanges();
103 }
104 } catch (GordianException e) {
105 throw new PrometheusSecurityException(e);
106 }
107 }
108
109 @Override
110 public byte[] encryptValue(final char[] pValue) throws OceanusException {
111
112 try {
113 final byte[] myBytes = OceanusDataConverter.charsToByteArray(pValue);
114 return theKeySet.encryptBytes(myBytes);
115 } catch (GordianException e) {
116 throw new PrometheusSecurityException(e);
117 }
118 }
119
120 @Override
121 public char[] decryptValue(final byte[] pValue) throws OceanusException {
122
123 try {
124 final byte[] myBytes = theKeySet.decryptBytes(pValue);
125 return OceanusDataConverter.bytesToCharArray(myBytes);
126 } catch (GordianException e) {
127 throw new PrometheusSecurityException(e);
128 }
129 }
130
131
132
133
134
135
136 private static char[] getHostName() {
137
138 try {
139 final InetAddress myAddr = InetAddress.getLocalHost();
140 return myAddr.getHostName().toCharArray();
141
142 } catch (UnknownHostException e) {
143 LOGGER.error("Hostname can not be resolved", e);
144 return "localhost".toCharArray();
145 }
146 }
147
148
149
150
151 public enum PrometheusSecurityPreferenceKey implements MetisPreferenceKey {
152
153
154
155 LOCK("Lock", null),
156
157
158
159
160 FACTORY("FactoryType", MetisPreferenceResource.SECPREF_FACTORY),
161
162
163
164
165 KEYLENGTH("KeyLength", MetisPreferenceResource.SECPREF_KEYLEN),
166
167
168
169
170 CIPHERSTEPS("CipherSteps", MetisPreferenceResource.SECPREF_CIPHERSTEPS),
171
172
173
174
175 HASHITERATIONS("HashIterations", MetisPreferenceResource.SECPREF_ITERATIONS),
176
177
178
179
180 ACTIVEKEYSETS("NumActiveKeySets", MetisPreferenceResource.SECPREF_KEYSETS);
181
182
183
184
185 private final String theName;
186
187
188
189
190 private final String theDisplay;
191
192
193
194
195
196
197
198 PrometheusSecurityPreferenceKey(final String pName,
199 final MetisPreferenceResource pDisplay) {
200 theName = pName;
201 theDisplay = pDisplay != null
202 ? pDisplay.getValue()
203 : null;
204 }
205
206 @Override
207 public String getName() {
208 return theName;
209 }
210
211 @Override
212 public String getDisplay() {
213 return theDisplay;
214 }
215 }
216
217
218
219
220 public static class PrometheusBaseSecurityPreferences
221 extends PrometheusPreferenceSet {
222
223
224
225
226
227
228 public PrometheusBaseSecurityPreferences(final MetisPreferenceParams pParams) throws OceanusException {
229 super(pParams, MetisPreferenceResource.SECPREF_BASEPREFNAME);
230 setHidden();
231 }
232
233
234
235
236
237
238 protected void setHash(final byte[] pHash) {
239 getByteArrayPreference(PrometheusSecurityPreferenceKey.LOCK).setValue(pHash);
240 }
241
242 @Override
243 protected void definePreferences() {
244 defineByteArrayPreference(PrometheusSecurityPreferenceKey.LOCK);
245 }
246
247 @Override
248 public void autoCorrectPreferences() {
249
250 }
251 }
252
253
254
255
256 public static class PrometheusSecurityPreferences
257 extends PrometheusPreferenceSet {
258
259
260
261 private static final Set<GordianLength> VALID_LENGTHS = EnumSet.of(GordianLength.LEN_128, GordianLength.LEN_192, GordianLength.LEN_256);
262
263
264
265
266 private static final int MINIMUM_ACTIVE_KEYSETS = 4;
267
268
269
270
271 private static final int MAXIMUM_ACTIVE_KEYSETS = 64;
272
273
274
275
276 private static final int DEFAULT_ACTIVE_KEYSETS = 8;
277
278
279
280
281
282
283
284 public PrometheusSecurityPreferences(final MetisPreferenceParams pParams) throws OceanusException {
285 super(pParams, MetisPreferenceResource.SECPREF_PREFNAME);
286 }
287
288
289
290
291
292
293 public GordianFactoryType getFactoryType() {
294 return getEnumValue(PrometheusSecurityPreferenceKey.FACTORY, GordianFactoryType.class);
295 }
296
297
298
299
300
301
302 public GordianKeySetSpec getKeySetSpec() {
303
304 final GordianLength myKeyLen = getEnumValue(PrometheusSecurityPreferenceKey.KEYLENGTH, GordianLength.class);
305 final int mySteps = getIntegerValue(PrometheusSecurityPreferenceKey.CIPHERSTEPS);
306 final GordianKeySetSpecBuilder myBuilder = GordianUtilities.newKeySetSpecBuilder();
307 return myBuilder.keySet(myKeyLen, mySteps);
308 }
309
310
311
312
313
314
315 public GordianPasswordLockSpec getPasswordLockSpec() {
316
317 final int myIterations = getIntegerValue(PrometheusSecurityPreferenceKey.HASHITERATIONS);
318 return GordianUtilities.newPasswordLockSpecBuilder().passwordLock(myIterations, getKeySetSpec());
319 }
320
321 @Override
322 protected void definePreferences() throws OceanusException {
323 defineEnumPreference(PrometheusSecurityPreferenceKey.FACTORY, GordianFactoryType.class);
324 defineEnumPreference(PrometheusSecurityPreferenceKey.KEYLENGTH, GordianLength.class);
325 defineIntegerPreference(PrometheusSecurityPreferenceKey.CIPHERSTEPS);
326 defineIntegerPreference(PrometheusSecurityPreferenceKey.HASHITERATIONS);
327 defineIntegerPreference(PrometheusSecurityPreferenceKey.ACTIVEKEYSETS);
328 }
329
330 @Override
331 public void autoCorrectPreferences() {
332
333 final MetisEnumPreference<GordianFactoryType> myFactPref
334 = getEnumPreference(PrometheusSecurityPreferenceKey.FACTORY, GordianFactoryType.class);
335 if (!myFactPref.isAvailable()) {
336 myFactPref.setValue(GordianFactoryType.BC);
337 }
338
339
340 final MetisEnumPreference<GordianLength> myLengthPref
341 = getEnumPreference(PrometheusSecurityPreferenceKey.KEYLENGTH, GordianLength.class);
342 if (!myLengthPref.isAvailable()) {
343 myLengthPref.setValue(DEFAULT_KEYLEN);
344 }
345
346
347 myLengthPref.setFilter(VALID_LENGTHS::contains);
348
349
350 MetisIntegerPreference myPref = getIntegerPreference(PrometheusSecurityPreferenceKey.CIPHERSTEPS);
351 if (!myPref.isAvailable()) {
352 myPref.setValue(GordianKeySetSpec.DEFAULT_CIPHER_STEPS);
353 }
354
355
356 myPref.setRange(GordianKeySetSpec.MINIMUM_CIPHER_STEPS, GordianKeySetSpec.MAXIMUM_CIPHER_STEPS);
357 if (!myPref.validate()) {
358 myPref.setValue(GordianKeySetSpec.DEFAULT_CIPHER_STEPS);
359 }
360
361
362 myPref = getIntegerPreference(PrometheusSecurityPreferenceKey.HASHITERATIONS);
363 if (!myPref.isAvailable()) {
364 myPref.setValue(GordianPasswordLockSpec.DEFAULT_ITERATIONS);
365 }
366
367
368 myPref.setRange(GordianPasswordLockSpec.MINIMUM_ITERATIONS, GordianPasswordLockSpec.MAXIMUM_ITERATIONS);
369 if (!myPref.validate()) {
370 myPref.setValue(GordianPasswordLockSpec.DEFAULT_ITERATIONS);
371 }
372
373
374 myPref = getIntegerPreference(PrometheusSecurityPreferenceKey.ACTIVEKEYSETS);
375 if (!myPref.isAvailable()) {
376 myPref.setValue(DEFAULT_ACTIVE_KEYSETS);
377 }
378
379
380 myPref.setRange(MINIMUM_ACTIVE_KEYSETS, MAXIMUM_ACTIVE_KEYSETS);
381 if (!myPref.validate()) {
382 myPref.setValue(DEFAULT_ACTIVE_KEYSETS);
383 }
384 }
385 }
386 }