A "Salt" is used in cryptography to make encryption more efficient making the decryption less efficient for attackers. It basically adds a layer hashing on top of your encryption algorithm. The idea is basically to hash your data+salt rather than hashing only the data, and salt is a randomly generated string. How salt adds an advantage is
- The attacker’s dictionary now needs to contain many more entries, one for each possible salt value for each probable passphrase.
- The Brute force approach taken by the attacker will take more time.
we can use various hashing strategy and add slat to make our password more secure. We are going to cover
- MD5 algorithm + salt.
- SHA algorithm.
- PBKDF2WithHmacSHA1 algorithm.
- Bcrypt algorigthms.
- Scrypt algorigthms.
Using MD5 algorithm
The MD5 Message-Digest Algorithm is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value. It’s very simple and straight forward; the basic idea is to map data sets of variable length to data sets of a fixed length. In order to do this, the input message is split into chunks of 512-bit blocks. A padding is added to the end so that it’s length can be divided by 512. Now these blocks are processed by the MD5 algorithm, which operates in a 128-bit state, and the result will be a 128-bit hash value. After applying MD5, generated hash is typically a 32-digit hexadecimal number.
The Simple MD5 java code:
package com.sachi.secure.hashing.examples;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Example {
{
String passwordToHash = "password";
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(passwordToHash.getBytes());
byte[] bytes = md.digest();
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
System.out.println(generatedPassword);
}
}
Output: 5f4dcc3b5aa765d61d8327deb882cf99import java.security.NoSuchAlgorithmException;
/**
* @param args
*/
public static void main(String[] args) {
String passwordToHash = "password";
String generatedPassword = null;
try {
md.update(passwordToHash.getBytes());
byte[] bytes = md.digest();
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
System.out.println(generatedPassword);
}
Although MD5 is a widely spread hashing algorithm, is far from being secure, MD5 generates fairly weak hashes. It's main advantages are that it is fast, and easy to implement. But it also means that it is susceptible to brute-force and dictionary attacks. Rainbow tables with words and hashes generated allows searching very quickly for a known hash and getting the original word. Also, It is not collision resistant: this means that different passwords can eventually result in the same hash
Important: We always need to use a SecureRandom to create good Salts, and in Java, the SecureRandom class supports the "SHA1PRNG" pseudo random number generator algorithm, and we can take advantage of it.SHA1PRNG algorithm is used as cryptographically strong pseudo-random number generator based on the SHA-1 message digest algorithm. Note that if a seed is not provided, it will generate a seed from a true random number generator (TRNG).
The Salted MD5 java code:
package com.sachi.secure.hashing.examples;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
{
String passwordToHash = "password";
String salt = getSalt();
System.out.println(securePassword);
System.out.println(regeneratedPassowrdToVerify);
}
{
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(salt.getBytes());
byte[] bytes = md.digest(passwordToHash.getBytes());
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return generatedPassword;
}
{
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt.toString();
}
}
Using SHA Algorithms
The SHA (Secure Hash Algorithm) is a family of cryptographic hash functions. It is very similar to MD5 except it generates more strong hashes. However these hashes are not always unique, and it means that for two different inputs we could have equal hashes. When this happens it’s called a "collision". Chances of collision in SHA is less than MD5. But, do not worry about these collisions because they are really very rare.Java has 4 implementations of SHA algorithm. They generate following length hashes in comparison to MD5 (128 bit hash):
SHA-1 (Simplest one – 160 bits Hash)
SHA-256 (Stronger than SHA-1 – 256 bits Hash)
SHA-384 (Stronger than SHA-256 – 384 bits Hash)
SHA-512 (Stronger than SHA-384 – 512 bits Hash)
package com.sachi.secure.hashing.examples;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* @param args
* @throws NoSuchAlgorithmException
*/
public static void main(String[] args) throws NoSuchAlgorithmException {String passwordToHash = "password";
String salt = getSalt();
String securePassword = get_SHA_1_SecurePassword(passwordToHash, salt);
System.out.println(securePassword);
}
private static String get_SHA_1_SecurePassword(String passwordToHash, String salt)
{
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(salt.getBytes());
byte[] bytes = md.digest(passwordToHash.getBytes());
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return generatedPassword;
}
private static String getSalt() throws NoSuchAlgorithmException
{
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt.toString();
}
Using PBKDF2WithHmacSHA1 Algorithm
From wiki , PBKDF2 (Password-Based Key Derivation Function 2) is a key derivation function that is part of RSA Laboratories' Public-Key Cryptography Standards (PKCS) series, specifically PKCS #5 v2.0, also published as Internet Engineering Task Force's RFC 2898. It replaces an earlier standard, PBKDF1, which could only produce derived keys up to 160 bits long.
PBKDF2 applies a pseudorandom function, such as a cryptographic hash, cipher, or HMAC to the input password or passphrase along with a salt value and repeats the process many times to produce a derived key, which can then be used as a cryptographic key in subsequent operations. The added computational work makes password cracking much more difficult, and is known as key stretching. When the standard was written in 2000, the recommended minimum number of iterations was 1000, but the parameter is intended to be increased over time as CPU speeds increase. Having a salt added to the password reduces the ability to use precomputed hashes (rainbow tables) for attacks, and means that multiple passwords have to be tested individually, not all at once. The standard recommends a salt length of at least 64 bits.
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
/**
* @param args
*/
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
String originalPassword = "password";
String generatedSecuredPasswordHash = generateStorngPasswordHash(originalPassword);
System.out.println(generatedSecuredPasswordHash);
}
private static String generateStorngPasswordHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException
{
int iterations = 1000;
char[] chars = password.toCharArray();
byte[] salt = getSalt().getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = skf.generateSecret(spec).getEncoded();
return iterations + ":" + toHex(salt) + ":" + toHex(hash);
}
{
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt.toString();
}
{
BigInteger bi = new BigInteger(1, array);
String hex = bi.toString(16);
int paddingLength = (array.length * 2) - hex.length();
if(paddingLength > 0)
{
return String.format("%0" +paddingLength + "d", 0) + hex;
}else{
return hex;
}
}
From wiki , BCrypt is a key derivation function for passwords designed by Niels Provos and David Mazières, based on the Blowfish cipher, and presented at USENIX in 1999.[1] Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.
package com.sachi.secure.hashing.examples;
import java.security.NoSuchAlgorithmException;
public class BCryptImpl {
/**
* @param args
*/
public static void main(String[] args) throws NoSuchAlgorithmException {
String originalPassword = "IAMTestIng";
String generatedSecuredPasswordHash = BCrypt.hashpw(originalPassword, BCrypt.gensalt(12));
System.out.println(generatedSecuredPasswordHash);
System.out.println(matched);
}
}
OUTPUT:
$2a$12$yhDrmY5dT7DhneT5bJxY1eTheNmc.Hjk9b39l2Hc4ZYtMaIUZ1m9i
true
Using SCrypt Algorithm
From Wiki, In cryptography scrypt is a password-based key derivation function created by Colin Percival, originally for the Tarsnap online backup service. The algorithm was specifically designed to make it costly to perform large scale custom hardware attacks by requiring large amounts of memory. In 2012, the scrypt algorithm was published by IETF as an Internet Draft, on track to becoming an informational RFC
public class ScryptImpl
{
public static void main(String[] args) {
String originalPassword = "password";
String generatedSecuredPasswordHash = SCryptUtil.scrypt(originalPassword, 16, 16, 16);
System.out.println(generatedSecuredPasswordHash);
System.out.println(matched);
System.out.println(matched);
}
}
true
false
References
- http://en.wikipedia.org/wiki/Scrypt
- https://github.com/wg/scrypt
- https://github.com/Hellblazer/jbcrypt
- http://en.wikipedia.org/wiki/Bcrypt
- https://en.wikipedia.org/wiki/MD5
- https://en.wikipedia.org/wiki/Secure_Hash_Algorithm
- http://en.wikipedia.org/wiki/PBKDF2
- http://www.mindrot.org/projects/jBCrypt/
No comments:
Post a Comment