Bläddra i källkod

bugfix ominbus

jrivard 10 år sedan
förälder
incheckning
2eeda15e77
81 ändrade filer med 824 tillägg och 600 borttagningar
  1. 5 0
      pwm/servlet/src/password/pwm/AppProperty.java
  2. 5 0
      pwm/servlet/src/password/pwm/AppProperty.properties
  3. 2 0
      pwm/servlet/src/password/pwm/PwmAboutProperty.java
  4. 15 2
      pwm/servlet/src/password/pwm/PwmApplication.java
  5. 5 0
      pwm/servlet/src/password/pwm/PwmConstants.java
  6. 1 1
      pwm/servlet/src/password/pwm/bean/SessionStateBean.java
  7. 6 10
      pwm/servlet/src/password/pwm/bean/UserIdentity.java
  8. 8 20
      pwm/servlet/src/password/pwm/config/Configuration.java
  9. 2 1
      pwm/servlet/src/password/pwm/config/ConfigurationReader.java
  10. 3 3
      pwm/servlet/src/password/pwm/config/PwmSetting.java
  11. 14 18
      pwm/servlet/src/password/pwm/config/StoredConfiguration.java
  12. 4 1
      pwm/servlet/src/password/pwm/config/StoredValue.java
  13. 12 7
      pwm/servlet/src/password/pwm/config/value/AbstractValue.java
  14. 39 0
      pwm/servlet/src/password/pwm/config/value/ActionValue.java
  15. 10 8
      pwm/servlet/src/password/pwm/config/value/BooleanValue.java
  16. 17 18
      pwm/servlet/src/password/pwm/config/value/ChallengeValue.java
  17. 14 15
      pwm/servlet/src/password/pwm/config/value/EmailValue.java
  18. 11 7
      pwm/servlet/src/password/pwm/config/value/FileValue.java
  19. 3 3
      pwm/servlet/src/password/pwm/config/value/FormValue.java
  20. 11 12
      pwm/servlet/src/password/pwm/config/value/LocalizedStringArrayValue.java
  21. 7 11
      pwm/servlet/src/password/pwm/config/value/LocalizedStringValue.java
  22. 7 11
      pwm/servlet/src/password/pwm/config/value/OptionListValue.java
  23. 16 8
      pwm/servlet/src/password/pwm/config/value/PasswordValue.java
  24. 4 4
      pwm/servlet/src/password/pwm/config/value/StringArrayValue.java
  25. 0 1
      pwm/servlet/src/password/pwm/config/value/StringValue.java
  26. 3 3
      pwm/servlet/src/password/pwm/config/value/UserPermissionValue.java
  27. 2 5
      pwm/servlet/src/password/pwm/config/value/VerificationMethodValue.java
  28. 17 14
      pwm/servlet/src/password/pwm/config/value/X509CertificateValue.java
  29. 1 1
      pwm/servlet/src/password/pwm/http/ContextManager.java
  30. 5 2
      pwm/servlet/src/password/pwm/http/PwmRequest.java
  31. 2 3
      pwm/servlet/src/password/pwm/http/PwmResponse.java
  32. 1 1
      pwm/servlet/src/password/pwm/http/PwmSession.java
  33. 1 1
      pwm/servlet/src/password/pwm/http/SessionManager.java
  34. 33 13
      pwm/servlet/src/password/pwm/http/servlet/ChangePasswordServlet.java
  35. 1 1
      pwm/servlet/src/password/pwm/http/servlet/ConfigEditorServlet.java
  36. 10 10
      pwm/servlet/src/password/pwm/http/servlet/ConfigManagerServlet.java
  37. 5 1
      pwm/servlet/src/password/pwm/http/servlet/ForgottenPasswordServlet.java
  38. 3 6
      pwm/servlet/src/password/pwm/http/servlet/NewUserServlet.java
  39. 2 2
      pwm/servlet/src/password/pwm/http/servlet/OAuthConsumerServlet.java
  40. 15 13
      pwm/servlet/src/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java
  41. 11 11
      pwm/servlet/src/password/pwm/http/servlet/peoplesearch/PeopleSearchServlet.java
  42. 3 3
      pwm/servlet/src/password/pwm/i18n/Config.properties
  43. 2 2
      pwm/servlet/src/password/pwm/ldap/UserSearchEngine.java
  44. 7 6
      pwm/servlet/src/password/pwm/token/TokenService.java
  45. 3 1
      pwm/servlet/src/password/pwm/util/BuildChecksumMaker.java
  46. 19 0
      pwm/servlet/src/password/pwm/util/Helper.java
  47. 11 9
      pwm/servlet/src/password/pwm/util/PasswordData.java
  48. 1 0
      pwm/servlet/src/password/pwm/util/RandomPasswordGenerator.java
  49. 1 0
      pwm/servlet/src/password/pwm/util/ServletHelper.java
  50. 8 6
      pwm/servlet/src/password/pwm/util/X509Utils.java
  51. 3 2
      pwm/servlet/src/password/pwm/util/cache/CacheKey.java
  52. 2 1
      pwm/servlet/src/password/pwm/util/intruder/IntruderManager.java
  53. 1 1
      pwm/servlet/src/password/pwm/util/intruder/RecordManagerImpl.java
  54. 1 1
      pwm/servlet/src/password/pwm/util/macro/StandardMacros.java
  55. 2 2
      pwm/servlet/src/password/pwm/util/operations/OtpService.java
  56. 23 21
      pwm/servlet/src/password/pwm/util/operations/otp/AbstractOtpOperator.java
  57. 3 6
      pwm/servlet/src/password/pwm/util/operations/otp/DbOtpOperator.java
  58. 4 6
      pwm/servlet/src/password/pwm/util/operations/otp/LdapOtpOperator.java
  59. 6 5
      pwm/servlet/src/password/pwm/util/operations/otp/LocalDbOtpOperator.java
  60. 1 0
      pwm/servlet/src/password/pwm/util/queue/SmsQueueManager.java
  61. 3 2
      pwm/servlet/src/password/pwm/util/report/ReportSettings.java
  62. 1 1
      pwm/servlet/src/password/pwm/util/report/UserCacheService.java
  63. 33 0
      pwm/servlet/src/password/pwm/util/secure/PwmBlockAlgorithm.java
  64. 18 0
      pwm/servlet/src/password/pwm/util/secure/PwmHashAlgorithm.java
  65. 1 1
      pwm/servlet/src/password/pwm/util/secure/PwmRandom.java
  66. 65 0
      pwm/servlet/src/password/pwm/util/secure/PwmSecurityKey.java
  67. 114 225
      pwm/servlet/src/password/pwm/util/secure/SecureHelper.java
  68. 98 0
      pwm/servlet/src/password/pwm/util/secure/SecureService.java
  69. 6 2
      pwm/servlet/src/password/pwm/util/stats/StatisticsManager.java
  70. 3 2
      pwm/servlet/src/password/pwm/wordlist/AbstractWordlist.java
  71. 1 1
      pwm/servlet/src/password/pwm/wordlist/SeedlistManager.java
  72. 20 23
      pwm/servlet/src/password/pwm/wordlist/SharedHistoryManager.java
  73. 5 4
      pwm/servlet/src/password/pwm/ws/client/rest/naaf/NAAFEndPoint.java
  74. 3 2
      pwm/servlet/src/password/pwm/ws/server/rest/RestAppDataServer.java
  75. 1 1
      pwm/servlet/src/password/pwm/ws/server/rest/RestRandomPasswordServer.java
  76. 1 1
      pwm/servlet/tests/junit/password/pwm/tests/LocalDBLoggerTest.java
  77. 1 1
      pwm/servlet/tests/junit/password/pwm/tests/LocalDBStoredQueueTest.java
  78. 4 3
      pwm/servlet/web/WEB-INF/jsp/configguide-ldapcert.jsp
  79. 1 1
      pwm/servlet/web/public/reference/referencedoc.jsp
  80. 1 0
      pwm/servlet/web/public/resources/configStyle.css
  81. 10 10
      pwm/servlet/web/public/resources/js/helpdesk.js

+ 5 - 0
pwm/servlet/src/password/pwm/AppProperty.java

@@ -161,6 +161,7 @@ public enum AppProperty {
     OTP_RECOVERY_HASH_METHOD                        ("otp.recoveryHash.method"),
     OTP_QR_IMAGE_HEIGHT                             ("otp.qrImage.height"),
     OTP_QR_IMAGE_WIDTH                              ("otp.qrImage.width"),
+    OTP_ENCRYPTION_ALG                              ("otp.encryptionAlg"),
     PASSWORD_RANDOMGEN_MAX_ATTEMPTS                 ("password.randomGenerator.maxAttempts"),
     PASSWORD_RANDOMGEN_MAX_LENGTH                   ("password.randomGenerator.maxLength"),
     PASSWORD_RANDOMGEN_JITTER_COUNT                 ("password.randomGenerator.jitter.count"),
@@ -191,9 +192,13 @@ public enum AppProperty {
     SECURITY_SHAREDHISTORY_HASH_ITERATIONS          ("security.sharedHistory.hashIterations"),
     SECURITY_SHAREDHISTORY_HASH_NAME                ("security.sharedHistory.hashName"),
     SECURITY_SHAREDHISTORY_CASE_INSENSITIVE         ("security.sharedHistory.caseInsensitive"),
+    SECURITY_SHAREDHISTORY_SALT_LENGTH              ("security.sharedHistory.saltLength"),
     SECURITY_CERTIFICATES_VALIDATE_TIMESTAMPS       ("security.certs.validateTimestamps"),
     SECURITY_LDAP_BASEDN_RESOLVE_CANONICAL_DN       ("security.ldap.resolveCanonicalDN"),
     SECURITY_LDAP_BASEDN_CANONICAL_CACHE_SECONDS    ("security.ldap.canonicalCacheSeconds"),
+    SECURITY_CONFIG_MIN_SECURITY_KEY_LENGTH         ("security.config.minSecurityKeyLength"),
+    SECURITY_DEFAULT_EPHEMERAL_BLOCK_ALG            ("security.defaultEphemeralBlockAlg"),
+    SECURITY_DEFAULT_EPHEMERAL_HASH_ALG             ("security.defaultEphemeralHashAlg"),
     TOKEN_REMOVAL_DELAY_MS                          ("token.removalDelayMS"),
     TOKEN_PURGE_BATCH_SIZE                          ("token.purgeBatchSize"),
     TOKEN_MAX_UNIQUE_CREATE_ATTEMPTS                ("token.maxUniqueCreateAttempts"),

+ 5 - 0
pwm/servlet/src/password/pwm/AppProperty.properties

@@ -149,6 +149,7 @@ otp.recoveryHash.iterations=1000
 otp.recoveryHash.method=SHA1
 otp.qrImage.height=200
 otp.qrImage.width=200
+otp.encryptionAlg=AES
 password.randomGenerator.maxAttempts=2000
 password.randomGenerator.maxLength=1024
 password.randomGenerator.jitter.count=50
@@ -179,9 +180,13 @@ security.ws.rest.clientKeyLength=32
 security.sharedHistory.hashIterations=100000
 security.sharedHistory.hashName=SHA-512
 security.sharedHistory.caseInsensitive=true
+security.sharedHistory.saltLength=64
 security.certs.validateTimestamps=false
 security.ldap.resolveCanonicalDN=true
 security.ldap.canonicalCacheSeconds=30
+security.defaultEphemeralBlockAlg=AES_HMAC
+security.defaultEphemeralHashAlg=SHA512
+security.config.minSecurityKeyLength=32
 token.removalDelayMS=86400000
 token.purgeBatchSize=1000
 token.maxUniqueCreateAttempts=100

+ 2 - 0
pwm/servlet/src/password/pwm/PwmAboutProperty.java

@@ -25,6 +25,8 @@ public enum PwmAboutProperty {
     app_localDbStorageSize,
     app_localDbFreeSpace,
     app_configurationRestartCounter,
+    app_secureBlockAlgorithm,
+    app_secureHashAlgorithm,
 
     build_Time,
     build_Number,

+ 15 - 2
pwm/servlet/src/password/pwm/PwmApplication.java

@@ -40,7 +40,10 @@ import password.pwm.event.SystemAuditRecord;
 import password.pwm.health.HealthMonitor;
 import password.pwm.ldap.LdapConnectionService;
 import password.pwm.token.TokenService;
-import password.pwm.util.*;
+import password.pwm.util.Helper;
+import password.pwm.util.JsonUtil;
+import password.pwm.util.TimeDuration;
+import password.pwm.util.UrlShortenerService;
 import password.pwm.util.cache.CacheService;
 import password.pwm.util.db.DatabaseAccessorImpl;
 import password.pwm.util.intruder.IntruderManager;
@@ -57,6 +60,8 @@ import password.pwm.util.operations.OtpService;
 import password.pwm.util.queue.EmailQueueManager;
 import password.pwm.util.queue.SmsQueueManager;
 import password.pwm.util.report.ReportService;
+import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.secure.SecureService;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 import password.pwm.wordlist.SeedlistManager;
@@ -126,6 +131,7 @@ public class PwmApplication {
     private MODE applicationMode;
 
     private static final List<Class<? extends PwmService>> PWM_SERVICE_CLASSES  = Collections.unmodifiableList(Arrays.asList(
+            SecureService.class,
             LdapConnectionService.class,
             DatabaseAccessorImpl.class,
             SharedHistoryManager.class,
@@ -214,7 +220,7 @@ public class PwmApplication {
         this.localDBLogger = PwmLogManager.initializeLocalDBLogger(this);
 
         // log the loaded configuration
-        LOGGER.info("loaded configuration: \n" + configuration.toString());
+        LOGGER.info("configuration load completed");
 
         // read the pwm servlet instance id
         instanceID = fetchInstanceID(localDB, this);
@@ -277,6 +283,9 @@ public class PwmApplication {
 
     private void postInitTasks() {
         final Date startTime = new Date();
+
+        LOGGER.debug("loaded configuration: \n" + configuration.toDebugString());
+
         // detect if config has been modified since previous startup
         try {
             final String previousHash = readAppAttribute(AppAttribute.CONFIG_HASH);
@@ -502,6 +511,10 @@ public class PwmApplication {
         return (CacheService)pwmServices.get(CacheService.class);
     }
 
+    public SecureService getSecureService() {
+        return (SecureService)pwmServices.get(SecureService.class);
+    }
+
     public void sendSmsUsingQueue(
             final SmsItemBean smsItem,
             final MacroMachine macroMachine

+ 5 - 0
pwm/servlet/src/password/pwm/PwmConstants.java

@@ -24,6 +24,8 @@ package password.pwm;
 
 import org.apache.commons.csv.CSVFormat;
 import password.pwm.bean.SessionLabel;
+import password.pwm.util.secure.PwmBlockAlgorithm;
+import password.pwm.util.secure.PwmHashAlgorithm;
 
 import java.nio.charset.Charset;
 import java.text.DateFormat;
@@ -129,6 +131,9 @@ public abstract class PwmConstants {
     public static final String SESSION_ATTR_PWM_SESSION = "PwmSession";
     public static final String SESSION_ATTR_CONTEXT_GUID = "ContextInstanceGUID";
 
+    public static final PwmBlockAlgorithm IN_MEMORY_PASSWORD_ENCRYPT_METHOD = PwmBlockAlgorithm.AES;
+    public static final PwmHashAlgorithm SETTING_CHECKSUM_HASH_METHOD = PwmHashAlgorithm.SHA256;
+
     public static enum REQUEST_ATTR {
         PwmErrorInfo,
         PwmRequest,

+ 1 - 1
pwm/servlet/src/password/pwm/bean/SessionStateBean.java

@@ -25,7 +25,7 @@ package password.pwm.bean;
 import password.pwm.config.ShortcutItem;
 import password.pwm.http.bean.PwmSessionBean;
 import password.pwm.i18n.Message;
-import password.pwm.util.PwmRandom;
+import password.pwm.util.secure.PwmRandom;
 
 import java.util.Date;
 import java.util.Locale;

+ 6 - 10
pwm/servlet/src/password/pwm/bean/UserIdentity.java

@@ -31,9 +31,7 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 
-import javax.crypto.SecretKey;
 import java.io.Serializable;
 import java.util.StringTokenizer;
 
@@ -78,7 +76,7 @@ public class UserIdentity implements Serializable, Comparable {
         return "UserIdentity" + JsonUtil.serialize(this);
     }
 
-    public String toObfuscatedKey(final Configuration configuration)
+    public String toObfuscatedKey(final PwmApplication pwmApplication)
             throws PwmUnrecoverableException
     {
         final String cachedValue = obfuscatedValue;
@@ -86,9 +84,8 @@ public class UserIdentity implements Serializable, Comparable {
             return cachedValue;
         }
         try {
-            final SecretKey secretKey = configuration.getSecurityKey();
             final String jsonValue = JsonUtil.serialize(this);
-            final String localValue = CRYPO_HEADER + SecureHelper.encryptToString(jsonValue, secretKey, true);
+            final String localValue = CRYPO_HEADER + pwmApplication.getSecureService().encryptToString(jsonValue);
             this.obfuscatedValue = localValue;
             return localValue;
         } catch (Exception e) {
@@ -104,7 +101,7 @@ public class UserIdentity implements Serializable, Comparable {
         return this.getUserDN() + ((this.getLdapProfileID() != null && !this.getLdapProfileID().isEmpty()) ? " (" + this.getLdapProfileID() + ")" : "");
     }
 
-    public static UserIdentity fromObfuscatedKey(final String key, final Configuration configuration) throws PwmUnrecoverableException {
+    public static UserIdentity fromObfuscatedKey(final String key, final PwmApplication pwmApplication) throws PwmUnrecoverableException {
         if (key == null || key.length() < 1) {
             return null;
         }
@@ -115,8 +112,7 @@ public class UserIdentity implements Serializable, Comparable {
 
         try {
             final String input = key.substring(CRYPO_HEADER.length(),key.length());
-            final SecretKey secretKey = configuration.getSecurityKey();
-            final String jsonValue = SecureHelper.decryptStringValue(input, secretKey, true);
+            final String jsonValue = pwmApplication.getSecureService().decryptStringValue(input);
             return JsonUtil.deserialize(jsonValue,UserIdentity.class);
         } catch (Exception e) {
             throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_UNKNOWN,"unexpected error reversing obfuscated user key: " + e.getMessage()));
@@ -139,13 +135,13 @@ public class UserIdentity implements Serializable, Comparable {
         return new UserIdentity(userDN,profileID);
     }
 
-    public static UserIdentity fromKey(final String key, final Configuration configuration) throws PwmUnrecoverableException {
+    public static UserIdentity fromKey(final String key, final PwmApplication pwmApplication) throws PwmUnrecoverableException {
         if (key == null || key.length() < 1) {
             return null;
         }
 
         if (key.startsWith(CRYPO_HEADER)) {
-            return fromObfuscatedKey(key,configuration);
+            return fromObfuscatedKey(key, pwmApplication);
         }
 
         return fromDelimitedKey(key);

+ 8 - 20
pwm/servlet/src/password/pwm/config/Configuration.java

@@ -36,13 +36,13 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.LocaleHelper;
+import password.pwm.util.JsonUtil;
 import password.pwm.util.PasswordData;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.StringUtil;
 import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmSecurityKey;
 
-import javax.crypto.SecretKey;
 import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.security.cert.X509Certificate;
@@ -66,21 +66,13 @@ public class Configuration implements Serializable, SettingReader {
         this.storedConfiguration = storedConfiguration;
     }
 
-// ------------------------ CANONICAL METHODS ------------------------
-
-    public String toString() {
+    public String toDebugString() {
         final StringBuilder outputText = new StringBuilder();
         outputText.append("  ");
-        outputText.append(storedConfiguration.toString(true));
+        outputText.append(JsonUtil.serialize(storedConfiguration.toJsonDebugObject()));
         return outputText.toString().replaceAll("\n","\n  ");
     }
 
-    public String toString(final PwmSetting pwmSetting) {
-        return this.storedConfiguration.readSetting(pwmSetting).toDebugString(false,PwmConstants.DEFAULT_LOCALE);
-    }
-
-// -------------------------- OTHER METHODS --------------------------
-
     public List<FormConfiguration> readSettingAsForm(final PwmSetting setting) {
         final StoredValue value = readStoredValue(setting);
         return JavaTypeConverter.valueToForm(value);
@@ -488,15 +480,11 @@ public class Configuration implements Serializable, SettingReader {
         return (X509Certificate[])readStoredValue(setting).toNativeObject();
     }
 
-    public String toDebugString() {
-        return storedConfiguration.toString(true);
-    }
-
     public String getNotes() {
         return storedConfiguration.readConfigProperty(StoredConfiguration.ConfigProperty.PROPERTY_KEY_NOTES);
     }
 
-    public SecretKey getSecurityKey() throws PwmUnrecoverableException {
+    public PwmSecurityKey getSecurityKey() throws PwmUnrecoverableException {
         final PasswordData configValue = readSettingAsPassword(PwmSetting.PWM_SECURITY_KEY);
         if (configValue == null) {
             final String errorMsg = "Security Key value is not configured";
@@ -504,15 +492,15 @@ public class Configuration implements Serializable, SettingReader {
             throw new PwmUnrecoverableException(errorInfo);
         }
 
-        final String rawValue = configValue.getStringValue();
-        if (rawValue.length() < 32) {
+        final int minSecurityKeyLength = Integer.parseInt(readAppProperty(AppProperty.SECURITY_CONFIG_MIN_SECURITY_KEY_LENGTH));
+        if (configValue.getStringValue().length() < minSecurityKeyLength) {
             final String errorMsg = "Security Key must be greater than 32 characters in length";
             final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_INVALID_SECURITY_KEY, errorMsg);
             throw new PwmUnrecoverableException(errorInfo);
         }
 
         try {
-            return SecureHelper.makeKey(rawValue);
+            return new PwmSecurityKey(configValue.getStringValue());
         } catch (Exception e) {
             final String errorMsg = "unexpected error generating Security Key crypto: " + e.getMessage();
             final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_INVALID_SECURITY_KEY, errorMsg);

+ 2 - 1
pwm/servlet/src/password/pwm/config/ConfigurationReader.java

@@ -33,6 +33,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.event.AuditEvent;
 import password.pwm.event.SystemAuditRecord;
 import password.pwm.util.Helper;
+import password.pwm.util.JsonUtil;
 import password.pwm.util.logging.PwmLogger;
 
 import java.io.*;
@@ -188,7 +189,7 @@ public class ConfigurationReader {
             saveInProgress = true;
 
             storedConfiguration.toXml(new FileOutputStream(configFile, false));
-            LOGGER.info("saved configuration " + storedConfiguration.toString(true));
+            LOGGER.info("saved configuration " + JsonUtil.serialize(storedConfiguration.toJsonDebugObject()));
             if (pwmApplication != null) {
                 final String actualChecksum = storedConfiguration.settingChecksum();
                 pwmApplication.writeAppAttribute(PwmApplication.AppAttribute.CONFIG_HASH, actualChecksum);

+ 3 - 3
pwm/servlet/src/password/pwm/config/PwmSetting.java

@@ -1122,14 +1122,14 @@ public enum PwmSetting {
         return defaultValues.get(templates);
     }
 
-    public Map<PwmSettingTemplate, String> getDefaultValueDebugStrings(final boolean prettyPrint, final Locale locale)
+    public Map<PwmSettingTemplate, String> getDefaultValueDebugStrings(final Locale locale)
             throws PwmOperationalException, PwmUnrecoverableException {
         final Map<PwmSettingTemplate, String> returnObj = new LinkedHashMap<>();
-        final String defaultDebugStr = this.getDefaultValue(PwmSettingTemplate.DEFAULT).toDebugString(prettyPrint, locale);
+        final String defaultDebugStr = this.getDefaultValue(PwmSettingTemplate.DEFAULT).toDebugString(locale);
         returnObj.put(PwmSettingTemplate.DEFAULT, defaultDebugStr);
         for (final PwmSettingTemplate template : PwmSettingTemplate.values()) {
             if (template != PwmSettingTemplate.DEFAULT) {
-                final String debugStr = this.getDefaultValue(template).toDebugString(prettyPrint, locale);
+                final String debugStr = this.getDefaultValue(template).toDebugString(locale);
                 if (!defaultDebugStr.equals(debugStr)) {
                     returnObj.put(template, debugStr);
                 }

+ 14 - 18
pwm/servlet/src/password/pwm/config/StoredConfiguration.java

@@ -39,6 +39,8 @@ import password.pwm.i18n.LocaleHelper;
 import password.pwm.i18n.PwmLocaleBundle;
 import password.pwm.util.*;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -283,7 +285,7 @@ public class StoredConfiguration implements Serializable {
                 recordMap.put("profile", settingValueRecord.getProfile());
             }
             if (settingValueRecord.getStoredValue() != null) {
-                recordMap.put("value", settingValueRecord.getStoredValue().toDebugString(true,locale));
+                recordMap.put("value", settingValueRecord.getStoredValue().toDebugString(locale));
             }
             final SettingMetaData settingMetaData = readSettingMetadata(settingValueRecord.getSetting(), settingValueRecord.getProfile());
             if (settingMetaData != null) {
@@ -384,20 +386,16 @@ public class StoredConfiguration implements Serializable {
         writeConfigProperty(ConfigProperty.PROPERTY_KEY_TEMPLATE, template.toString());
     }
 
-    public String toString() {
-        return toString(false);
-    }
-
     public String toString(final PwmSetting setting, final String profileID ) {
         final StoredValue storedValue = readSetting(setting, profileID);
-        return setting.getKey() + "=" + storedValue.toDebugString(false, null);
+        return setting.getKey() + "=" + storedValue.toDebugString(null);
     }
 
     public Map<String,String> getModifiedSettingDebugValues(final Locale locale, final boolean prettyPrint) {
         final Map<String,String> returnObj = new LinkedHashMap<>();
         for (SettingValueRecord record : this.modifiedSettings()) {
             final String label = record.getSetting().toMenuLocationDebug(record.getProfile(),locale);
-            final String value = record.getStoredValue().toDebugString(true, locale);
+            final String value = record.getStoredValue().toDebugString(locale);
             returnObj.put(label,value);
         }
         return returnObj;
@@ -440,7 +438,7 @@ public class StoredConfiguration implements Serializable {
         }
     }
 
-    public String toString(final boolean linebreaks) {
+    public Serializable toJsonDebugObject() {
         domModifyLock.readLock().lock();
         try {
             final TreeMap<String,Object> outputObject = new TreeMap<>();
@@ -449,7 +447,7 @@ public class StoredConfiguration implements Serializable {
                 if (setting.getSyntax() != PwmSettingSyntax.PROFILE && !setting.getCategory().hasProfiles()) {
                     if (!isDefaultValue(setting,null)) {
                         final StoredValue value = readSetting(setting);
-                        outputObject.put(setting.getKey(), value.toDebugString(false, null));
+                        outputObject.put(setting.getKey(), value.toDebugJsonObject(null));
                     }
                 }
             }
@@ -458,11 +456,11 @@ public class StoredConfiguration implements Serializable {
                 if (category.hasProfiles()) {
                     final TreeMap<String,Object> profiles = new TreeMap<>();
                     for (final String profileID : this.profilesForSetting(category.getProfileSetting())) {
-                        final TreeMap<String,String> profileObject = new TreeMap<>();
+                        final TreeMap<String,Object> profileObject = new TreeMap<>();
                         for (final PwmSetting profileSetting : category.getSettings()) {
                             if (!isDefaultValue(profileSetting, profileID)) {
                                 final StoredValue value = readSetting(profileSetting, profileID);
-                                profileObject.put(profileSetting.getKey(), value.toDebugString(false, null));
+                                profileObject.put(profileSetting.getKey(), value.toDebugJsonObject(null));
                             }
                         }
                         profiles.put(profileID,profileObject);
@@ -471,9 +469,7 @@ public class StoredConfiguration implements Serializable {
                 }
             }
 
-            return linebreaks
-                    ? JsonUtil.serialize(outputObject, JsonUtil.Flag.PrettyPrint)
-                    : JsonUtil.serialize(outputObject);
+            return outputObject;
         } finally {
             domModifyLock.readLock().unlock();
         }
@@ -651,8 +647,8 @@ public class StoredConfiguration implements Serializable {
             return false;
         }
         {
-            final String valueDebug = value.toDebugString(true, locale);
-            if (valueDebug.toLowerCase().contains(lowerSearchTerm)) {
+            final String valueDebug = value.toDebugString(locale);
+            if (valueDebug != null && valueDebug.toLowerCase().contains(lowerSearchTerm)) {
                 return true;
             }
         }
@@ -823,7 +819,7 @@ public class StoredConfiguration implements Serializable {
         }
 
 
-        final String result = SecureHelper.hash(sb.toString());
+        final String result = SecureHelper.hash(sb.toString(), PwmConstants.SETTING_CHECKSUM_HASH_METHOD);
         LOGGER.trace("computed setting checksum in " + TimeDuration.fromCurrent(startTime).asCompactString());
         return result;
     }
@@ -1239,7 +1235,7 @@ public class StoredConfiguration implements Serializable {
                         final StoredValue currentValue = readSetting((PwmSetting) configRecordID.recordID, configRecordID.profileID);
                         final PwmSetting pwmSetting = (PwmSetting) configRecordID.recordID;
                         final String keyName = pwmSetting.toMenuLocationDebug(configRecordID.getProfileID(), locale);
-                        final String debugValue = currentValue.toDebugString(asHtml, locale);
+                        final String debugValue = currentValue.toDebugString(locale);
                         outputMap.put(keyName,debugValue);
                     }
                     break;

+ 4 - 1
pwm/servlet/src/password/pwm/config/StoredValue.java

@@ -37,8 +37,11 @@ public interface StoredValue extends Serializable {
 
     List<String> validateValue(PwmSetting pwm);
 
+    Serializable toDebugJsonObject(
+            Locale locale
+    );
+
     String toDebugString(
-            boolean prettyFormat,
             Locale locale
     );
 

+ 12 - 7
pwm/servlet/src/password/pwm/config/value/AbstractValue.java

@@ -22,23 +22,28 @@
 
 package password.pwm.config.value;
 
+import password.pwm.PwmConstants;
 import password.pwm.config.StoredValue;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.Serializable;
 import java.util.Locale;
 
 public abstract class AbstractValue implements StoredValue {
     public String toString() {
-        return toDebugString(false, null);
+        return toDebugString(null);
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        return prettyFormat
-                ? JsonUtil.serialize((Serializable)this.toNativeObject(), JsonUtil.Flag.PrettyPrint)
-                : JsonUtil.serialize((Serializable)this.toNativeObject());
+    @Override
+    public String toDebugString(Locale locale) {
+        return JsonUtil.serialize((Serializable) this.toNativeObject(), JsonUtil.Flag.PrettyPrint);
+    }
+
+    @Override
+    public Serializable toDebugJsonObject(Locale locale) {
+        return (Serializable)this.toNativeObject();
     }
 
     public boolean requiresStoredUpdate()
@@ -54,6 +59,6 @@ public abstract class AbstractValue implements StoredValue {
 
     @Override
     public String valueHash() throws PwmUnrecoverableException {
-        return SecureHelper.hash(JsonUtil.serialize((Serializable)this.toNativeObject()));
+        return SecureHelper.hash(JsonUtil.serialize((Serializable)this.toNativeObject()), PwmConstants.SETTING_CHECKSUM_HASH_METHOD);
     }
 }

+ 39 - 0
pwm/servlet/src/password/pwm/config/value/ActionValue.java

@@ -130,4 +130,43 @@ public class ActionValue extends AbstractValue implements StoredValue {
 
         return Collections.emptyList();
     }
+
+    public String toDebugString(Locale locale) {
+        final StringBuilder sb = new StringBuilder();
+        int counter = 0;
+        for (final ActionConfiguration actionConfiguration : values) {
+            sb.append("Action");
+            if (values.size() > 1) {
+                sb.append(counter);
+            }
+            sb.append("-");
+            sb.append(actionConfiguration.getType() == null ? ActionConfiguration.Type.ldap.toString() : actionConfiguration.getType().toString());
+            sb.append(": [");
+            switch (actionConfiguration.getType()) {
+                case webservice: {
+                    sb.append("WebService: ");
+                    sb.append("method=" + actionConfiguration.getMethod());
+                    sb.append(" url=" + actionConfiguration.getUrl());
+                    sb.append(" headers=" + JsonUtil.serializeMap(actionConfiguration.getHeaders()));
+                    sb.append(" body=" + actionConfiguration.getBody());
+                }
+                break;
+
+                case ldap: {
+                    sb.append("LDAP: ");
+                    sb.append("method=" + actionConfiguration.getLdapMethod());
+                    sb.append(" attribute=" + actionConfiguration.getAttributeName());
+                    sb.append(" value=" + actionConfiguration.getAttributeValue());
+
+                }
+            }
+            sb.append("]");
+            counter++;
+            if (counter != values.size()) {
+                sb.append("\n");
+            }
+        }
+        return sb.toString();
+    }
+
 }

+ 10 - 8
pwm/servlet/src/password/pwm/config/value/BooleanValue.java

@@ -30,6 +30,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.Display;
 import password.pwm.util.JsonUtil;
 
+import java.io.Serializable;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -76,15 +77,16 @@ public class BooleanValue implements StoredValue {
         return value;
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
+    public String toDebugString(Locale locale) {
         locale = locale == null ? PwmConstants.DEFAULT_LOCALE : locale;
-        if (prettyFormat) {
-            return value
-                    ? Display.getLocalizedMessage(locale,Display.Value_True,null)
-                    : Display.getLocalizedMessage(locale,Display.Value_False,null);
-        } else {
-            return Boolean.toString(value);
-        }
+        return value
+                ? Display.getLocalizedMessage(locale,Display.Value_True,null)
+                : Display.getLocalizedMessage(locale,Display.Value_False,null);
+    }
+
+    @Override
+    public Serializable toDebugJsonObject(Locale locale) {
+        return value;
     }
 
     @Override

+ 17 - 18
pwm/servlet/src/password/pwm/config/value/ChallengeValue.java

@@ -182,25 +182,24 @@ public class ChallengeValue extends AbstractValue implements StoredValue {
         return new ChallengeItemBean(challengeText, minLength, maxLength, adminDefined);
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
-            final StringBuilder sb = new StringBuilder();
-            for (final String localeKey : values.keySet()) {
-                final List<ChallengeItemBean> challengeItems = values.get(localeKey);
-                sb.append("Locale: ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append("\n");
-                for (ChallengeItemBean challengeItemBean : challengeItems) {
-                    sb.append(" ChallengeItem: [AdminDefined: ").append(challengeItemBean.isAdminDefined());
-                    sb.append(" MinLength:").append(challengeItemBean.getMinLength());
-                    sb.append(" MaxLength:").append(challengeItemBean.getMaxLength());
-                    sb.append(" MaxQuestionCharsInAnswer:").append(challengeItemBean.getMaxQuestionCharsInAnswer());
-                    sb.append(" EnforceWordlist:").append(challengeItemBean.isEnforceWordlist());
-                    sb.append("]\n");
-                    sb.append("  Text:").append(challengeItemBean.getText()).append("\n");
-                }
+    public String toDebugString(Locale locale) {
+        if (values == null) {
+            return "No Actions";
+        }
+        final StringBuilder sb = new StringBuilder();
+        for (final String localeKey : values.keySet()) {
+            final List<ChallengeItemBean> challengeItems = values.get(localeKey);
+            sb.append("Locale: ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append("\n");
+            for (ChallengeItemBean challengeItemBean : challengeItems) {
+                sb.append(" ChallengeItem: [AdminDefined: ").append(challengeItemBean.isAdminDefined());
+                sb.append(" MinLength:").append(challengeItemBean.getMinLength());
+                sb.append(" MaxLength:").append(challengeItemBean.getMaxLength());
+                sb.append(" MaxQuestionCharsInAnswer:").append(challengeItemBean.getMaxQuestionCharsInAnswer());
+                sb.append(" EnforceWordlist:").append(challengeItemBean.isEnforceWordlist());
+                sb.append("]\n");
+                sb.append("  Text:").append(challengeItemBean.getText()).append("\n");
             }
-            return sb.toString();
-        } else {
-            return JsonUtil.serializeMap(values);
         }
+        return sb.toString();
     }
 }

+ 14 - 15
pwm/servlet/src/password/pwm/config/value/EmailValue.java

@@ -213,21 +213,20 @@ public class EmailValue extends AbstractValue implements StoredValue {
         return Collections.emptyList();
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
-            final StringBuilder sb = new StringBuilder();
-            for (final String localeKey : values.keySet()) {
-                final EmailItemBean emailItemBean = values.get(localeKey);
-                sb.append("EmailItem ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append(": \n");
-                sb.append("  To:").append(emailItemBean.getTo()).append("\n");
-                sb.append("From:").append(emailItemBean.getFrom()).append("\n");
-                sb.append("Subj:").append(emailItemBean.getSubject()).append("\n");
-                sb.append("Body:").append(emailItemBean.getBodyPlain()).append("\n");
-                sb.append("Html:").append(emailItemBean.getBodyHtml()).append("\n");
-            }
-            return sb.toString();
-        } else {
-            return JsonUtil.serializeMap(values);
+    public String toDebugString(Locale locale) {
+        if (values == null) {
+            return "No Email Item";
+        }
+        final StringBuilder sb = new StringBuilder();
+        for (final String localeKey : values.keySet()) {
+            final EmailItemBean emailItemBean = values.get(localeKey);
+            sb.append("EmailItem ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append(": \n");
+            sb.append("  To:").append(emailItemBean.getTo()).append("\n");
+            sb.append("From:").append(emailItemBean.getFrom()).append("\n");
+            sb.append("Subj:").append(emailItemBean.getSubject()).append("\n");
+            sb.append("Body:").append(emailItemBean.getBodyPlain()).append("\n");
+            sb.append("Html:").append(emailItemBean.getBodyHtml()).append("\n");
         }
+        return sb.toString();
     }
 }

+ 11 - 7
pwm/servlet/src/password/pwm/config/value/FileValue.java

@@ -23,14 +23,16 @@
 package password.pwm.config.value;
 
 import org.jdom2.Element;
+import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.StoredValue;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.StringUtil;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -101,7 +103,7 @@ public class FileValue extends AbstractValue implements StoredValue {
         public String sha1sum()
                 throws PwmUnrecoverableException
         {
-            return SecureHelper.hash(new ByteArrayInputStream(contents), SecureHelper.HashAlgorithm.SHA1);
+            return SecureHelper.hash(new ByteArrayInputStream(contents), PwmHashAlgorithm.SHA1);
         }
 
         public int size()
@@ -195,14 +197,16 @@ public class FileValue extends AbstractValue implements StoredValue {
 
     @Override
     public String toDebugString(
-            boolean prettyFormat,
             Locale locale
     )
     {
         final List<Map<String, Object>> output = asMetaData();
-        return prettyFormat
-                ? JsonUtil.serialize((Serializable)output, JsonUtil.Flag.PrettyPrint)
-                : JsonUtil.serialize((Serializable)output);
+        return JsonUtil.serialize((Serializable)output, JsonUtil.Flag.PrettyPrint);
+    }
+
+    @Override
+    public Serializable toDebugJsonObject(Locale locale) {
+        return (Serializable)asMetaData();
     }
 
     public List<Map<String, Object>> asMetaData()
@@ -246,6 +250,6 @@ public class FileValue extends AbstractValue implements StoredValue {
 
     @Override
     public String valueHash() throws PwmUnrecoverableException {
-        return SecureHelper.hash(JsonUtil.serializeCollection(toInfoMap()));
+        return SecureHelper.hash(JsonUtil.serializeCollection(toInfoMap()), PwmConstants.SETTING_CHECKSUM_HASH_METHOD);
     }
 }

+ 3 - 3
pwm/servlet/src/password/pwm/config/value/FormValue.java

@@ -130,8 +130,8 @@ public class FormValue extends AbstractValue implements StoredValue {
         return needsXmlUpdate;
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
+    public String toDebugString(Locale locale) {
+        if (values != null && !values.isEmpty()) {
             final StringBuilder sb = new StringBuilder();
             for (final FormConfiguration formRow : values) {
                 sb.append("FormItem Name:").append(formRow.getName()).append("\n");
@@ -152,7 +152,7 @@ public class FormValue extends AbstractValue implements StoredValue {
             }
             return sb.toString();
         } else {
-            return JsonUtil.serializeCollection(values);
+            return "";
         }
     }
 

+ 11 - 12
pwm/servlet/src/password/pwm/config/value/LocalizedStringArrayValue.java

@@ -118,21 +118,20 @@ public class LocalizedStringArrayValue extends AbstractValue implements StoredVa
     }
 
     @Override
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
-            final StringBuilder sb = new StringBuilder();
-            for (final String localeKey : values.keySet()) {
-                if (!values.get(localeKey).isEmpty()) {
-                    sb.append("Locale: ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append("\n");
-                    for (final String value : values.get(localeKey)) {
-                        sb.append("  ").append(value).append("\n");
-                    }
+    public String toDebugString(Locale locale) {
+        if (values == null) {
+            return "";
+        }
+        final StringBuilder sb = new StringBuilder();
+        for (final String localeKey : values.keySet()) {
+            if (!values.get(localeKey).isEmpty()) {
+                sb.append("Locale: ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append("\n");
+                for (final String value : values.get(localeKey)) {
+                    sb.append("  ").append(value).append("\n");
                 }
             }
-            return sb.toString();
-        } else {
-            return JsonUtil.serializeMap(values);
         }
+        return sb.toString();
     }
 
 }

+ 7 - 11
pwm/servlet/src/password/pwm/config/value/LocalizedStringValue.java

@@ -108,18 +108,14 @@ public class LocalizedStringValue extends AbstractValue implements StoredValue {
     }
 
     @Override
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && value != null && !value.isEmpty()) {
-            final StringBuilder sb = new StringBuilder();
-            for (final String localeKey : value.keySet()) {
-                if (value.size() > 1) {
-                    sb.append("Locale: ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append("\n");
-                }
-                sb.append(" ").append(value.get(localeKey)).append("\n");
+    public String toDebugString(Locale locale) {
+        final StringBuilder sb = new StringBuilder();
+        for (final String localeKey : value.keySet()) {
+            if (value.size() > 1) {
+                sb.append("Locale: ").append(LocaleHelper.debugLabel(LocaleHelper.parseLocaleString(localeKey))).append("\n");
             }
-            return sb.toString();
-        } else {
-            return JsonUtil.serializeMap(value);
+            sb.append(" ").append(value.get(localeKey)).append("\n");
         }
+        return sb.toString();
     }
 }

+ 7 - 11
pwm/servlet/src/password/pwm/config/value/OptionListValue.java

@@ -90,18 +90,14 @@ public class OptionListValue extends AbstractValue  implements StoredValue {
         return Collections.emptyList();
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
-            final StringBuilder sb = new StringBuilder();
-            for (Iterator valueIterator = values.iterator() ; valueIterator.hasNext();) {
-                sb.append(valueIterator.next());
-                if (valueIterator.hasNext()) {
-                    sb.append("\n");
-                }
+    public String toDebugString(Locale locale) {
+        final StringBuilder sb = new StringBuilder();
+        for (Iterator valueIterator = values.iterator() ; valueIterator.hasNext();) {
+            sb.append(valueIterator.next());
+            if (valueIterator.hasNext()) {
+                sb.append("\n");
             }
-            return sb.toString();
-        } else {
-            return JsonUtil.serializeCollection(values);
         }
+        return sb.toString();
     }
 }

+ 16 - 8
pwm/servlet/src/password/pwm/config/value/PasswordValue.java

@@ -32,9 +32,11 @@ import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.JsonUtil;
 import password.pwm.util.PasswordData;
-import password.pwm.util.SecureHelper;
+import password.pwm.util.secure.PwmBlockAlgorithm;
+import password.pwm.util.secure.PwmSecurityKey;
+import password.pwm.util.secure.SecureHelper;
 
-import javax.crypto.SecretKey;
+import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.security.NoSuchAlgorithmException;
 import java.util.Collections;
@@ -95,8 +97,8 @@ public class PasswordValue implements StoredValue {
                     newPasswordValue.requiresStoredUpdate = true;
                 } else {
                     try {
-                        final SecretKey secretKey = SecureHelper.makeKey(key);
-                        newPasswordValue.value = new PasswordData(SecureHelper.decryptStringValue(rawValue, secretKey, false, SecureHelper.BlockAlgorithm.CONFIG));
+                        final PwmSecurityKey secretKey = new PwmSecurityKey(key);
+                        newPasswordValue.value = new PasswordData(SecureHelper.decryptStringValue(rawValue, secretKey, PwmBlockAlgorithm.CONFIG));
                         return newPasswordValue;
                     } catch (Exception e) {
                         final String errorMsg = "unable to decode encrypted password value for setting: " + e.getMessage();
@@ -151,15 +153,21 @@ public class PasswordValue implements StoredValue {
         return PwmConstants.LOG_REMOVED_VALUE_REPLACEMENT;
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
+    @Override
+    public String toDebugString(Locale locale) {
+        return PwmConstants.LOG_REMOVED_VALUE_REPLACEMENT;
+    }
+
+    @Override
+    public Serializable toDebugJsonObject(Locale locale) {
         return PwmConstants.LOG_REMOVED_VALUE_REPLACEMENT;
     }
 
     private static String encryptValue(final String key, final String value)
             throws PwmUnrecoverableException, UnsupportedEncodingException, NoSuchAlgorithmException
     {
-        final SecretKey secretKey = SecureHelper.makeKey(key);
-        return SecureHelper.encryptToString(value, secretKey, false, SecureHelper.BlockAlgorithm.CONFIG);
+        final PwmSecurityKey secretKey = new PwmSecurityKey(key);
+        return SecureHelper.encryptToString(value, secretKey, PwmBlockAlgorithm.CONFIG);
     }
 
     public boolean requiresStoredUpdate()
@@ -169,6 +177,6 @@ public class PasswordValue implements StoredValue {
 
     @Override
     public String valueHash() throws PwmUnrecoverableException {
-        return value == null ? "" : SecureHelper.hash(JsonUtil.serialize(value.getStringValue()));
+        return value == null ? "" : SecureHelper.hash(JsonUtil.serialize(value.getStringValue()), PwmConstants.SETTING_CHECKSUM_HASH_METHOD);
     }
 }

+ 4 - 4
pwm/servlet/src/password/pwm/config/value/StringArrayValue.java

@@ -94,7 +94,7 @@ public class StringArrayValue extends AbstractValue implements StoredValue {
         final Pattern pattern = pwmSetting.getRegExPattern();
         for (final String loopValue : values) {
             final Matcher matcher = pattern.matcher(loopValue);
-            if (loopValue != null && loopValue.length() > 0 && !matcher.matches()) {
+            if (loopValue.length() > 0 && !matcher.matches()) {
                 return Collections.singletonList("incorrect value format for value '" + loopValue + "'");
             }
         }
@@ -102,8 +102,8 @@ public class StringArrayValue extends AbstractValue implements StoredValue {
         return Collections.emptyList();
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
+    public String toDebugString(Locale locale) {
+        if (values != null && !values.isEmpty()) {
             final StringBuilder sb = new StringBuilder();
             for (Iterator valueIterator = values.iterator() ; valueIterator.hasNext();) {
                 sb.append(valueIterator.next());
@@ -113,7 +113,7 @@ public class StringArrayValue extends AbstractValue implements StoredValue {
             }
             return sb.toString();
         } else {
-            return JsonUtil.serializeCollection(values);
+            return "";
         }
     }
 }

+ 0 - 1
pwm/servlet/src/password/pwm/config/value/StringValue.java

@@ -91,7 +91,6 @@ public class StringValue extends AbstractValue implements StoredValue {
 
     @Override
     public String toDebugString(
-            boolean prettyFormat,
             Locale locale
     )
     {

+ 3 - 3
pwm/servlet/src/password/pwm/config/value/UserPermissionValue.java

@@ -141,8 +141,8 @@ public class UserPermissionValue extends AbstractValue implements StoredValue {
         return 2;
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat && values != null && !values.isEmpty()) {
+    public String toDebugString(Locale locale) {
+        if (values != null && !values.isEmpty()) {
             final StringBuilder sb = new StringBuilder();
             int counter = 0;
             for (final UserPermission userPermission : values) {
@@ -174,7 +174,7 @@ public class UserPermissionValue extends AbstractValue implements StoredValue {
             }
             return sb.toString();
         } else {
-            return JsonUtil.serializeCollection(values);
+            return null;
         }
     }
 }

+ 2 - 5
pwm/servlet/src/password/pwm/config/value/VerificationMethodValue.java

@@ -112,19 +112,16 @@ public class VerificationMethodValue extends AbstractValue implements StoredValu
     }
 
     @Override
-    public String toDebugString(boolean prettyFormat, Locale locale) {
+    public String toDebugString(Locale locale) {
         if (value == null) {
             return "No Verification Methods";
         }
-        if (!prettyFormat) {
-            return super.toDebugString(prettyFormat, locale);
-        }
         final StringBuilder out = new StringBuilder();
         for (final RecoveryVerificationMethods method : value.getMethodSettings().keySet()) {
             out.append(" ").append(method.toString()).append(": ").append(value.getMethodSettings().get(method).getEnabledState());
             out.append("\n");
         }
-        out.append("  Minimum Optional Methods Required: " + value.getMinOptionalRequired());
+        out.append("  Minimum Optional Methods Required: ").append(value.getMinOptionalRequired());
         return out.toString();
     }
 }

+ 17 - 14
pwm/servlet/src/password/pwm/config/value/X509CertificateValue.java

@@ -23,16 +23,18 @@
 package password.pwm.config.value;
 
 import org.jdom2.Element;
+import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.StoredValue;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.StringUtil;
 import password.pwm.util.X509Utils;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.ByteArrayInputStream;
+import java.io.Serializable;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
@@ -111,8 +113,7 @@ public class X509CertificateValue extends AbstractValue implements StoredValue {
         return Collections.emptyList();
     }
 
-    public String toDebugString(boolean prettyFormat, Locale locale) {
-        if (prettyFormat) {
+    public String toDebugString(Locale locale) {
             final StringBuilder sb = new StringBuilder();
             int counter = 0;
             for (X509Certificate cert : certificates) {
@@ -120,21 +121,23 @@ public class X509CertificateValue extends AbstractValue implements StoredValue {
                 sb.append(" Subject: ").append(cert.getSubjectDN().toString()).append("\n");
                 sb.append(" Serial: ").append(X509Utils.hexSerial(cert)).append("\n");
                 sb.append(" Issuer: ").append(cert.getIssuerDN().toString()).append("\n");
-                sb.append(" IssueDate: ").append(cert.getNotBefore().toString()).append("\n");
-                sb.append(" ExpireDate: ").append(cert.getNotAfter().toString()).append("\n");
+                sb.append(" IssueDate: ").append(PwmConstants.DEFAULT_DATETIME_FORMAT.format(cert.getNotBefore())).append("\n");
+                sb.append(" ExpireDate: ").append(PwmConstants.DEFAULT_DATETIME_FORMAT.format(cert.getNotAfter())).append("\n");
                 try {
                     sb.append(" MD5 Hash: ").append(SecureHelper.hash(new ByteArrayInputStream(cert.getEncoded()),
-                            SecureHelper.HashAlgorithm.MD5)).append("\n");
+                            PwmHashAlgorithm.MD5)).append("\n");
                     sb.append(" SHA1 Hash: ").append(SecureHelper.hash(new ByteArrayInputStream(cert.getEncoded()),
-                            SecureHelper.HashAlgorithm.SHA1)).append("\n");
+                            PwmHashAlgorithm.SHA1)).append("\n");
                 } catch (PwmUnrecoverableException | CertificateEncodingException e) {
                     LOGGER.warn("error generating hash for certificate: " + e.getMessage());
                 }
             }
             return sb.toString();
-        } else {
-            return JsonUtil.serializeCollection(this.toInfoMap(false));
-        }
+    }
+
+    @Override
+    public Serializable toDebugJsonObject(Locale locale) {
+        return (Serializable)toInfoMap(false);
     }
 
     public List<Map<String,Object>> toInfoMap(final boolean includeDetail) {
@@ -158,11 +161,11 @@ public class X509CertificateValue extends AbstractValue implements StoredValue {
         map.put("expireDate",cert.getNotAfter());
         try {
             map.put("md5Hash", SecureHelper.hash(new ByteArrayInputStream(cert.getEncoded()),
-                    SecureHelper.HashAlgorithm.MD5));
+                    PwmHashAlgorithm.MD5));
             map.put("sha1Hash", SecureHelper.hash(new ByteArrayInputStream(cert.getEncoded()),
-                    SecureHelper.HashAlgorithm.SHA1));
+                    PwmHashAlgorithm.SHA1));
             map.put("sha512Hash", SecureHelper.hash(new ByteArrayInputStream(cert.getEncoded()),
-                    SecureHelper.HashAlgorithm.SHA512));
+                    PwmHashAlgorithm.SHA512));
             if (includeDetail) {
                 map.put("detail",X509Utils.makeDetailText(cert));
             }

+ 1 - 1
pwm/servlet/src/password/pwm/http/ContextManager.java

@@ -33,8 +33,8 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.Helper;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;

+ 5 - 2
pwm/servlet/src/password/pwm/http/PwmRequest.java

@@ -39,8 +39,11 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.Message;
-import password.pwm.util.*;
+import password.pwm.util.Helper;
+import password.pwm.util.JsonUtil;
+import password.pwm.util.ServletHelper;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.ws.server.RestResultBean;
 
 import javax.servlet.ServletException;
@@ -541,7 +544,7 @@ public class PwmRequest extends PwmHttpRequestWrapper implements Serializable {
         final String strValue = this.readCookie(cookieName);
 
         if (strValue != null && !strValue.isEmpty()) {
-            final String decryptedCookie = SecureHelper.decryptStringValue(strValue, getConfig().getSecurityKey(), true);
+            final String decryptedCookie = pwmApplication.getSecureService().decryptStringValue(strValue);
             return JsonUtil.deserialize(decryptedCookie, returnClass);
         }
         

+ 2 - 3
pwm/servlet/src/password/pwm/http/PwmResponse.java

@@ -31,7 +31,6 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.i18n.Message;
 import password.pwm.util.Helper;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.ws.server.RestResultBean;
 
@@ -131,7 +130,7 @@ public class PwmResponse extends PwmHttpResponseWrapper {
             throws PwmUnrecoverableException
     {
         final String jsonValue = JsonUtil.serialize(cookieValue);
-        final String encryptedValue = SecureHelper.encryptToString(jsonValue, pwmRequest.getConfig().getSecurityKey(), true);
+        final String encryptedValue = pwmRequest.getPwmApplication().getSecureService().encryptToString(jsonValue);
         pwmRequest.getPwmResponse().writeCookie(cookieName, encryptedValue, -1, true, path);
     }
 
@@ -139,7 +138,7 @@ public class PwmResponse extends PwmHttpResponseWrapper {
             throws PwmUnrecoverableException
     {
         final String jsonValue = JsonUtil.serialize(cookieValue);
-        final String encryptedValue = SecureHelper.encryptToString(jsonValue, pwmRequest.getConfig().getSecurityKey(), true);
+        final String encryptedValue = pwmRequest.getPwmApplication().getSecureService().encryptToString(jsonValue);
         pwmRequest.getPwmResponse().writeCookie(cookieName, encryptedValue, seconds, httpOnly, path);
     }
 

+ 1 - 1
pwm/servlet/src/password/pwm/http/PwmSession.java

@@ -37,9 +37,9 @@ import password.pwm.http.bean.*;
 import password.pwm.i18n.LocaleHelper;
 import password.pwm.ldap.UserStatusReader;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 

+ 1 - 1
pwm/servlet/src/password/pwm/http/SessionManager.java

@@ -44,9 +44,9 @@ import password.pwm.ldap.LdapUserDataReader;
 import password.pwm.ldap.UserDataReader;
 import password.pwm.util.Helper;
 import password.pwm.util.PasswordData;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
+import password.pwm.util.secure.PwmRandom;
 
 import java.io.Serializable;
 import java.util.List;

+ 33 - 13
pwm/servlet/src/password/pwm/http/servlet/ChangePasswordServlet.java

@@ -372,16 +372,10 @@ public class ChangePasswordServlet extends PwmServlet {
             return;
         }
 
-        if (pwmSession.getUserInfoBean().getPasswordState().isWarnPeriod()) {
-            if (!pwmRequest.getPwmSession().getSessionStateBean().isSkippedRequireNewPassword()) {
-                if (!changePasswordBean.isWarnPassed()) {
-                    if (pwmRequest.getPwmSession().getLoginInfoBean().getAuthenticationType() != AuthenticationType.AUTH_FROM_PUBLIC_MODULE) {
-                        LOGGER.trace(pwmRequest, "pasword expiration is within password warn period, forwarding user to warning page");
-                        pwmRequest.forwardToJsp(PwmConstants.JSP_URL.PASSWORD_WARN);
-                        return;
-                    }
-                }
-            }
+        if (warnPageShouldBeShown(pwmRequest, changePasswordBean)) {
+            LOGGER.trace(pwmRequest, "pasword expiration is within password warn period, forwarding user to warning page");
+            pwmRequest.forwardToJsp(PwmConstants.JSP_URL.PASSWORD_WARN);
+            return;
         }
 
         final String agreementMsg = pwmApplication.getConfig().readSettingAsLocalizedString(PwmSetting.PASSWORD_CHANGE_AGREEMENT_MESSAGE, pwmRequest.getLocale());
@@ -640,9 +634,35 @@ public class ChangePasswordServlet extends PwmServlet {
             pwmRequest.forwardToJsp(PwmConstants.JSP_URL.PASSWORD_CHANGE_WAIT);
         }
     }
-    
-    protected void forwardToFormPage(final PwmRequest pwmRequest) 
-            throws ServletException, PwmUnrecoverableException, IOException 
+
+    private boolean warnPageShouldBeShown(final PwmRequest pwmRequest, final ChangePasswordBean changePasswordBean) {
+        final PwmSession pwmSession = pwmRequest.getPwmSession();
+
+        if (pwmSession.getUserInfoBean().isRequiresNewPassword()) {
+            return false;
+        }
+
+        if (!pwmSession.getUserInfoBean().getPasswordState().isWarnPeriod()) {
+            return false;
+        }
+
+        if (pwmRequest.getPwmSession().getSessionStateBean().isSkippedRequireNewPassword()) {
+            return false;
+        }
+
+        if (changePasswordBean.isWarnPassed()) {
+            return false;
+        }
+
+        if (pwmRequest.getPwmSession().getLoginInfoBean().getAuthenticationType() == AuthenticationType.AUTH_FROM_PUBLIC_MODULE) {
+            return false;
+        }
+
+        return true;
+    }
+
+    protected void forwardToFormPage(final PwmRequest pwmRequest)
+            throws ServletException, PwmUnrecoverableException, IOException
     {
         pwmRequest.addFormInfoToRequestAttr(PwmSetting.PASSWORD_REQUIRE_FORM,false,false);
         pwmRequest.forwardToJsp(PwmConstants.JSP_URL.PASSWORD_FORM);

+ 1 - 1
pwm/servlet/src/password/pwm/http/servlet/ConfigEditorServlet.java

@@ -581,7 +581,7 @@ public class ConfigEditorServlet extends PwmServlet {
                     final PwmSetting setting = (PwmSetting) recordID.getRecordID();
                     final LinkedHashMap<String, Object> settingData = new LinkedHashMap<>();
                     settingData.put("category", setting.getCategory().toString());
-                    settingData.put("value", configManagerBean.getStoredConfiguration().readSetting(setting, recordID.getProfileID()).toDebugString(true, pwmRequest.getLocale()));
+                    settingData.put("value", configManagerBean.getStoredConfiguration().readSetting(setting, recordID.getProfileID()).toDebugString(pwmRequest.getLocale()));
                     settingData.put("navigation", setting.getCategory().toMenuLocationDebug(recordID.getProfileID(), locale));
                     settingData.put("default", configManagerBean.getStoredConfiguration().isDefaultValue(setting, recordID.getProfileID()));
                     settingData.put("profile",recordID.getProfileID());

+ 10 - 10
pwm/servlet/src/password/pwm/http/servlet/ConfigManagerServlet.java

@@ -51,9 +51,11 @@ import password.pwm.util.logging.LocalDBLogger;
 import password.pwm.util.logging.PwmLogEvent;
 import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.PwmSecurityKey;
+import password.pwm.util.secure.SecureHelper;
 import password.pwm.ws.server.RestResultBean;
 
-import javax.crypto.SecretKey;
 import javax.servlet.ServletException;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
@@ -106,7 +108,6 @@ public class ConfigManagerServlet extends PwmServlet {
     protected void processAction(final PwmRequest pwmRequest)
             throws ServletException, IOException, ChaiUnavailableException, PwmUnrecoverableException
     {
-        final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
         final PwmSession pwmSession = pwmRequest.getPwmSession();
         final ConfigManagerBean configManagerBean = pwmSession.getConfigManagerBean();
 
@@ -283,18 +284,18 @@ public class ConfigManagerServlet extends PwmServlet {
             LOGGER.debug(pwmRequest, "security not available, persistent login not possible.");
         } else {
             persistentLoginEnabled = true;
-            final SecretKey securityKey = pwmRequest.getConfig().getSecurityKey();
+            final PwmSecurityKey securityKey = pwmRequest.getConfig().getSecurityKey();
 
             if (PwmApplication.MODE.RUNNING == pwmRequest.getPwmApplication().getApplicationMode()) {
                 persistentLoginValue = SecureHelper.hash(
                         storedConfig.readConfigProperty(StoredConfiguration.ConfigProperty.PROPERTY_KEY_PASSWORD_HASH)
                                 + pwmSession.getUserInfoBean().getUserIdentity().toDelimitedKey(),
-                        SecureHelper.DEFAULT_HASH_ALGORITHM);
+                        PwmHashAlgorithm.SHA512);
 
             } else {
                 persistentLoginValue = SecureHelper.hash(
                         storedConfig.readConfigProperty(StoredConfiguration.ConfigProperty.PROPERTY_KEY_PASSWORD_HASH),
-                        SecureHelper.DEFAULT_HASH_ALGORITHM);
+                        PwmHashAlgorithm.SHA512);
             }
 
             {
@@ -304,7 +305,7 @@ public class ConfigManagerServlet extends PwmServlet {
                 );
                 if (securityKey != null && cookieStr != null && !cookieStr.isEmpty()) {
                     try {
-                        final String jsonStr = SecureHelper.decryptStringValue(cookieStr, securityKey);
+                        final String jsonStr = pwmApplication.getSecureService().decryptStringValue(cookieStr);
                         final PersistentLoginInfo persistentLoginInfo = JsonUtil.deserialize(jsonStr, PersistentLoginInfo.class);
                         if (persistentLoginInfo != null && persistentLoginValue != null) {
                             if (persistentLoginInfo.getExpireDate().after(new Date())) {
@@ -358,8 +359,7 @@ public class ConfigManagerServlet extends PwmServlet {
                     final Date expirationDate = new Date(System.currentTimeMillis() + (persistentSeconds * 1000));
                     final PersistentLoginInfo persistentLoginInfo = new PersistentLoginInfo(expirationDate, persistentLoginValue);
                     final String jsonPersistentLoginInfo = JsonUtil.serialize(persistentLoginInfo);
-                    final String cookieValue = SecureHelper.encryptToString(jsonPersistentLoginInfo,
-                            pwmRequest.getConfig().getSecurityKey());
+                    final String cookieValue = pwmApplication.getSecureService().encryptToString(jsonPersistentLoginInfo);
                     pwmRequest.getPwmResponse().writeCookie(
                             PwmConstants.COOKIE_PERSISTENT_CONFIG_LOGIN,
                             cookieValue,
@@ -670,8 +670,8 @@ public class ConfigManagerServlet extends PwmServlet {
         {
             final StoredConfiguration storedConfiguration = readCurrentConfiguration(pwmRequest);
             storedConfiguration.resetAllPasswordValues("value removed from " + PwmConstants.PWM_APP_NAME + "-Support configuration export");
-
-            outputStream.write(storedConfiguration.toString(true).getBytes(PwmConstants.DEFAULT_CHARSET));
+            final String jsonOutput = JsonUtil.serialize(storedConfiguration.toJsonDebugObject(), JsonUtil.Flag.PrettyPrint);
+            outputStream.write(jsonOutput.getBytes(PwmConstants.DEFAULT_CHARSET));
         }
     }
 

+ 5 - 1
pwm/servlet/src/password/pwm/http/servlet/ForgottenPasswordServlet.java

@@ -62,7 +62,10 @@ import password.pwm.ldap.auth.AuthenticationUtility;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.token.TokenPayload;
 import password.pwm.token.TokenService;
-import password.pwm.util.*;
+import password.pwm.util.JsonUtil;
+import password.pwm.util.PasswordData;
+import password.pwm.util.PostChangePasswordAction;
+import password.pwm.util.RandomPasswordGenerator;
 import password.pwm.util.intruder.RecordType;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
@@ -71,6 +74,7 @@ import password.pwm.util.operations.OtpService;
 import password.pwm.util.operations.PasswordUtility;
 import password.pwm.util.operations.cr.NMASCrOperator;
 import password.pwm.util.otp.OTPUserRecord;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 import password.pwm.ws.client.rest.RestTokenDataClient;

+ 3 - 6
pwm/servlet/src/password/pwm/http/servlet/NewUserServlet.java

@@ -1128,8 +1128,7 @@ public class NewUserServlet extends PwmServlet {
             final PasswordData passwordData;
             if (payloadMap.containsKey(FIELD_PASSWORD1)) {
                 final String rawPassword = payloadMap.get(FIELD_PASSWORD1);
-                final String realPassword = SecureHelper.decryptStringValue(rawPassword,
-                        pwmRequest.getConfig().getSecurityKey(), true);
+                final String realPassword = pwmRequest.getPwmApplication().getSecureService().decryptStringValue(rawPassword);
                 passwordData = new PasswordData(realPassword);
             } else {
                 passwordData = null;
@@ -1147,10 +1146,8 @@ public class NewUserServlet extends PwmServlet {
             final Map<String, String> payloadMap = new LinkedHashMap<>();
             payloadMap.put(TOKEN_PAYLOAD_ATTR, pwmRequest.getPwmSession().getNewUserBean().getProfileID());
             payloadMap.putAll(FormUtility.asStringMap(newUserForm.getFormData()));
-            final String encryptedPassword = SecureHelper.encryptToString(
-                    newUserForm.getNewUserPassword().getStringValue(),
-                    pwmRequest.getConfig().getSecurityKey(),
-                    true
+            final String encryptedPassword = pwmRequest.getPwmApplication().getSecureService().encryptToString(
+                    newUserForm.getNewUserPassword().getStringValue()
             );
             payloadMap.put(FIELD_PASSWORD1, encryptedPassword);
             return payloadMap;

+ 2 - 2
pwm/servlet/src/password/pwm/http/servlet/OAuthConsumerServlet.java

@@ -572,7 +572,7 @@ public class OAuthConsumerServlet extends PwmServlet {
 
 
         final String jsonValue = JsonUtil.serialize(oAuthState);
-        return SecureHelper.encryptToString(jsonValue, pwmRequest.getConfig().getSecurityKey(), true);
+        return pwmRequest.getPwmApplication().getSecureService().encryptToString(jsonValue);
     }
 
     public static class OAuthRequestState {
@@ -629,7 +629,7 @@ public class OAuthConsumerServlet extends PwmServlet {
     {
         final String requestStateStr = pwmRequest.readParameterAsString(pwmRequest.getConfig().readAppProperty(AppProperty.HTTP_PARAM_OAUTH_STATE));
         if (requestStateStr != null) {
-            final String stateJson = SecureHelper.decryptStringValue(requestStateStr, pwmRequest.getConfig().getSecurityKey(), true);
+            final String stateJson = pwmRequest.getPwmApplication().getSecureService().decryptStringValue(requestStateStr);
             final OAuthState oAuthState = JsonUtil.deserialize(stateJson, OAuthState.class);
             if (oAuthState != null) {
                 final boolean sessionMatch = oAuthState.sessionID.equals(pwmRequest.getPwmSession().getSessionStateBean().getSessionVerificationKey());

+ 15 - 13
pwm/servlet/src/password/pwm/http/servlet/helpdesk/HelpdeskServlet.java

@@ -232,7 +232,7 @@ public class HelpdeskServlet extends PwmServlet {
             pwmRequest.respondWithError(errorInformation, false);
             return;
         }
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
         LOGGER.debug(pwmRequest, "received executeAction request for user " + userIdentity.toString());
 
         final List<ActionConfiguration> actionConfigurations = helpdeskProfile.readSettingAsAction(PwmSetting.HELPDESK_ACTIONS);
@@ -310,7 +310,7 @@ public class HelpdeskServlet extends PwmServlet {
             return;
         }
 
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmApplication.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmApplication);
         LOGGER.info(pwmSession, "received deleteUser request by " + pwmSession.getUserInfoBean().getUserIdentity().toString() + " for user " + userIdentity.toString());
 
         // check if user should be seen by actor
@@ -364,7 +364,7 @@ public class HelpdeskServlet extends PwmServlet {
             return;
         }
 
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig()).canonicalized(pwmRequest.getPwmApplication());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication()).canonicalized(pwmRequest.getPwmApplication());
         processDetailRequest(pwmRequest, helpdeskProfile, userIdentity);
         final HelpdeskAuditRecord auditRecord = pwmRequest.getPwmApplication().getAuditManager().createHelpdeskAuditRecord(
                 AuditEvent.HELPDESK_VIEW_DETAIL,
@@ -401,7 +401,7 @@ public class HelpdeskServlet extends PwmServlet {
         pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.HelpdeskDetail, helpdeskDetailInfoBean);
 
         if (helpdeskDetailInfoBean != null && helpdeskDetailInfoBean.getUserInfoBean() != null) {
-            final String obfuscatedDN = helpdeskDetailInfoBean.getUserInfoBean().getUserIdentity().toObfuscatedKey(pwmRequest.getConfig());
+            final String obfuscatedDN = helpdeskDetailInfoBean.getUserInfoBean().getUserIdentity().toObfuscatedKey(pwmRequest.getPwmApplication());
             pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.HelpdeskObfuscatedDN, obfuscatedDN);
             pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.HelpdeskUsername, helpdeskDetailInfoBean.getUserInfoBean().getUsername());
         }
@@ -571,7 +571,7 @@ public class HelpdeskServlet extends PwmServlet {
             pwmRequest.respondWithError(errorInformation, false);
             return;
         }
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
 
         if (!helpdeskProfile.readSettingAsBoolean(PwmSetting.HELPDESK_ENABLE_UNLOCK)) {
             final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNAUTHORIZED, "password unlock request, but helpdesk unlock is not enabled");
@@ -639,7 +639,7 @@ public class HelpdeskServlet extends PwmServlet {
             pwmRequest.respondWithError(errorInformation, false);
             return;
         }
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
 
         if (!helpdeskProfile.readSettingAsBoolean(PwmSetting.HELPDESK_ENABLE_OTP_VERIFY)) {
             final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UNAUTHORIZED, "password unlock request, but helpdesk otp verify is not enabled");
@@ -724,19 +724,22 @@ public class HelpdeskServlet extends PwmServlet {
             pwmRequest.respondWithError(errorInformation, false);
             return;
         }
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
 
 
         final HelpdeskDetailInfoBean helpdeskDetailInfoBean = makeHelpdeskDetailInfo(pwmRequest, helpdeskProfile, userIdentity);
         final UserInfoBean userInfoBean = helpdeskDetailInfoBean.getUserInfoBean();
-        final MacroMachine macroMachine = MacroMachine.forNonUserSpecific(pwmRequest.getPwmApplication(), pwmRequest.getSessionLabel());
+        final UserDataReader userDataReader = LdapUserDataReader.appProxiedReader(pwmRequest.getPwmApplication(), userIdentity);
+        final MacroMachine macroMachine = new MacroMachine(pwmRequest.getPwmApplication(), pwmRequest.getSessionLabel(), userInfoBean, null, userDataReader);
         final String configuredTokenString = config.readAppProperty(AppProperty.HELPDESK_TOKEN_VALUE);
         final String tokenKey = macroMachine.expandMacros(configuredTokenString);
+        final EmailItemBean emailItemBean = config.readSettingAsEmail(PwmSetting.EMAIL_HELPDESK_TOKEN, pwmRequest.getLocale());
 
+        final String destEmailAddress = macroMachine.expandMacros(emailItemBean.getTo());
         final StringBuilder destDisplayString = new StringBuilder();
-        if (userInfoBean.getUserEmailAddress() != null && !userInfoBean.getUserEmailAddress().isEmpty()) {
+        if (destEmailAddress != null && !destEmailAddress.isEmpty()) {
             if (tokenSendMethod == MessageSendMethod.BOTH || tokenSendMethod == MessageSendMethod.EMAILFIRST || tokenSendMethod == MessageSendMethod.EMAILONLY) {
-                destDisplayString.append(userInfoBean.getUserEmailAddress());
+                destDisplayString.append(destEmailAddress);
             }
         }
         if (userInfoBean.getUserSmsNumber() != null && !userInfoBean.getUserSmsNumber().isEmpty()) {
@@ -750,7 +753,6 @@ public class HelpdeskServlet extends PwmServlet {
 
         LOGGER.debug(pwmRequest, "generated token code for " + userIdentity.toDelimitedKey());
 
-        final EmailItemBean emailItemBean = config.readSettingAsEmail(PwmSetting.EMAIL_HELPDESK_TOKEN, pwmRequest.getLocale());
         final String smsMessage = config.readSettingAsLocalizedString(PwmSetting.SMS_HELPDESK_TOKEN_TEXT, pwmRequest.getLocale());
 
         try {
@@ -760,7 +762,7 @@ public class HelpdeskServlet extends PwmServlet {
                     macroMachine,
                     emailItemBean,
                     tokenSendMethod,
-                    userInfoBean.getUserEmailAddress(),
+                    destEmailAddress,
                     userInfoBean.getUserSmsNumber(),
                     smsMessage,
                     tokenKey
@@ -792,7 +794,7 @@ public class HelpdeskServlet extends PwmServlet {
             pwmRequest.respondWithError(errorInformation, false);
             return;
         }
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
 
         if (!helpdeskProfile.readSettingAsBoolean(PwmSetting.HELPDESK_CLEAR_OTP_BUTTON)) {
             final String errorMsg = "clear otp request, but helpdesk clear otp button is not enabled";

+ 11 - 11
pwm/servlet/src/password/pwm/http/servlet/peoplesearch/PeopleSearchServlet.java

@@ -40,7 +40,6 @@ import password.pwm.http.PwmRequest;
 import password.pwm.http.servlet.PwmServlet;
 import password.pwm.ldap.*;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.cache.CacheKey;
 import password.pwm.util.cache.CachePolicy;
@@ -315,7 +314,7 @@ public class PeopleSearchServlet extends PwmServlet {
             return;
         }
         final boolean asParent = Boolean.parseBoolean(requestInputMap.get("asParent"));
-        final UserIdentity userIdentity = UserIdentity.fromObfuscatedKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromObfuscatedKey(userKey, pwmRequest.getPwmApplication());
 
         final UserIdentity parentIdentity;
         try {
@@ -323,7 +322,7 @@ public class PeopleSearchServlet extends PwmServlet {
                 parentIdentity = userIdentity;
             } else {
                 final UserDetailBean userDetailBean = makeUserDetailRequestImpl(pwmRequest, peopleSearchConfiguration, userKey);
-                parentIdentity = UserIdentity.fromObfuscatedKey(userDetailBean.getOrgChartParentKey(), pwmRequest.getConfig());
+                parentIdentity = UserIdentity.fromObfuscatedKey(userDetailBean.getOrgChartParentKey(), pwmRequest.getPwmApplication());
             }
 
             final OrgChartData orgChartData = makeOrgChartData(pwmRequest, parentIdentity);
@@ -421,7 +420,7 @@ public class PeopleSearchServlet extends PwmServlet {
             throws PwmUnrecoverableException, IOException, ServletException, PwmOperationalException, ChaiUnavailableException
     {
         final Date startTime = new Date();
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
 
         final CacheKey cacheKey = makeCacheKey(pwmRequest, "detail", userIdentity.toDelimitedKey());
         {
@@ -465,14 +464,14 @@ public class PeopleSearchServlet extends PwmServlet {
             if (parentDN != null && !parentDN.isEmpty()) {
                 userDetailBean.setHasOrgChart(true);
                 final UserIdentity parentIdentity = new UserIdentity(parentDN,userIdentity.getLdapProfileID());
-                userDetailBean.setOrgChartParentKey(parentIdentity.toObfuscatedKey(pwmRequest.getConfig()));
+                userDetailBean.setOrgChartParentKey(parentIdentity.toObfuscatedKey(pwmRequest.getPwmApplication()));
             } else {
                 final String childAttr = pwmRequest.getConfig().readSettingAsString(PwmSetting.PEOPLE_SEARCH_ORGCHART_CHILD_ATTRIBUTE);
                 final String childDN = searchResults.get(childAttr);
                 if (childDN != null && !childDN.isEmpty()) {
                     userDetailBean.setHasOrgChart(true);
                     // no parent so use self as parent.
-                    userDetailBean.setOrgChartParentKey(userIdentity.toObfuscatedKey(pwmRequest.getConfig()));
+                    userDetailBean.setOrgChartParentKey(userIdentity.toObfuscatedKey(pwmRequest.getPwmApplication()));
                 }
             }
         }
@@ -526,7 +525,7 @@ public class PeopleSearchServlet extends PwmServlet {
             throw PwmUnrecoverableException.fromChaiException(e);
         }
 
-        return "PeopleSearch?processAction=photo&userKey=" + userIdentity.toObfuscatedKey(pwmApplication.getConfig());
+        return "PeopleSearch?processAction=photo&userKey=" + userIdentity.toObfuscatedKey(pwmApplication);
     }
 
     private static String figureDisplaynameValue(
@@ -571,7 +570,7 @@ public class PeopleSearchServlet extends PwmServlet {
         }
 
 
-        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getConfig());
+        final UserIdentity userIdentity = UserIdentity.fromKey(userKey, pwmRequest.getPwmApplication());
         try {
             checkIfUserIdentityViewable(pwmRequest, userIdentity);
         } catch (PwmOperationalException e) {
@@ -639,7 +638,7 @@ public class PeopleSearchServlet extends PwmServlet {
                         for (final UserIdentity loopIdentity : identityValues) {
                             final String displayValue = figureDisplaynameValue(pwmRequest, loopIdentity);
                             final UserReferenceBean userReference = new UserReferenceBean();
-                            userReference.setUserKey(loopIdentity.toObfuscatedKey(pwmRequest.getConfig()));
+                            userReference.setUserKey(loopIdentity.toObfuscatedKey(pwmRequest.getPwmApplication()));
                             userReference.setDisplayName(displayValue);
                             userReferences.put(displayValue, userReference);
                         }
@@ -777,7 +776,7 @@ public class PeopleSearchServlet extends PwmServlet {
             throws PwmUnrecoverableException
     {
         final OrgChartReferenceBean orgChartReferenceBean = new OrgChartReferenceBean();
-        orgChartReferenceBean.setUserKey(userIdentity.toObfuscatedKey(pwmRequest.getConfig()));
+        orgChartReferenceBean.setUserKey(userIdentity.toObfuscatedKey(pwmRequest.getPwmApplication()));
         orgChartReferenceBean.setPhotoURL(figurePhotoURL(pwmRequest, userIdentity));
 
             final List<String> displayLabels = figureDisplaynames(pwmRequest, userIdentity);
@@ -852,10 +851,11 @@ public class PeopleSearchServlet extends PwmServlet {
         } else {
             userIdentity = null;
         }
+        final String keyString = operationIdentifer + "|" + pwmRequest.getPwmApplication().getSecureService().hash(dataIdentifer);
         return CacheKey.makeCacheKey(
                 this.getClass(),
                 userIdentity,
-                operationIdentifer + "|" + SecureHelper.hash(dataIdentifer, SecureHelper.HashAlgorithm.SHA1));
+                keyString);
     }
 
     private static class PeopleSearchConfiguration {

+ 3 - 3
pwm/servlet/src/password/pwm/i18n/Config.properties

@@ -140,11 +140,11 @@ Tooltip_FormOptions_RegexError=Error message to show when the regular expression
 Tooltip_FormOptions_Placeholder=Placeholder text to display in the form field with the field is not populated with a value.
 Tooltip_FormOptions_Javascript=Javascript to be added to the browser.
 VerificationMethodDetail_PREVIOUS_AUTH=This method is passed when a user has previously authenticated using their browser.  There is no user interaction or display associated with this method.
-VerificationMethodDetail_ATTRIBUTES=User will be prompted for LDAP attribute values defined by the setting @PwmSettingReference:challenge.requiredAttributes@
+VerificationMethodDetail_ATTRIBUTES=User will be prompted for LDAP attribute values defined by the setting @PwmSettingReference:challenge.requiredAttributes@.
 VerificationMethodDetail_CHALLENGE_RESPONSES=Challenge/Response questions and answers.
 VerificationMethodDetail_TOKEN=An Email and/or SMS token is sent to the user for validation.  See @PwmSettingReference:challenge.token.sendMethod@.
-VerificationMethodDetail_OTP=TOTP authentication.  Referred to on user screens as "Mobile App Authentication".
+VerificationMethodDetail_OTP=TOTP authentication.  Referred to on user screens as Mobile App Authentication.
 VerificationMethodDetail_REMOTE_RESPONSES=Utilize a configured web service for user response verification.   See @PwmSettingReference:external.remoteResponses.url@.
-VerificationMethodDetail_NAAF=NetIQ Advanced Authentication Framework
+VerificationMethodDetail_NAAF=Use NetIQ Advanced Authentication Framework for verification.
 
 

+ 2 - 2
pwm/servlet/src/password/pwm/ldap/UserSearchEngine.java

@@ -98,7 +98,7 @@ public class UserSearchEngine {
         {
             UserIdentity inputIdentity = null;
             try {
-                inputIdentity = UserIdentity.fromKey(username, pwmApplication.getConfig());
+                inputIdentity = UserIdentity.fromKey(username, pwmApplication);
             } catch (PwmException e) { /* input is not a userIdentity */ }
 
             if (inputIdentity != null) {
@@ -625,7 +625,7 @@ public class UserSearchEngine {
                 for (final String attribute : this.getHeaderAttributeMap().keySet()) {
                     rowMap.put(attribute,this.getResults().get(userIdentity).get(attribute));
                 }
-                rowMap.put("userKey",userIdentity.toObfuscatedKey(pwmApplication.getConfig()));
+                rowMap.put("userKey",userIdentity.toObfuscatedKey(pwmApplication));
                 rowMap.put("id",idCounter);
                 outputList.add(rowMap);
                 idCounter++;

+ 7 - 6
pwm/servlet/src/password/pwm/token/TokenService.java

@@ -41,16 +41,19 @@ import password.pwm.health.HealthMessage;
 import password.pwm.health.HealthRecord;
 import password.pwm.http.PwmSession;
 import password.pwm.ldap.auth.SessionAuthenticator;
-import password.pwm.util.*;
+import password.pwm.util.Helper;
+import password.pwm.util.JsonUtil;
+import password.pwm.util.TimeDuration;
 import password.pwm.util.intruder.RecordType;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
 import password.pwm.util.operations.PasswordUtility;
+import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.secure.SecureHelper;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 
-import javax.crypto.SecretKey;
 import java.util.*;
 
 /**
@@ -75,7 +78,6 @@ public class TokenService implements PwmService {
     private long maxTokenAgeMS;
     private long maxTokenPurgeAgeMS;
     private TokenMachine tokenMachine;
-    private SecretKey secretKey;
     private long counter;
 
     private ServiceInfo serviceInfo = new ServiceInfo(Collections.<DataStorageMethod>emptyList());
@@ -128,7 +130,6 @@ public class TokenService implements PwmService {
         }
 
         try {
-            secretKey = configuration.getSecurityKey();
             DataStorageMethod usedStorageMethod = null;
             switch (storageMethod) {
                 case STORE_LOCALDB:
@@ -467,7 +468,7 @@ public class TokenService implements PwmService {
             throws PwmUnrecoverableException, PwmOperationalException
     {
         final String jsonPayload = JsonUtil.serialize(tokenPayload);
-        return SecureHelper.encryptToString(jsonPayload, secretKey, true);
+        return pwmApplication.getSecureService().encryptToString(jsonPayload);
     }
 
     TokenPayload fromEncryptedString(final String inputString)
@@ -475,7 +476,7 @@ public class TokenService implements PwmService {
     {
         final String deWhiteSpacedToken = inputString.replaceAll("\\s","");
         try {
-            final String decryptedString = SecureHelper.decryptStringValue(deWhiteSpacedToken, secretKey, true);
+            final String decryptedString = pwmApplication.getSecureService().decryptStringValue(deWhiteSpacedToken);
             return JsonUtil.deserialize(decryptedString, TokenPayload.class);
         } catch (PwmUnrecoverableException e) {
             final String errorMsg = "unable to decrypt user supplied token value: " + e.getErrorInformation().toDebugStr();

+ 3 - 1
pwm/servlet/src/password/pwm/util/BuildChecksumMaker.java

@@ -23,6 +23,8 @@
 package password.pwm.util;
 
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.*;
 import java.util.*;
@@ -146,7 +148,7 @@ public class BuildChecksumMaker {
                 file.getAbsolutePath(),
                 new Date(file.lastModified()),
                 file.length(),
-                SecureHelper.hash(file, SecureHelper.HashAlgorithm.SHA1)
+                SecureHelper.hash(file, PwmHashAlgorithm.SHA1)
         );
     }
 

+ 19 - 0
pwm/servlet/src/password/pwm/util/Helper.java

@@ -43,6 +43,7 @@ import password.pwm.i18n.Display;
 import password.pwm.i18n.LocaleHelper;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
+import password.pwm.util.secure.PwmRandom;
 
 import java.io.*;
 import java.lang.reflect.Method;
@@ -559,6 +560,9 @@ public class
             }
         }
 
+        aboutMap.put(PwmAboutProperty.app_secureBlockAlgorithm,     pwmApplication.getSecureService().getDefaultBlockAlgorithm().getLabel());
+        aboutMap.put(PwmAboutProperty.app_secureHashAlgorithm,      pwmApplication.getSecureService().getDefaultHashAlorithm().toString());
+
         aboutMap.put(PwmAboutProperty.app_wordlistSize,             Integer.toString(pwmApplication.getWordlistManager().size()));
         aboutMap.put(PwmAboutProperty.app_seedlistSize,             Integer.toString(pwmApplication.getSeedlistManager().size()));
         if (pwmApplication.getSharedHistoryManager() != null) {
@@ -644,4 +648,19 @@ public class
         throw new IllegalArgumentException("unknown scheme: " + scheme);
     }
 
+    public static <E extends Enum<E>> E readEnumFromString(Class<E> enumClass, E defaultValue, String input) {
+        if (input == null) {
+            return defaultValue;
+        }
+
+        try {
+            Method valueOfMethod = enumClass.getMethod("valueOf",String.class);
+            Object result = valueOfMethod.invoke(null,input);
+            return (E)result;
+        } catch (Exception e) {
+            LOGGER.warn("unexpected error translating input=" + input + " to enumClass=" + enumClass.getSimpleName(),e);
+        }
+
+        return defaultValue;
+    }
 }

+ 11 - 9
pwm/servlet/src/password/pwm/util/PasswordData.java

@@ -28,8 +28,10 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.logging.PwmLogger;
-
-import javax.crypto.SecretKey;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.secure.PwmSecurityKey;
+import password.pwm.util.secure.SecureHelper;
 
 /*
  * A in-memory password value wrapper.  Instances of this class cannot be serialized.  The actual password value is encrypted using a
@@ -42,21 +44,21 @@ public class PasswordData {
     private final byte[] passwordData;
     private final String keyHash; // not a secure value, used to detect if key is same over time.
 
-    private static final SecretKey staticKey;
+    private static final PwmSecurityKey staticKey;
     private static final String staticKeyHash;
     private static final ErrorInformation initializationError;
 
     private String passwordHashCache;
 
     static {
-        SecretKey newKey = null;
+        PwmSecurityKey newKey = null;
         String newKeyHash = null;
         ErrorInformation newInitializationError = null;
         try {
             final byte[] randomBytes = new byte[1024 * 10];
             PwmRandom.getInstance().nextBytes(randomBytes);
-            newKey = SecureHelper.makeKey(randomBytes);
-            newKeyHash = SecureHelper.hash(newKey.getEncoded(), SecureHelper.HashAlgorithm.SHA1);
+            newKey = new PwmSecurityKey(randomBytes);
+            newKeyHash = SecureHelper.hash(randomBytes, PwmHashAlgorithm.SHA512);
         } catch (Exception e) {
             LOGGER.fatal("can't initialize PasswordData handler: " + e.getMessage(),e);
             e.printStackTrace();
@@ -81,7 +83,7 @@ public class PasswordData {
         if (passwordData.isEmpty()) {
             throw new NullPointerException("password data can not be empty");
         }
-        this.passwordData = SecureHelper.encryptToBytes(passwordData, staticKey);
+        this.passwordData = SecureHelper.encryptToBytes(passwordData, staticKey, PwmConstants.IN_MEMORY_PASSWORD_ENCRYPT_METHOD);
         this.keyHash = staticKeyHash;
     }
 
@@ -105,7 +107,7 @@ public class PasswordData {
             throws PwmUnrecoverableException
     {
         checkCurrentStatus();
-        return SecureHelper.decryptBytes(passwordData, staticKey);
+        return SecureHelper.decryptBytes(passwordData, staticKey, PwmConstants.IN_MEMORY_PASSWORD_ENCRYPT_METHOD);
     }
 
     @Override
@@ -153,7 +155,7 @@ public class PasswordData {
 
     public String hash() throws PwmUnrecoverableException {
         if (passwordHashCache == null) {
-            passwordHashCache = SecureHelper.hash(this.getStringValue());
+            passwordHashCache = SecureHelper.hash(this.getStringValue(), PwmHashAlgorithm.SHA1);
         }
         return passwordHashCache;
     }

+ 1 - 0
pwm/servlet/src/password/pwm/util/RandomPasswordGenerator.java

@@ -37,6 +37,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.PwmSession;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.operations.PasswordUtility;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.Statistic;
 import password.pwm.wordlist.SeedlistManager;
 

+ 1 - 0
pwm/servlet/src/password/pwm/util/ServletHelper.java

@@ -38,6 +38,7 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.*;
 import password.pwm.i18n.LocaleHelper;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 

+ 8 - 6
pwm/servlet/src/password/pwm/util/X509Utils.java

@@ -29,6 +29,8 @@ import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 
 import javax.net.ssl.*;
 import java.io.ByteArrayInputStream;
@@ -65,8 +67,8 @@ public abstract class X509Utils {
             LOGGER.debug("ServerCertReader: socket established to host=" + host + ", port=" + port);
             sslSock.isConnected();
             LOGGER.debug("ServerCertReader: connected to host=" + host + ", port=" + port);
-            sslSock.getOutputStream().write("data!".getBytes());//write some data so the connection gets established
-            LOGGER.debug("ServerCertReader: data transfer completed host=" + host + ", port=" + port);
+            sslSock.startHandshake();
+            LOGGER.debug("ServerCertReader: handshake completed to host=" + host + ", port=" + port);
             sslSock.close();
             LOGGER.debug("ServerCertReader: certificate information read from host=" + host + ", port=" + port);
         } catch (Exception e) {
@@ -209,10 +211,10 @@ public abstract class X509Utils {
             throws CertificateEncodingException, PwmUnrecoverableException
     {
         return x509Certificate.toString()
-                + "\n:MD5 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()),SecureHelper.HashAlgorithm.MD5)
-                + "\n:SHA1 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()),SecureHelper.HashAlgorithm.SHA1)
-                + "\n:SHA2-256 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()),SecureHelper.HashAlgorithm.SHA256)
-                + "\n:SHA2-512 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()),SecureHelper.HashAlgorithm.SHA512);
+                + "\n:MD5 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()), PwmHashAlgorithm.MD5)
+                + "\n:SHA1 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()), PwmHashAlgorithm.SHA1)
+                + "\n:SHA2-256 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()), PwmHashAlgorithm.SHA256)
+                + "\n:SHA2-512 checksum: " + SecureHelper.hash(new ByteArrayInputStream(x509Certificate.getEncoded()), PwmHashAlgorithm.SHA512);
 
 
     }

+ 3 - 2
pwm/servlet/src/password/pwm/util/cache/CacheKey.java

@@ -24,7 +24,8 @@ package password.pwm.util.cache;
 
 import password.pwm.bean.UserIdentity;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.util.SecureHelper;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 
 public class CacheKey {
     private final String cacheKey;
@@ -44,7 +45,7 @@ public class CacheKey {
         if (hash != null) {
             return hash;
         }
-        hash = SecureHelper.hash(this.cacheKey, SecureHelper.HashAlgorithm.SHA256);
+        hash = SecureHelper.hash(this.cacheKey, PwmHashAlgorithm.SHA256);
         return hash;
     }
 

+ 2 - 1
pwm/servlet/src/password/pwm/util/intruder/IntruderManager.java

@@ -51,6 +51,7 @@ import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBDataStore;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 
@@ -328,7 +329,7 @@ public class IntruderManager implements Serializable, PwmService {
                 }
 
                 if (recordType == RecordType.USER_ID) {
-                    final UserIdentity userIdentity = UserIdentity.fromKey(subject, pwmApplication.getConfig());
+                    final UserIdentity userIdentity = UserIdentity.fromKey(subject, pwmApplication);
                     final UserAuditRecord auditRecord = pwmApplication.getAuditManager().createUserAuditRecord(
                             AuditEvent.INTRUDER_USER,
                             userIdentity,

+ 1 - 1
pwm/servlet/src/password/pwm/util/intruder/RecordManagerImpl.java

@@ -28,9 +28,9 @@ import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.ClosableIterator;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.SecureHelper;
 
 class RecordManagerImpl implements RecordManager {
     private static final PwmLogger LOGGER = PwmLogger.forClass(RecordManagerImpl.class);

+ 1 - 1
pwm/servlet/src/password/pwm/util/macro/StandardMacros.java

@@ -32,10 +32,10 @@ import password.pwm.config.PwmSetting;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.bean.LoginInfoBean;
 import password.pwm.ldap.UserDataReader;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.StringUtil;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 
 import java.net.MalformedURLException;
 import java.net.URL;

+ 2 - 2
pwm/servlet/src/password/pwm/util/operations/OtpService.java

@@ -38,7 +38,6 @@ import password.pwm.error.*;
 import password.pwm.health.HealthRecord;
 import password.pwm.http.PwmSession;
 import password.pwm.ldap.LdapOperationsHelper;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.StringUtil;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
@@ -49,6 +48,7 @@ import password.pwm.util.operations.otp.LocalDbOtpOperator;
 import password.pwm.util.operations.otp.OtpOperator;
 import password.pwm.util.otp.OTPUserRecord;
 import password.pwm.util.otp.PasscodeGenerator;
+import password.pwm.util.secure.PwmRandom;
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
@@ -76,7 +76,7 @@ public class OtpService implements PwmService {
     public void init(PwmApplication pwmApplication) throws PwmException {
         this.pwmApplication = pwmApplication;
         operatorMap.put(DataStorageMethod.LDAP, new LdapOtpOperator(pwmApplication));
-        operatorMap.put(DataStorageMethod.LOCALDB, new LocalDbOtpOperator(pwmApplication.getLocalDB(), pwmApplication.getConfig()));
+        operatorMap.put(DataStorageMethod.LOCALDB, new LocalDbOtpOperator(pwmApplication));
         operatorMap.put(DataStorageMethod.DB, new DbOtpOperator(pwmApplication));
         settings = OtpSettings.fromConfig(pwmApplication.getConfig());
     }

+ 23 - 21
pwm/servlet/src/password/pwm/util/operations/otp/AbstractOtpOperator.java

@@ -23,6 +23,8 @@
 package password.pwm.util.operations.otp;
 
 import com.google.gson.JsonSyntaxException;
+import password.pwm.AppProperty;
+import password.pwm.PwmApplication;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.option.OTPStorageFormat;
@@ -30,14 +32,15 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.util.Helper;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.otp.OTPPamUtil;
 import password.pwm.util.otp.OTPUrlUtil;
 import password.pwm.util.otp.OTPUserRecord;
-
-import javax.crypto.SecretKey;
+import password.pwm.util.secure.PwmBlockAlgorithm;
+import password.pwm.util.secure.PwmSecurityKey;
+import password.pwm.util.secure.SecureHelper;
 
 /**
  *
@@ -46,7 +49,7 @@ import javax.crypto.SecretKey;
 public abstract class AbstractOtpOperator implements OtpOperator {
 
     private static final PwmLogger LOGGER = PwmLogger.forClass(AbstractOtpOperator.class);
-    private Configuration config;
+    protected PwmApplication pwmApplication;
 
     /**
      * Compose a single line of OTP information.
@@ -58,6 +61,7 @@ public abstract class AbstractOtpOperator implements OtpOperator {
     public String composeOtpAttribute(OTPUserRecord otpUserRecord) throws PwmUnrecoverableException {
         String value = "";
         if (otpUserRecord != null) {
+            final Configuration config = pwmApplication.getConfig();
             final OTPStorageFormat format = config.readSettingAsEnum(PwmSetting.OTP_SECRET_STORAGEFORMAT,OTPStorageFormat.class);
             switch (format) {
                 case PWM:
@@ -90,8 +94,14 @@ public abstract class AbstractOtpOperator implements OtpOperator {
      * @throws PwmOperationalException
      */
     public String encryptAttributeValue(String unencrypted) throws PwmUnrecoverableException, PwmOperationalException {
-        SecretKey key = config.getSecurityKey();
-        return SecureHelper.encryptToString(unencrypted, key);
+        final PwmBlockAlgorithm pwmBlockAlgorithm = figureBlockAlg();
+        final PwmSecurityKey pwmSecurityKey = pwmApplication.getConfig().getSecurityKey();
+        return SecureHelper.encryptToString(unencrypted, pwmSecurityKey, pwmBlockAlgorithm);
+    }
+
+    public PwmBlockAlgorithm figureBlockAlg() {
+        final String otpEncryptionAlgString = pwmApplication.getConfig().readAppProperty(AppProperty.OTP_ENCRYPTION_ALG);
+        return Helper.readEnumFromString(PwmBlockAlgorithm.class, PwmBlockAlgorithm.AES, otpEncryptionAlgString);
     }
 
     /**
@@ -103,8 +113,9 @@ public abstract class AbstractOtpOperator implements OtpOperator {
      * @throws PwmOperationalException
      */
     public String decryptAttributeValue(String encrypted) throws PwmUnrecoverableException, PwmOperationalException {
-        SecretKey key = config.getSecurityKey();
-        return SecureHelper.decryptStringValue(encrypted, key);
+        final PwmBlockAlgorithm pwmBlockAlgorithm = figureBlockAlg();
+        final PwmSecurityKey pwmSecurityKey = pwmApplication.getConfig().getSecurityKey();
+        return SecureHelper.decryptStringValue(encrypted, pwmSecurityKey, pwmBlockAlgorithm);
     }
 
     /**
@@ -153,20 +164,11 @@ public abstract class AbstractOtpOperator implements OtpOperator {
         return otpconfig;
     }
 
-    /**
-     *
-     * @return
-     */
-    public Configuration getConfig() {
-        return config;
+    public PwmApplication getPwmApplication() {
+        return pwmApplication;
     }
 
-    /**
-     *
-     * @param config
-     */
-    public void setConfig(Configuration config) {
-        this.config = config;
+    public void setPwmApplication(PwmApplication pwmApplication) {
+        this.pwmApplication = pwmApplication;
     }
-
 }

+ 3 - 6
pwm/servlet/src/password/pwm/util/operations/otp/DbOtpOperator.java

@@ -50,11 +50,8 @@ public class DbOtpOperator extends AbstractOtpOperator {
 
     final static private PwmLogger LOGGER = PwmLogger.forClass(DbOtpOperator.class);
 
-    final PwmApplication pwmApplication;
-
     public DbOtpOperator(PwmApplication pwmApplication) {
-        this.pwmApplication = pwmApplication;
-        super.setConfig(pwmApplication.getConfig());
+        super.setPwmApplication(pwmApplication);
     }
     
     @Override
@@ -69,7 +66,7 @@ public class DbOtpOperator extends AbstractOtpOperator {
             final DatabaseAccessorImpl databaseAccessor = pwmApplication.getDatabaseAccessor();
             String value = databaseAccessor.get(DatabaseTable.OTP, userGUID);
             if (value != null && value.length() > 0) {
-                if (getConfig().readSettingAsBoolean(PwmSetting.OTP_SECRET_ENCRYPT)) {
+                if (getPwmApplication().getConfig().readSettingAsBoolean(PwmSetting.OTP_SECRET_ENCRYPT)) {
                     value = decryptAttributeValue(value);
                 }
                 if (value != null) {
@@ -108,7 +105,7 @@ public class DbOtpOperator extends AbstractOtpOperator {
         
         try {
             String value = composeOtpAttribute(otpConfig);
-            if (getConfig().readSettingAsBoolean(PwmSetting.OTP_SECRET_ENCRYPT)) {
+            if (getPwmApplication().getConfig().readSettingAsBoolean(PwmSetting.OTP_SECRET_ENCRYPT)) {
                 LOGGER.debug("Encrypting OTP secret for storage");
                 value = encryptAttributeValue(value);
             }

+ 4 - 6
pwm/servlet/src/password/pwm/util/operations/otp/LdapOtpOperator.java

@@ -46,11 +46,9 @@ import password.pwm.util.otp.OTPUserRecord;
 public class LdapOtpOperator extends AbstractOtpOperator {
 
     private static final PwmLogger LOGGER = PwmLogger.forClass(LdapOtpOperator.class);
-    private PwmApplication pwmApplication;
 
     public LdapOtpOperator(PwmApplication pwmApplication) {
-        this.pwmApplication = pwmApplication;
-        setConfig(pwmApplication.getConfig());
+        setPwmApplication(pwmApplication);
     }
 
     /**
@@ -63,7 +61,7 @@ public class LdapOtpOperator extends AbstractOtpOperator {
      */
     @Override
     public OTPUserRecord readOtpUserConfiguration(UserIdentity userIdentity, String userGUID) throws PwmUnrecoverableException {
-        Configuration config = getConfig();
+        Configuration config = getPwmApplication().getConfig();
         String ldapStorageAttribute = config.readSettingAsString(PwmSetting.OTP_SECRET_LDAP_ATTRIBUTE);
         if (ldapStorageAttribute == null || ldapStorageAttribute.length() < 1) {
             final String errorMsg = "ldap storage attribute is not configured, unable to read OTP secret";
@@ -110,7 +108,7 @@ public class LdapOtpOperator extends AbstractOtpOperator {
             final String userGuid,
             final OTPUserRecord otpConfig
     ) throws PwmUnrecoverableException {
-        Configuration config = getConfig();
+        Configuration config = pwmApplication.getConfig();
         final String ldapStorageAttribute = config.readSettingAsString(PwmSetting.OTP_SECRET_LDAP_ATTRIBUTE);
         if (ldapStorageAttribute == null || ldapStorageAttribute.length() < 1) {
             final String errorMsg = "ldap storage attribute is not configured, unable to write OTP secret";
@@ -163,7 +161,7 @@ public class LdapOtpOperator extends AbstractOtpOperator {
             final UserIdentity userIdentity,
             final String userGuid
     ) throws PwmUnrecoverableException {
-        Configuration config = getConfig();
+        Configuration config = pwmApplication.getConfig();
         final String ldapStorageAttribute = config.readSettingAsString(PwmSetting.OTP_SECRET_LDAP_ATTRIBUTE);
         if (ldapStorageAttribute == null || ldapStorageAttribute.length() < 1) {
             final String errorMsg = "ldap storage attribute is not configured, unable to clear OTP secret";

+ 6 - 5
pwm/servlet/src/password/pwm/util/operations/otp/LocalDbOtpOperator.java

@@ -27,6 +27,7 @@
  */
 package password.pwm.util.operations.otp;
 
+import password.pwm.PwmApplication;
 import password.pwm.bean.UserIdentity;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
@@ -49,9 +50,9 @@ public class LocalDbOtpOperator extends AbstractOtpOperator {
     private static final PwmLogger LOGGER = PwmLogger.forClass(LocalDbOtpOperator.class);
     private final LocalDB localDB;
 
-    public LocalDbOtpOperator(LocalDB localDB, Configuration config) {
-        this.localDB = localDB;
-        setConfig(config);
+    public LocalDbOtpOperator(PwmApplication pwmApplication) {
+        this.localDB = pwmApplication.getLocalDB();
+        setPwmApplication(pwmApplication);
     }
 
     @Override
@@ -69,7 +70,7 @@ public class LocalDbOtpOperator extends AbstractOtpOperator {
 
         OTPUserRecord otpConfig = null;
         try {
-            Configuration config = this.getConfig();
+            Configuration config = this.getPwmApplication().getConfig();
             String value = localDB.get(LocalDB.DB.OTP_SECRET, userGUID);
             if (value != null && value.length() > 0) {
                 if (config.readSettingAsBoolean(PwmSetting.OTP_SECRET_ENCRYPT)) {
@@ -115,7 +116,7 @@ public class LocalDbOtpOperator extends AbstractOtpOperator {
         }
 
         try {
-            Configuration config = this.getConfig();
+            Configuration config = this.getPwmApplication().getConfig();
             String value = composeOtpAttribute(otpConfig);
             if (config.readSettingAsBoolean(PwmSetting.OTP_SECRET_ENCRYPT)) {
                 LOGGER.debug(pwmSession,"Encrypting OTP secret for storage");

+ 1 - 0
pwm/servlet/src/password/pwm/util/queue/SmsQueueManager.java

@@ -42,6 +42,7 @@ import password.pwm.http.client.PwmHttpClient;
 import password.pwm.util.*;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.Statistic;
 import password.pwm.util.stats.StatisticsManager;
 

+ 3 - 2
pwm/servlet/src/password/pwm/util/report/ReportSettings.java

@@ -22,13 +22,14 @@
 
 package password.pwm.util.report;
 
+import password.pwm.PwmConstants;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -130,6 +131,6 @@ class ReportSettings implements Serializable {
     public String getSettingsHash() 
             throws PwmUnrecoverableException 
     {
-        return SecureHelper.hash(JsonUtil.serialize(this), SecureHelper.DEFAULT_HASH_ALGORITHM);
+        return SecureHelper.hash(JsonUtil.serialize(this), PwmConstants.SETTING_CHECKSUM_HASH_METHOD);
     }
 }

+ 1 - 1
pwm/servlet/src/password/pwm/util/report/UserCacheService.java

@@ -35,10 +35,10 @@ import password.pwm.health.HealthRecord;
 import password.pwm.ldap.LdapOperationsHelper;
 import password.pwm.util.ClosableIterator;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.SecureHelper;
 
 import java.util.Collections;
 import java.util.List;

+ 33 - 0
pwm/servlet/src/password/pwm/util/secure/PwmBlockAlgorithm.java

@@ -0,0 +1,33 @@
+package password.pwm.util.secure;
+
+import password.pwm.PwmConstants;
+
+public enum PwmBlockAlgorithm {
+    AES(      "AES", "AES",         "AES-128"),
+    AES_HMAC( "AES", "AES_HMAC",    "AES-128+Hmac256"),
+    CONFIG(   "AES", "",            PwmConstants.PWM_APP_NAME + " Configuration AES"),
+
+    ;
+
+    private final String algName;
+    private final byte[] prefix;
+    private final String label;
+
+    PwmBlockAlgorithm(String algName, String prefix, String label) {
+        this.algName = algName;
+        this.prefix = prefix.getBytes(PwmConstants.DEFAULT_CHARSET);
+        this.label = label;
+    }
+
+    public String getAlgName() {
+        return algName;
+    }
+
+    public byte[] getPrefix() {
+        return prefix;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+}

+ 18 - 0
pwm/servlet/src/password/pwm/util/secure/PwmHashAlgorithm.java

@@ -0,0 +1,18 @@
+package password.pwm.util.secure;
+
+public enum PwmHashAlgorithm {
+    MD5("MD5"),
+    SHA1("SHA1"),
+    SHA256("SHA-256"),
+    SHA512("SHA-512"),;
+
+    private final String algName;
+
+    PwmHashAlgorithm(String algName) {
+        this.algName = algName;
+    }
+
+    public String getAlgName() {
+        return algName;
+    }
+}

+ 1 - 1
pwm/servlet/src/password/pwm/util/PwmRandom.java → pwm/servlet/src/password/pwm/util/secure/PwmRandom.java

@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-package password.pwm.util;
+package password.pwm.util.secure;
 
 import java.security.SecureRandom;
 import java.util.UUID;

+ 65 - 0
pwm/servlet/src/password/pwm/util/secure/PwmSecurityKey.java

@@ -0,0 +1,65 @@
+package password.pwm.util.secure;
+
+import password.pwm.error.ErrorInformation;
+import password.pwm.error.PwmError;
+import password.pwm.error.PwmUnrecoverableException;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class PwmSecurityKey {
+
+    enum Type {
+        AES,
+        HMAC_256,
+    }
+
+    final private byte[] keyData;
+
+    public PwmSecurityKey(byte[] keyData) {
+        this.keyData = keyData;
+    }
+
+    public PwmSecurityKey(String keyData) throws PwmUnrecoverableException {
+        this.keyData = stringToKeyData(keyData);
+    }
+
+    byte[] stringToKeyData(final String input) throws PwmUnrecoverableException {
+        try {
+            return input.getBytes("iso-8859-1");
+        } catch (UnsupportedEncodingException e) {
+            final String errorMsg = "unexpected error converting input text to crypto key bytes: " + e.getMessage();
+            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
+            throw new PwmUnrecoverableException(errorInformation);
+        }
+    }
+
+    SecretKey getKey(Type keyType)
+            throws PwmUnrecoverableException {
+        switch (keyType) {
+            case AES: {
+                try {
+                    final int KEY_LENGTH = 16;
+                    final MessageDigest md = MessageDigest.getInstance("SHA1");
+                    md.update(keyData, 0, keyData.length);
+                    final byte[] key = new byte[KEY_LENGTH];
+                    System.arraycopy(md.digest(), 0, key, 0, KEY_LENGTH);
+                    return new SecretKeySpec(key, "AES");
+                } catch (NoSuchAlgorithmException e) {
+                    final String errorMsg = "unexpected error generating simple crypto key: " + e.getMessage();
+                    final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
+                    throw new PwmUnrecoverableException(errorInformation);
+                }
+            }
+
+            case HMAC_256: {
+                return new SecretKeySpec(keyData, "HmacSHA256");
+            }
+        }
+
+        throw new IllegalStateException("unknown key type: " + keyType);
+    }
+}

+ 114 - 225
pwm/servlet/src/password/pwm/util/SecureHelper.java → pwm/servlet/src/password/pwm/util/secure/SecureHelper.java

@@ -20,18 +20,21 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-package password.pwm.util;
+package password.pwm.util.secure;
 
 import password.pwm.PwmConstants;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.util.Helper;
+import password.pwm.util.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 
 import javax.crypto.Cipher;
+import javax.crypto.Mac;
 import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
 import java.io.*;
+import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
@@ -42,81 +45,20 @@ public class SecureHelper {
 
     private static final int HASH_BUFFER_SIZE = 1024;
 
-    public static final HashAlgorithm DEFAULT_HASH_ALGORITHM = HashAlgorithm.SHA512;
-    public static final BlockAlgorithm DEFAULT_BLOCK_ALGORITHM = BlockAlgorithm.AES;
-
-    public enum HashAlgorithm {
-        MD5("MD5"),
-        SHA1("SHA1"),
-        SHA256("SHA-256"),
-        SHA512("SHA-512"),
-
-        ;
-
-        private final String algName;
-
-        HashAlgorithm(String algName)
-        {
-            this.algName = algName;
-        }
-
-        public String getAlgName()
-        {
-            return algName;
-        }
-    }
-
-    public enum BlockAlgorithm {
-        AES("AES"),
-        AES_SHA2("AES"),
-        AES_CHECKSUM("AES/CBC/PKCS5Padding"),
-        CONFIG("AES"),
-
-        ;
-
-        private final String algName;
-
-        BlockAlgorithm(String algName)
-        {
-            this.algName = algName;
-        }
-
-        public String getAlgName()
-        {
-            return algName;
-        }
-    }
-
-    public static String encryptToString(
-            final String value,
-            final SecretKey key
-    )
-            throws PwmUnrecoverableException
-    {
-        return encryptToString(value, key, false);
-    }
-
-    public static String encryptToString(
-            final String value,
-            final SecretKey key,
-            final boolean urlSafe
-    )
-            throws PwmUnrecoverableException
-    {
-        return encryptToString(value, key, urlSafe, DEFAULT_BLOCK_ALGORITHM);
+    public enum Flag {
+        URL_SAFE,
     }
 
     public static String encryptToString(
             final String value,
-            final SecretKey key,
-            final boolean urlSafe,
-            final BlockAlgorithm blockAlgorithm
+            final PwmSecurityKey key,
+            final PwmBlockAlgorithm blockAlgorithm,
+            final Flag... flags
     )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
         try {
             final byte[] encrypted = encryptToBytes(value, key, blockAlgorithm);
-            return urlSafe
+            return Arrays.asList(flags).contains(Flag.URL_SAFE)
                     ? StringUtil.base64Encode(encrypted, StringUtil.Base64Options.URL_SAFE, StringUtil.Base64Options.GZIP)
                     : StringUtil.base64Encode(encrypted);
         } catch (Exception e) {
@@ -127,46 +69,31 @@ public class SecureHelper {
         }
     }
 
-    public static byte[] encryptToBytes(
-            final String value,
-            final SecretKey key
-    )
-            throws PwmUnrecoverableException
-    {
-        return encryptToBytes(value, key, DEFAULT_BLOCK_ALGORITHM);
-    }
 
     public static byte[] encryptToBytes(
             final String value,
-            final SecretKey key,
-            final BlockAlgorithm blockAlgorithm
+            final PwmSecurityKey key,
+            final PwmBlockAlgorithm blockAlgorithm
     )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
         try {
             if (value == null || value.length() < 1) {
                 return null;
             }
 
+            final SecretKey aesKey = key.getKey(PwmSecurityKey.Type.AES);
             final Cipher cipher = Cipher.getInstance(blockAlgorithm.getAlgName());
-            cipher.init(Cipher.ENCRYPT_MODE, key, cipher.getParameters());
+            cipher.init(Cipher.ENCRYPT_MODE, aesKey, cipher.getParameters());
             final byte[] encryptedBytes = cipher.doFinal(value.getBytes(PwmConstants.DEFAULT_CHARSET));
-            if (blockAlgorithm.equals(BlockAlgorithm.AES_SHA2)) {
-                final byte[] hashChecksum;
-                {
-                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                    baos.write(key.getEncoded());
-                    baos.write(encryptedBytes);
-                    hashChecksum = hashToBytes(new ByteArrayInputStream(baos.toByteArray()),HashAlgorithm.SHA256);
-                }
-                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                baos.write(hashChecksum);
-                baos.write(encryptedBytes);
-                return baos.toByteArray();
 
+            final byte[] output;
+            if (blockAlgorithm.equals(PwmBlockAlgorithm.AES_HMAC)) {
+                final byte[] hashChecksum = hmac(key, encryptedBytes);
+                output = appendByteArrays(blockAlgorithm.getPrefix(), hashChecksum, encryptedBytes);
             } else {
-                return encryptedBytes;
+                output = appendByteArrays(blockAlgorithm.getPrefix(), encryptedBytes);
             }
+            return output;
 
         } catch (Exception e) {
             final String errorMsg = "unexpected error performing simple crypt operation: " + e.getMessage();
@@ -176,41 +103,21 @@ public class SecureHelper {
         }
     }
 
-    public static String decryptStringValue(
-            final String value,
-            final SecretKey key
-    )
-            throws PwmUnrecoverableException
-    {
-        return decryptStringValue(value, key, false);
-    }
 
     public static String decryptStringValue(
             final String value,
-            final SecretKey key,
-            final boolean urlSafe
+            final PwmSecurityKey key,
+            final PwmBlockAlgorithm blockAlgorithm,
+            final Flag... flags
     )
-            throws PwmUnrecoverableException
-    {
-
-        return decryptStringValue(value, key, urlSafe, DEFAULT_BLOCK_ALGORITHM);
-    }
-
-    public static String decryptStringValue(
-            final String value,
-            final SecretKey key,
-            final boolean urlSafe,
-            final BlockAlgorithm blockAlgorithm
-    )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
         try {
             if (value == null || value.length() < 1) {
                 return "";
             }
 
-            final byte[] decoded = urlSafe
-                    ? StringUtil.base64Decode(value, StringUtil.Base64Options.URL_SAFE,StringUtil.Base64Options.GZIP)
+            final byte[] decoded = Arrays.asList(flags).contains(Flag.URL_SAFE)
+                    ? StringUtil.base64Decode(value, StringUtil.Base64Options.URL_SAFE, StringUtil.Base64Options.GZIP)
                     : StringUtil.base64Decode(value);
             return decryptBytes(decoded, key, blockAlgorithm);
         } catch (Exception e) {
@@ -220,51 +127,37 @@ public class SecureHelper {
         }
     }
 
-    public static String decryptBytes(
-            final byte[] value,
-            final SecretKey key
-    )
-            throws PwmUnrecoverableException
-    {
-        return decryptBytes(value, key, DEFAULT_BLOCK_ALGORITHM);
-    }
-
     public static String decryptBytes(
             byte[] value,
-            final SecretKey key,
-            final BlockAlgorithm blockAlgorithm
+            final PwmSecurityKey key,
+            final PwmBlockAlgorithm blockAlgorithm
     )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
         try {
             if (value == null || value.length < 1) {
                 return null;
             }
 
-            if (blockAlgorithm == BlockAlgorithm.AES_SHA2) {
+            value = verifyAndStripPrefix(blockAlgorithm, value);
+
+            final SecretKey aesKey = key.getKey(PwmSecurityKey.Type.AES);
+            if (blockAlgorithm == PwmBlockAlgorithm.AES_HMAC) {
                 final int CHECKSUM_SIZE = 32;
                 if (value.length <= CHECKSUM_SIZE) {
-                    throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_CRYPT_ERROR,"incoming AES_SHA2 data is missing checksum"));
+                    throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, "incoming " + blockAlgorithm.toString()  + " data is missing checksum"));
                 }
-                final byte[] suppliedChecksum = Arrays.copyOfRange(value, 0, CHECKSUM_SIZE);
-                final byte[] suppliedPayload = Arrays.copyOfRange(value, CHECKSUM_SIZE, value.length);
-                final byte[] computedChecksum;
-                {
-                    final byte[] keyBytes = key.getEncoded();
-                    final byte[] payloadPlusKeyBytes = new byte[keyBytes.length + suppliedPayload.length];
-                    System.arraycopy(keyBytes, 0, payloadPlusKeyBytes, 0, keyBytes.length);
-                    System.arraycopy(suppliedPayload, 0, payloadPlusKeyBytes, keyBytes.length, suppliedPayload.length);
-                    computedChecksum = hashToBytes(new ByteArrayInputStream(payloadPlusKeyBytes), HashAlgorithm.SHA256);
+                final byte[] inputChecksum = Arrays.copyOfRange(value, 0, CHECKSUM_SIZE);
+                final byte[] inputPayload = Arrays.copyOfRange(value, CHECKSUM_SIZE, value.length);
+                final byte[] computedChecksum = hmac(key, inputPayload);
+                if (!Arrays.equals(inputChecksum, computedChecksum)) {
+                    throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, "incoming " + blockAlgorithm.toString()  + " data has incorrect checksum"));
                 }
-                if (!Arrays.equals(suppliedChecksum,computedChecksum)) {
-                    throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_CRYPT_ERROR,"incoming AES_SHA2 data has incorrect checksum"));
-                }
-                value = suppliedPayload;
+                value = inputPayload;
             }
             final Cipher cipher = Cipher.getInstance(blockAlgorithm.getAlgName());
-            cipher.init(Cipher.DECRYPT_MODE, key);
+            cipher.init(Cipher.DECRYPT_MODE, aesKey);
             final byte[] decrypted = cipher.doFinal(value);
-            return new String(decrypted,PwmConstants.DEFAULT_CHARSET);
+            return new String(decrypted, PwmConstants.DEFAULT_CHARSET);
         } catch (Exception e) {
             final String errorMsg = "unexpected error performing simple decrypt operation: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
@@ -272,75 +165,32 @@ public class SecureHelper {
         }
     }
 
-    public static SecretKey makeKey(final String text)
-            throws PwmUnrecoverableException
-    {
-        try {
-        final byte[] key = text.getBytes("iso-8859-1");
-        return makeKey(key);
-        } catch ( UnsupportedEncodingException e) {
-            final String errorMsg = "unexpected error converting input text to crypto key bytes: " + e.getMessage();
-            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
-            throw new PwmUnrecoverableException(errorInformation);
-        }
-    }
-
-    public static SecretKey makeKey(final byte[] inputBytes)
-            throws PwmUnrecoverableException {
-        try {
-            final MessageDigest md = MessageDigest.getInstance("SHA1");
-            md.update(inputBytes, 0, inputBytes.length);
-            final byte[] key = new byte[16];
-            System.arraycopy(md.digest(), 0, key, 0, 16);
-            return new SecretKeySpec(key, "AES");
-        } catch (NoSuchAlgorithmException e) {
-            final String errorMsg = "unexpected error generating simple crypto key: " + e.getMessage();
-            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
-            throw new PwmUnrecoverableException(errorInformation);
-        }
-    }
-
     public static String md5sum(final String input)
-            throws PwmUnrecoverableException
-    {
-        return hash(input, HashAlgorithm.MD5);
-    }
-
-    public static String md5sum(final File theFile)
-            throws PwmUnrecoverableException, IOException {
-        return md5sum(new FileInputStream(theFile));
+            throws PwmUnrecoverableException {
+        return hash(input, PwmHashAlgorithm.MD5);
     }
 
     public static String md5sum(final InputStream is)
             throws PwmUnrecoverableException {
-        return hash(is, HashAlgorithm.MD5);
+        return hash(is, PwmHashAlgorithm.MD5);
     }
 
     public static String hash(
             final byte[] input,
-            final HashAlgorithm algorithm
+            final PwmHashAlgorithm algorithm
     )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
         if (input == null || input.length < 1) {
             return null;
         }
         return hash(new ByteArrayInputStream(input), algorithm);
     }
 
-    public static String hash(
-            final File file
-    )
-            throws IOException, PwmUnrecoverableException
-    {
-        return hash(file,DEFAULT_HASH_ALGORITHM);
-    }
     public static String hash(
             final File file,
-            final HashAlgorithm hashAlgorithm
+            final PwmHashAlgorithm hashAlgorithm
     )
-            throws IOException, PwmUnrecoverableException
-    {
+            throws IOException, PwmUnrecoverableException {
         if (file == null || !file.exists()) {
             return null;
         }
@@ -355,23 +205,11 @@ public class SecureHelper {
         }
     }
 
-    public static String hash(
-            final String input
-    )
-            throws PwmUnrecoverableException
-    {
-        if (input == null || input.length() < 1) {
-            return null;
-        }
-        return hash(new ByteArrayInputStream(input.getBytes(PwmConstants.DEFAULT_CHARSET)), DEFAULT_HASH_ALGORITHM);
-    }
-
     public static String hash(
             final String input,
-            final HashAlgorithm algorithm
+            final PwmHashAlgorithm algorithm
     )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
         if (input == null || input.length() < 1) {
             return null;
         }
@@ -380,21 +218,33 @@ public class SecureHelper {
 
     public static String hash(
             final InputStream is,
-            final HashAlgorithm algorithm
+            final PwmHashAlgorithm algorithm
     )
+            throws PwmUnrecoverableException {
+        return Helper.byteArrayToHexString(hashToBytes(is, algorithm));
+    }
+
+    static byte[] hmac(final PwmSecurityKey pwmSecurityKey, final byte[] input)
             throws PwmUnrecoverableException
     {
-        return Helper.byteArrayToHexString(hashToBytes(is,algorithm));
+        try {
+            final Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+            final SecretKey secret_key = pwmSecurityKey.getKey(PwmSecurityKey.Type.HMAC_256);
+            sha256_HMAC.init(secret_key);
+            return sha256_HMAC.doFinal(input);
+        } catch (GeneralSecurityException e) {
+            final String errorMsg = "error during hmac operation: " + e.getMessage();
+            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
+            throw new PwmUnrecoverableException(errorInformation);
+        }
     }
 
 
-
     public static byte[] hashToBytes(
             final InputStream is,
-            final HashAlgorithm algorithm
+            final PwmHashAlgorithm algorithm
     )
-            throws PwmUnrecoverableException
-    {
+            throws PwmUnrecoverableException {
 
         final InputStream bis = is instanceof BufferedInputStream ? is : new BufferedInputStream(is);
 
@@ -407,8 +257,7 @@ public class SecureHelper {
             throw new PwmUnrecoverableException(errorInformation);
         }
 
-        try
-        {
+        try {
             final byte[] buffer = new byte[HASH_BUFFER_SIZE];
             int length;
             while (true) {
@@ -422,9 +271,49 @@ public class SecureHelper {
 
             return messageDigest.digest();
         } catch (IOException e) {
-            final String errorMsg = "unexepected error during hash operation: " + e.getMessage();
+            final String errorMsg = "unexpected error during hash operation: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
             throw new PwmUnrecoverableException(errorInformation);
         }
     }
+
+    static byte[] appendByteArrays(final byte[]... input) {
+        if (input == null || input.length == 0) {
+            return new byte[0];
+        }
+
+        if (input.length == 1) {
+            return input[0];
+        }
+
+        int totalLength = 0;
+        for (final byte[] loopBa : input) {
+            totalLength += loopBa.length;
+        }
+
+        final byte[] output = new byte[totalLength];
+
+        int position = 0;
+        for (final byte[] loopBa : input) {
+            System.arraycopy(loopBa,0,output,position,loopBa.length);
+            position += loopBa.length;
+        }
+        return output;
+    }
+
+    static byte[] verifyAndStripPrefix(final PwmBlockAlgorithm blockAlgorithm, final byte[] input) throws PwmUnrecoverableException {
+        byte[] definedPrefix = blockAlgorithm.getPrefix();
+        if (definedPrefix.length == 0) {
+            return input;
+        }
+        byte[] inputPrefix = Arrays.copyOf(input, definedPrefix.length);
+        if (!Arrays.equals(definedPrefix, inputPrefix)) {
+            final String errorMsg = "value is missing valid prefix for decrpyption type";
+            final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_CRYPT_ERROR, errorMsg);
+            throw new PwmUnrecoverableException(errorInformation);
+        }
+
+        return Arrays.copyOfRange(input,definedPrefix.length,input.length);
+    }
+
 }

+ 98 - 0
pwm/servlet/src/password/pwm/util/secure/SecureService.java

@@ -0,0 +1,98 @@
+package password.pwm.util.secure;
+
+import password.pwm.AppProperty;
+import password.pwm.PwmApplication;
+import password.pwm.PwmService;
+import password.pwm.config.Configuration;
+import password.pwm.error.PwmException;
+import password.pwm.error.PwmUnrecoverableException;
+import password.pwm.health.HealthRecord;
+import password.pwm.util.Helper;
+import password.pwm.util.logging.PwmLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class SecureService implements PwmService {
+
+    private static final PwmLogger LOGGER = PwmLogger.forClass(SecureService.class);
+
+    private PwmSecurityKey pwmSecurityKey;
+    private PwmBlockAlgorithm defaultBlockAlgorithm;
+    private PwmHashAlgorithm defaultHashAlorithm;
+
+    @Override
+    public STATUS status() {
+        return STATUS.OPEN;
+    }
+
+    @Override
+    public void init(PwmApplication pwmApplication) throws PwmException {
+        final Configuration config = pwmApplication.getConfig();
+        pwmSecurityKey = config.getSecurityKey();
+        {
+            final String defaultBlockAlgString = config.readAppProperty(AppProperty.SECURITY_DEFAULT_EPHEMERAL_BLOCK_ALG);
+            defaultBlockAlgorithm = Helper.readEnumFromString(PwmBlockAlgorithm.class, PwmBlockAlgorithm.AES, defaultBlockAlgString);
+            LOGGER.debug("using default ephemeral block algorithm: "+ defaultBlockAlgorithm.getLabel());
+        }
+        {
+            final String defaultHashAlgString = config.readAppProperty(AppProperty.SECURITY_DEFAULT_EPHEMERAL_HASH_ALG);
+            defaultHashAlorithm = Helper.readEnumFromString(PwmHashAlgorithm.class, PwmHashAlgorithm.SHA512, defaultHashAlgString);
+            LOGGER.debug("using default ephemeral hash algorithm: "+ defaultHashAlgString.toString());
+        }
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public List<HealthRecord> healthCheck() {
+        return null;
+    }
+
+    @Override
+    public ServiceInfo serviceInfo() {
+        return null;
+    }
+
+    public PwmBlockAlgorithm getDefaultBlockAlgorithm() {
+        return defaultBlockAlgorithm;
+    }
+
+    public PwmHashAlgorithm getDefaultHashAlorithm() {
+        return defaultHashAlorithm;
+    }
+
+    public String encryptToString(final String value)
+            throws PwmUnrecoverableException
+    {
+        return SecureHelper.encryptToString(value, pwmSecurityKey, defaultBlockAlgorithm, SecureHelper.Flag.URL_SAFE);
+    }
+
+    public String decryptStringValue(
+            final String value
+    )
+            throws PwmUnrecoverableException {
+        return SecureHelper.decryptStringValue(value, pwmSecurityKey, defaultBlockAlgorithm, SecureHelper.Flag.URL_SAFE);
+    }
+
+
+    public String hash(
+            final String input
+    )
+            throws PwmUnrecoverableException
+    {
+        return SecureHelper.hash(input, defaultHashAlorithm);
+    }
+
+    public String hash(
+            final File file
+    )
+            throws IOException, PwmUnrecoverableException
+    {
+        return SecureHelper.hash(file, defaultHashAlorithm);
+    }
+}

+ 6 - 2
pwm/servlet/src/password/pwm/util/stats/StatisticsManager.java

@@ -39,10 +39,14 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.health.HealthRecord;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.client.PwmHttpClient;
-import password.pwm.util.*;
+import password.pwm.util.AlertHandler;
+import password.pwm.util.Helper;
+import password.pwm.util.JsonUtil;
+import password.pwm.util.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -295,7 +299,7 @@ public class StatisticsManager implements PwmService {
                         }
                     }
                 }
-                final Date nextPublishTime = new Date(lastPublishTimestamp + PwmConstants.STATISTICS_PUBLISH_FREQUENCY_MS + (long)PwmRandom.getInstance().nextInt(3600 * 1000));
+                final Date nextPublishTime = new Date(lastPublishTimestamp + PwmConstants.STATISTICS_PUBLISH_FREQUENCY_MS + (long) PwmRandom.getInstance().nextInt(3600 * 1000));
                 daemonTimer.schedule(new PublishTask(), nextPublishTime, PwmConstants.STATISTICS_PUBLISH_FREQUENCY_MS);
             }
         }

+ 3 - 2
pwm/servlet/src/password/pwm/wordlist/AbstractWordlist.java

@@ -33,12 +33,13 @@ import password.pwm.health.HealthRecord;
 import password.pwm.health.HealthStatus;
 import password.pwm.health.HealthTopic;
 import password.pwm.util.Helper;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.Sleeper;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.File;
 import java.io.IOException;
@@ -167,7 +168,7 @@ abstract class AbstractWordlist implements Wordlist, PwmService {
     protected String makeChecksumString(final File wordlistFile)
             throws PwmUnrecoverableException, IOException {
         final StringBuilder checksumString = new StringBuilder();
-        checksumString.append("hash=").append(SecureHelper.hash(wordlistFile));
+        checksumString.append("hash=").append(SecureHelper.hash(wordlistFile, PwmHashAlgorithm.SHA1));
         checksumString.append(",length=").append(wordlistFile.length());
         checksumString.append(",caseSensitive=").append(wordlistConfiguration.isCaseSensitive());
         return checksumString.toString();

+ 1 - 1
pwm/servlet/src/password/pwm/wordlist/SeedlistManager.java

@@ -27,10 +27,10 @@ import password.pwm.PwmConstants;
 import password.pwm.config.PwmSetting;
 import password.pwm.error.PwmException;
 import password.pwm.util.Helper;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 
 import java.io.File;
 import java.util.Collections;

+ 20 - 23
pwm/servlet/src/password/pwm/wordlist/SharedHistoryManager.java

@@ -24,20 +24,20 @@ package password.pwm.wordlist;
 
 import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
-import password.pwm.PwmConstants;
 import password.pwm.PwmService;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.option.DataStorageMethod;
 import password.pwm.error.PwmException;
-import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.health.HealthRecord;
 import password.pwm.http.PwmSession;
-import password.pwm.util.*;
+import password.pwm.util.Helper;
+import password.pwm.util.Sleeper;
+import password.pwm.util.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmRandom;
 
-import java.io.ByteArrayInputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.*;
@@ -50,6 +50,7 @@ public class SharedHistoryManager implements Wordlist {
 
     private static final String KEY_OLDEST_ENTRY = "oldest_entry";
     private static final String KEY_VERSION = "version";
+    private static final String KEY_SALT = "salt";
 
     private static final int MIN_CLEANER_FREQUENCY = 1000 * 60 * 60; // 1 hour
     private static final int MAX_CLEANER_FREQUENCY = 1000 * 60 * 60 * 24; // 1 day
@@ -375,8 +376,10 @@ public class SharedHistoryManager implements Wordlist {
         settings.hashIterations = Integer.parseInt(pwmApplication.getConfig().readAppProperty(AppProperty.SECURITY_SHAREDHISTORY_HASH_ITERATIONS));
         settings.version = "2" + "_" + settings.hashName + "_" + settings.hashIterations + "_" + settings.caseInsensitive;
 
+        final int SALT_LENGTH = Integer.parseInt(pwmApplication.getConfig().readAppProperty(AppProperty.SECURITY_SHAREDHISTORY_SALT_LENGTH));
         this.localDB = pwmApplication.getLocalDB();
 
+        boolean needsClearing = false;
         if (localDB == null) {
             LOGGER.info("LocalDB is not available, will remain closed");
             status = STATUS.CLOSED;
@@ -385,7 +388,20 @@ public class SharedHistoryManager implements Wordlist {
 
         if (settings.maxAgeMs < 1) {
             LOGGER.debug("max age=" + settings.maxAgeMs + ", will remain closed");
+            needsClearing = true;
+        }
 
+        {
+            this.salt = localDB.get(META_DB, KEY_SALT);
+            if (salt == null || salt.length() < SALT_LENGTH) {
+                LOGGER.warn("stored global salt value is not present, creating new salt");
+                this.salt = PwmRandom.getInstance().alphaNumericString(SALT_LENGTH);
+                localDB.put(META_DB, KEY_SALT,this.salt);
+                needsClearing = true;
+            }
+        }
+
+        if (needsClearing) {
             LOGGER.trace("clearing wordlist");
             try {
                 localDB.truncate(WORDS_DB);
@@ -394,25 +410,6 @@ public class SharedHistoryManager implements Wordlist {
             }
         }
 
-        {
-            final PasswordData securityKey = pwmApplication.getConfig().readSettingAsPassword(PwmSetting.PWM_SECURITY_KEY);
-            if (securityKey == null) {
-                LOGGER.info("securityKey is not available, will remain closed");
-                status = STATUS.CLOSED;
-                return;
-            }
-            try {
-                this.salt = SecureHelper.hash(
-                        new ByteArrayInputStream(securityKey.getStringValue().getBytes(PwmConstants.DEFAULT_CHARSET)),
-                        SecureHelper.DEFAULT_HASH_ALGORITHM);
-            } catch (PwmUnrecoverableException e) {
-                LOGGER.info(
-                        "unable to create hash-derived salt value from security key, will remain closed; error: " + e.getMessage());
-                status = STATUS.CLOSED;
-                return;
-            }
-        }
-
         new Thread(new Runnable() {
             public void run() {
                 LOGGER.debug("starting up in background thread");

+ 5 - 4
pwm/servlet/src/password/pwm/ws/client/rest/naaf/NAAFEndPoint.java

@@ -12,10 +12,11 @@ import password.pwm.http.client.PwmHttpClientConfiguration;
 import password.pwm.http.client.PwmHttpClientRequest;
 import password.pwm.http.client.PwmHttpClientResponse;
 import password.pwm.util.JsonUtil;
-import password.pwm.util.PwmRandom;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.ServletHelper;
 import password.pwm.util.logging.PwmLogger;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.PwmRandom;
+import password.pwm.util.secure.SecureHelper;
 
 import java.io.Serializable;
 import java.security.cert.X509Certificate;
@@ -61,9 +62,9 @@ public class NAAFEndPoint {
     {
         LOGGER.debug("establishing endpoint connection to " + endpointURL);
         final String m1 = id + salt;
-        final String m1Hash = SecureHelper.hash(m1, SecureHelper.HashAlgorithm.SHA256).toLowerCase();
+        final String m1Hash = SecureHelper.hash(m1, PwmHashAlgorithm.SHA256).toLowerCase();
         final String m2 = secret + m1Hash;
-        final String m2Hash = SecureHelper.hash(m2, SecureHelper.HashAlgorithm.SHA256).toLowerCase();
+        final String m2Hash = SecureHelper.hash(m2, PwmHashAlgorithm.SHA256).toLowerCase();
 
         final HashMap<String, Object> initConnectMap = new HashMap<>();
         initConnectMap.put("salt", salt);

+ 3 - 2
pwm/servlet/src/password/pwm/ws/server/rest/RestAppDataServer.java

@@ -48,10 +48,11 @@ import password.pwm.http.PwmSession;
 import password.pwm.http.servlet.ResourceFileServlet;
 import password.pwm.i18n.Display;
 import password.pwm.i18n.LocaleHelper;
-import password.pwm.util.SecureHelper;
 import password.pwm.util.intruder.RecordType;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
+import password.pwm.util.secure.PwmHashAlgorithm;
+import password.pwm.util.secure.SecureHelper;
 import password.pwm.util.stats.Statistic;
 import password.pwm.ws.server.RestRequestBean;
 import password.pwm.ws.server.RestResultBean;
@@ -473,6 +474,6 @@ public class RestAppDataServer extends AbstractRestServer {
             inputString.append(pwmSession.getLoginInfoBean().getLocalAuthTime());
         }
 
-        return SecureHelper.hash(inputString.toString(), SecureHelper.HashAlgorithm.SHA1).toLowerCase();
+        return SecureHelper.hash(inputString.toString(), PwmHashAlgorithm.SHA1).toLowerCase();
     }
 }

+ 1 - 1
pwm/servlet/src/password/pwm/ws/server/rest/RestRandomPasswordServer.java

@@ -217,7 +217,7 @@ public class RestRandomPasswordServer extends AbstractRestServer {
         }
 
         if (!jsonInput.noUser && restRequestBean.getPwmSession().getSessionStateBean().isAuthenticated()) {
-            final UserIdentity userIdentity = UserIdentity.fromKey(jsonInput.username,restRequestBean.getPwmApplication().getConfig());
+            final UserIdentity userIdentity = UserIdentity.fromKey(jsonInput.username,restRequestBean.getPwmApplication());
             if (userIdentity != null) {
                 final HelpdeskProfile helpdeskProfile = restRequestBean.getPwmSession().getSessionManager().getHelpdeskProfile(restRequestBean.getPwmApplication());
                 final boolean useProxy = helpdeskProfile.readSettingAsBoolean(PwmSetting.HELPDESK_USE_PROXY);

+ 1 - 1
pwm/servlet/tests/junit/password/pwm/tests/LocalDBLoggerTest.java

@@ -31,13 +31,13 @@ import password.pwm.config.ConfigurationReader;
 import password.pwm.config.PwmSetting;
 import password.pwm.util.Helper;
 import password.pwm.util.Percent;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.TimeDuration;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBFactory;
 import password.pwm.util.logging.LocalDBLogger;
 import password.pwm.util.logging.PwmLogEvent;
 import password.pwm.util.logging.PwmLogLevel;
+import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.stats.EventRateMeter;
 
 import java.io.File;

+ 1 - 1
pwm/servlet/tests/junit/password/pwm/tests/LocalDBStoredQueueTest.java

@@ -24,10 +24,10 @@ package password.pwm.tests;
 
 import junit.framework.TestCase;
 import password.pwm.util.Helper;
-import password.pwm.util.PwmRandom;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBFactory;
 import password.pwm.util.localdb.LocalDBStoredQueue;
+import password.pwm.util.secure.PwmRandom;
 
 import java.io.File;
 import java.util.Iterator;

+ 4 - 3
pwm/servlet/web/WEB-INF/jsp/configguide-ldapcert.jsp

@@ -1,8 +1,9 @@
 <%@ page import="password.pwm.http.bean.ConfigGuideBean" %>
 <%@ page import="password.pwm.http.servlet.ConfigGuideServlet" %>
-<%@ page import="password.pwm.util.SecureHelper" %>
 <%@ page import="password.pwm.util.StringUtil" %>
 <%@ page import="password.pwm.util.X509Utils" %>
+<%@ page import="password.pwm.util.secure.PwmHashAlgorithm" %>
+<%@ page import="password.pwm.util.secure.SecureHelper" %>
 <%@ page import="java.io.ByteArrayInputStream" %>
 <%@ page import="java.security.cert.X509Certificate" %>
 <%--
@@ -69,8 +70,8 @@
                     <div>
                         <div id="titlePane_<%=ConfigGuideServlet.PARAM_LDAP_HOST%>" style="padding-left: 5px; padding-top: 5px">
                             <% int counter=0;for (X509Certificate certificate : configGuideBean.getLdapCertificates()) {%>
-                            <% final String md5sum = SecureHelper.hash(new ByteArrayInputStream(certificate.getEncoded()), SecureHelper.HashAlgorithm.MD5); %>
-                            <% final String sha1sum = SecureHelper.hash(new ByteArrayInputStream(certificate.getEncoded()), SecureHelper.HashAlgorithm.SHA1); %>
+                            <% final String md5sum = SecureHelper.hash(new ByteArrayInputStream(certificate.getEncoded()), PwmHashAlgorithm.MD5); %>
+                            <% final String sha1sum = SecureHelper.hash(new ByteArrayInputStream(certificate.getEncoded()), PwmHashAlgorithm.SHA1); %>
                             <table style="width:100%" id="table_certificate0">
                                 <tr><td colspan="2" class="key" style="text-align: center">
                                     Certificate <%=counter%>&nbsp;<a style="font-size: smaller" href="#" id="button-showCert_<%=md5sum%>">(details)</a>

+ 1 - 1
pwm/servlet/web/public/reference/referencedoc.jsp

@@ -288,7 +288,7 @@
                     </td>
                 </tr>
                 <% } %>
-                <% final Map<PwmSettingTemplate,String> defaultValues = setting.getDefaultValueDebugStrings(true,userLocale); %>
+                <% final Map<PwmSettingTemplate,String> defaultValues = setting.getDefaultValueDebugStrings(userLocale); %>
                 <tr>
                     <td class="key" style="width: 100px">
                         Default

+ 1 - 0
pwm/servlet/web/public/resources/configStyle.css

@@ -146,6 +146,7 @@
     background-color: #e9e9e9;
     border: 1px solid black;
     border-radius: 4px;
+    color: black;
 }
 
 .changeLogKey {

+ 10 - 10
pwm/servlet/web/public/resources/js/helpdesk.js

@@ -442,19 +442,19 @@ PWM_HELPDESK.initHelpdeskSearchPage = function() {
     PWM_HELPDESK.makeSearchGrid(function(){
         PWM_MAIN.addEventHandler('username', "keyup, input", function(){
             PWM_HELPDESK.processHelpdeskSearch();
-            var userPrefs = PWM_MAIN.readLocalStorage();
-            if (userPrefs) {
-                userPrefs['helpdesk-search-inputfield'] = PWM_MAIN.getObject('username').value;
-                PWM_MAIN.writeLocalStorage(userPrefs);
+            try {
+                var helpdeskFieldUsername = PWM_MAIN.getObject('username').value;
+                sessionStorage.setItem("helpdesk_field_username",helpdeskFieldUsername);
+            } catch (e) {
+                console.log('error writing username field from sessionStorage: ' + e);
             }
         });
 
-        var userPrefs = PWM_MAIN.readLocalStorage();
-        if (userPrefs) {
-            var oldValue = userPrefs['helpdesk-search-inputfield'];
-            if (oldValue) {
-                PWM_MAIN.getObject('username').value = oldValue;
-            }
+        try {
+            var helpdeskFieldUsername = sessionStorage.getItem("helpdesk_field_username");
+            PWM_MAIN.getObject('username').value = helpdeskFieldUsername;
+        } catch (e) {
+            console.log('error reading username field from sessionStorage: ' + e);
         }
 
         if (PWM_MAIN.getObject('username').value && PWM_MAIN.getObject('username').value.length > 0) {