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