Encrypt Password in Configuration Files

Encrypt Password in Configuration Files?

A simple way of doing this is to use Password Based Encryption in Java. This allows you to encrypt and decrypt a text by using a password.

This basically means initializing a javax.crypto.Cipher with algorithm "AES/CBC/PKCS5Padding" and getting a key from javax.crypto.SecretKeyFactory with the "PBKDF2WithHmacSHA512" algorithm.

Here is a code example (updated to replace the less secure MD5-based variant):

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class ProtectedConfigFile {

public static void main(String[] args) throws Exception {
String password = System.getProperty("password");
if (password == null) {
throw new IllegalArgumentException("Run with -Dpassword=<password>");
}

// The salt (probably) can be stored along with the encrypted data
byte[] salt = new String("12345678").getBytes();

// Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers
int iterationCount = 40000;
// Other values give me java.security.InvalidKeyException: Illegal key size or default parameters
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(),
salt, iterationCount, keyLength);

String originalPassword = "secret";
System.out.println("Original password: " + originalPassword);
String encryptedPassword = encrypt(originalPassword, key);
System.out.println("Encrypted password: " + encryptedPassword);
String decryptedPassword = decrypt(encryptedPassword, key);
System.out.println("Decrypted password: " + decryptedPassword);
}

private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
SecretKey keyTmp = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(keyTmp.getEncoded(), "AES");
}

private static String encrypt(String property, SecretKeySpec key) throws GeneralSecurityException, UnsupportedEncodingException {
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters parameters = pbeCipher.getParameters();
IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"));
byte[] iv = ivParameterSpec.getIV();
return base64Encode(iv) + ":" + base64Encode(cryptoText);
}

private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}

private static String decrypt(String string, SecretKeySpec key) throws GeneralSecurityException, IOException {
String iv = string.split(":")[0];
String property = string.split(":")[1];
Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
}

private static byte[] base64Decode(String property) throws IOException {
return Base64.getDecoder().decode(property);
}
}

One problem remains: Where should you store the password that you use to encrypt the passwords? You can store it in the source file and obfuscate it, but it's not too hard to find it again. Alternatively, you can give it as a system property when you start the Java process (-DpropertyProtectionPassword=...).

The same issue remains if you use the KeyStore, which also is protected by a password. Basically, you will need to have one master password somewhere, and it's pretty hard to protect.

What is a good alternative to putting passwords in config files?

You can actually encrypt sections of your config files. it's not "separate" from the config file as you asked about in your question, but it is more secure than storing the unencrypted/plaintext passwords in your config file.

Example to encrypt the connection strings (from command prompt):

aspnet_regiis -pe "connectionStrings" -app "/SampleApplication" -prov "RsaProtectedConfigurationProvider"

Note that this same technique can be applied to sections aside from connection strings.

See the tutorial at: https://msdn.microsoft.com/en-us/library/zhhddkxy%28v=vs.140%29.aspx

To decrypt and encrypt a section of the Web.config file, the ASP.NET process must have permission to read the appropriate encryption key information. For more information, see Importing and Exporting Protected Configuration RSA Key Containers.

The application will be able to use the encrypted values natively, but if a user had access to the config file say via a fileshare, the strings would still be encrypted.

Another tutorial which might have some additional info:
http://www.codeproject.com/Tips/795135/Encrypt-ConnectionString-in-Web-Config

Note that encryption is reversible with the appropriate key. Your safest bet would be to lock down remote and share access to the area where the config file is stored. Without either of these, your config file shouldn't even be accessible to anyone but administrators to the server.

Cannot encrypt password in configuration file

This is not the proper way to do it but solves.

StandardPBEStringEncryptor encryptor =new StandardPBEStringEncryptor();
encryptor.setPassword("somePass");
encryptor.setAlgorithm("PBEWITHMD5ANDDES");
Configuration configuration = new Configuration().configure();
String pass=encryptor.decrypt(configuration.getProperty("hibernate.connection.password"));
configuration.setProperty("hibernate.connection.password",pass);

And in hibernate.cfg

    <property name="connection.username">sa</property>
<property name="connection.password">Nzuyhu5PJJwsVH3mdw==</property>

Encrypt password in App.config

Lets say this is your connection string:

<connectionStrings>
<add name="cs" connectionString="Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=XXSDFASFDKSFJDKLJFDWERIODFSDFHSDJHKJNFJKSD;"/>
</connectionStrings>

Then you can do something like this:

string myCs = System.Configuration.ConfigurationManager.ConnectionStrings["cs"].ConnectionString;

System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder(myCs);
csb.Password = EncDecHelper.Decrypt(csb.Password);
myCs = csb.ToString();

You can write EncDecHelper.Decrypt by using samples from here: Encrypt and decrypt a string

Securing a password in a properties file

Sample Image

Jasypt provides the org.jasypt.properties.EncryptableProperties class for loading, managing and transparently decrypting encrypted values in .properties files, allowing the mix of both encrypted and not-encrypted values in the same file.

http://www.jasypt.org/encrypting-configuration.html

By using an org.jasypt.properties.EncryptableProperties object, an
application would be able to correctly read and use a .properties file
like this:

datasource.driver=com.mysql.jdbc.Driver 
datasource.url=jdbc:mysql://localhost/reportsdb
datasource.username=reportsUser
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)

Note that
the database password is encrypted (in fact, any other property could
also be encrypted, be it related with database configuration or not).

How do we read this value? like this:

/*
* First, create (or ask some other component for) the adequate encryptor for
* decrypting the values in our .properties file.
*/
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("jasypt"); // could be got from web, env variable...
/*
* Create our EncryptableProperties object and load it the usual way.
*/
Properties props = new EncryptableProperties(encryptor);
props.load(new FileInputStream("/path/to/my/configuration.properties"));

/*
* To get a non-encrypted value, we just get it with getProperty...
*/
String datasourceUsername = props.getProperty("datasource.username");

/*
* ...and to get an encrypted value, we do exactly the same. Decryption will
* be transparently performed behind the scenes.
*/
String datasourcePassword = props.getProperty("datasource.password");

// From now on, datasourcePassword equals "reports_passwd"...

Ruby encrypting passwords to be stored in config file

For encryption you can also use the bcrypt gem which is widely used and practical to use. Make sure you have bcrypt installed on your system otherwise the gem won't work.

To see how it works check out its Readme, especially the How to use bcrypt-ruby in general section.



Related Topics



Leave a reply



Submit