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