I use shiro in application for the authenticate. I use hashed password with a salt and I store them in my database like this :
private User createUserWithHas
As mentioned in the excellent answer https://stackoverflow.com/a/20206115/603901, Shiro's DefaultPasswordService already generates unique salts for each password.
However, there is no need to implement a custom PasswordService to add a private salt (sometimes called "pepper") to the per-user salts. Private salt can be configured in shiro.ini:
[main]
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-256
hashService.generatePublicSalt = true
# privateSalt needs to be base64-encoded in shiro.ini but not in the Java code
hashService.privateSalt = myVERYSECRETBase64EncodedSalt
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
passwordMatcher.passwordService = $passwordService
Java code for generating a matching password hash:
DefaultHashService hashService = new DefaultHashService();
hashService.setHashIterations(HASH_ITERATIONS); // 500000
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
hashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded.
hashService.setGeneratePublicSalt(true);
DefaultPasswordService passwordService = new DefaultPasswordService();
passwordService.setHashService(hashService);
String encryptedPassword = passwordService.encryptPassword("PasswordForThisUser");
The resulting hash looks like this:
$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs=
The private salt is not stored in the database, which makes it harder to crack the passwords if an adversary gains access to a database dump.
This example was created using shiro-1.2.2
Thanks to https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini for help with the syntax for shiro.ini
I change my type for the save of my salt. Now I'm using a byte[] instead of a String.
ByteSource salt = randomNumberGenerator.nextBytes(32);
byte[] byteTabSalt = salt.getBytes();
And I stock the byteTabSalt in my database.
The DefaultPasswordService implementation automatically adds a random salt to each encryptPassword call. That "public" salt will be stored within the "hashedPasswordBase64" that you receive from "encryptPassword".
Because the "public" salt is individually generated for each hashed password one cannot "simply" generate a rainbow table and brute-force all your hashed passwords at once. For each hashed password the attacker would have to generate an own, unique rainbow table because of the unique "public" salt. So far you do not need to put an extra salt into the database.
To make your stored hashed passwords even more secure you can furthermore add a "private" salt that should be stored anywhere else - as long as not in the database. By using a "private" salt you could protect the hashed passwords against a brute-force rainbow-table attack, because the attacker does not know the "private" salt and cannot gain the "private" salt from the database entries.
This is a very basic example how to create a PasswordService that utilizes a "private" salt provided as a constant string and that works as CredentialsMatcher:
public class MyPrivateSaltingPasswortService extends DefaultPasswordService
{
public MyPrivateSaltingPasswortService()
{
super();
HashService service = getHashService();
if (service instanceof DefaultHashService)
{
((DefaultHashService) service).setPrivateSalt(
new SimpleByteSource("MySuperSecretPrivateSalt"));
}
}
}
you then could use your own implementation in shiro.ini:
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
This example was created using shiro-1.2.2
Have you looked at PasswordMatcher / PasswordService?
This already has all of the encoding/decoding/compare logic built-in. To use it:
Storing password in database:
PasswordService service = new DefaultPasswordService(); // or use injection or shiro.ini to populate this
private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){
String hashedPasswordBase64 = service.encryptPassword(inPassword);
return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt);
}
Then you can simply use PasswordMatcher as the matcher in your realm.
realm.setCredentialsMatcher(new PasswordMatcher());
or in shiro.ini:
matcher = org.apache.shiro.authc.credential.PasswordMatcher
realm.credentialsMatcher = $matcher