-
Notifications
You must be signed in to change notification settings - Fork 1
Password Encryption
Historically, configuration files supported either clear text or base64-encoded passwords.
There was an optional property (*.password.isplaintext) that specified how passwords were written in the configuration file: *.password.isplaintext=true declared the password with the same prefix as plain text, *.password.isplaintext=false declared the password as base64-encoded.
If *.password.isplaintext was omitted, ConfigurationManager tried to deduce whether the password was plain text or base64-encoded, but there is no way to do this with 100% certainty for all passwords.
How ambiguous passwords were interpreted if *.password.isplaintext was omitted depended on which version of Common Framework was used (that behavior changed over time).
Starting with Common Framework 1.4.4, each password is either plain text, or DES encrypted + Ascii85-encoded. Password encryption works as follows: *.password.isencrypted missing means: encrypt this password. *.password.isencrypted=true means: this password is already encrypted. *.password.isencrypted=false means: do not encrypt this password Users will enter plain text passwords into the config file, and the utility will automatically replace them in-place with encrypted passwords (setting the new *.password.isencrypted property to true as it does it) unless it finds *.password.isencrypted=false.
When creating a new config file, the user enters the plain text password in the value of the *.password property.
Note: If no encryption is wanted, insert: *.password.isencrypted=false.
To change a password, the user changes the *.password value to the plain text password. If he wants the password to be automatically encrypted, he removes the *.password.isencrypted property. If he wants the password to be left in plain text, he sets *.password.isencrypted=false. All password properties must be of the pattern *.password. All properties of the form *.password must be passwords that are subject to these encryption rules.
Must consist only of ASCII characters exclamation point('!', 0x21) through tilde ('~', 0x7e). Minimum length: 1 Maximum length: 64
Legacy configuration files are handled as follows: *.password.isplaintext=true means the password is plain text *.password.isplaintext=false means the password is base64-encoded (which is now an obsolete representation) *.password.isplaintext missing means the password is plain text (at least that's what we'll assume). In this scenario, if the password looks like it might be base64-encoded, a warning is written to the log by ConfigurationPassword.
The property *.password.isplaintext, if present, will determine whether the utility reads the password as plain text (true) or base64-encoded (false). If isplaintext=true was present, the password will be left in plain text, and the isplaintext property will be replaced with isencrypted=false. The property *.password.isplaintext will be removed automatically. Once this property is removed, the config file is no longer considered a legacy file.
If the property *.password.isplaintext is missing, then the config file is treated as a non-legacy file, handled as described above. For plain text passwords, this will work fine. For base64 encoded passwords, this will produce an invalid encrypted password. When a utility encounters a non-encrypted password that matches the base64-encoded pattern, it will write a warning to the log which should make it easier to troubleshoot this scenario. All *.password.isplaintext properties will be removed. If it does not exist, the isencrypted property will be inserted. *.password.isencrypted properties are not automatically modified.
The password encryption / decryption feature has been tested on Oracle JVMs only. Correct operation on IBM JVMs cannot be guaranteed at this time. If you are running on an IBM JVM, and you receive an error encrypting/decrypting passwords, you can change the passwords to plain text and set .password.isencrypted=false to avoid the need to encrypt or decrypt.
The "standard passwords" protex.password and cc.password are decrypted by ConfigurationManager, so client code does not need to change for these. The most common way to support additional passwords in a client utility is to use code like this in the ConfigurationManager subclass:
import soleng.framework.core.config.ConfigurationPassword;
// Read the value of protex.db.password
ConfigurationPassword configurationPassword = ConfigurationPassword.createFromProperty(getProps(), "protex.db");
// if it is an optional property, use a test like this to test to see if the property was set or not
if (configurationPassword.getPlainText() != null) {
// get the plain text value of the password (even if it was encrypted in the property file)
protexDbPassword = configurationPassword.getPlainText();
}
}
There should be no need for end users to encrypt or decrypt passwords manually. Users will enter plain text passwords, and the utility will automatically encrypt those passwords if the user wants them encrypted. However, developers working on the SCM Connector utility do sometimes have a need to manually encrypt and decrypt passwords during testing. For this, crude encrypt/decrypt utilities are provided in the PasswordDecrypterTool and PasswordEncrypterTool unit tests.
Some relevant classes:
- Configuration information is (still) managed by soleng.framework.core.config.ConfigrationManager.
- Configuration file reading/writing is now delegated by ConfigurationManager to soleng.framework.core.config.ConfigurationFile.
- A password property and its associated meta-properties are managed by soleng.framework.core.config.ConfigurationPassword.
- Password encryption, decryption, encoding, and decoding are performed via static methods in soleng.framework.core.encryption.Password
- They KeyStore files Sun-Key.jceks (for standard JVMs) and IBK-Key.jceks (for IBM JVMs) are in the common-framework jar file, and are found by Password via the classpath.
- The key file password is the value of KEY_PASSWORD_STRING in soleng.framework.core.encryption.Password.java.
- Encryption algorithm: DES
- Encryption mode: ECB
- Encryption padding: NoPadding
The method Base64.isBase64() has been used for some time in Common Framework, but Common Framework 1.4.4 (and later) calls Base64.isBase64() under different circumstances than earlier versions did. It is possible to have had a dependency version conflict over the apache commons-codec library that was not noticed before upgrading to Common Framework 1.4.4 (because Base64.isBase64() was not called) that becomes noticeable upon upgrading to Common Framework 1.4.4 (because now Base64.isBase64() is called. Base64.isBase64() was added in version apache commons-codec version 1.5, so this version conflict can occur in utilities that have an indirect dependency (such as through apache POI) on an older version of commons-codec.
A temporary workaround is to, for each password in the config file, do either of the following:
- If you want the password stored as plain text: Change the password to plain text, and include the .password.isencrypted=false property.
- If you want the password encrypted: Change the password to its base64-encoded value, and include the .password.isplaintext=false property.
The solution is to modify the utilities pom.xml to force it to build with Common Framework's commons-codec dependency.