Symfony FOSUser Hash algorithm in java - java

hey everyone am trying to find out which algorithm of hash is used my symfony FOS User Bundle I've done some research , and it's mentioned that FOSUser Bundle default security config uses Sha512() and itirate it over 5000 times + salt then bas64 encoding i'm actually new with these hash algorithms ,however this is the algorithm in php
$password = 'toto';
$salt = '1234';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
for ($i=1; $i<5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encodedPassword = base64_encode($digest);
}
taking from this post How do I generate a SALT in Java for Salted-Hash?
since am not familiar with java hash libraries can anyone help me how to translated this code into Java !

The solution is to use a Java API that encode the password like the MessageDigestPasswordEncoder:
Generate a salt (lenght=43):
private static String generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_SIZE];
random.nextBytes(salt);
String saltBase64_encoded=BaseEncoding.base64().encode(salt);
String saltPlusDot= saltBase64_encoded.replace("+",".");
return saltPlusDot.substring(0,saltPlusDot.length()-1);
}
BaseEncoding.base64() is a class in commons-codec api
concat: password + { + salt + }:
private static String mergePasswordAndSalt(String pass, String salt) {
if (salt == null) {
return salt;
}
String cg="{";String cd="}";
return pass+cg+salt+cd;
}
For each additional iteration: hash the concat of previous digest +
salt:
private static byte[] encodePassword(String password,String salt)
throws NoSuchAlgorithmException,UnsupportedEncodingException {
String mergedPasswordAndSalt =mergePasswordAndSalt(password, salt);
MessageDigest digester = MessageDigest.getInstance(ALGORITHM);
byte[] hash = digester.digest(mergedPasswordAndSalt .getBytes("UTF-8"));
for (int i = 1; i < ITERATIONS; ++i) {
hash = digester.digest(Bytes.concat(hash, mergedPasswordAndSalt.getBytes("UTF-8")));
}
return hash;
}
Bytes.concat(bytes ...) is a method in guava 19.0 api
This is the API in github FOSJcrypt

Symfony default setting for password encryption is Bcrypt this code mentioned in your security.yml config file
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 15
in my case i used a trick since all my password start with 13 am assuming that the salt equals to 13
so i tried translating it into java by using the java BCrypt library
public boolean checkPassword(String passwordText, String DbHash) {
boolean password_verified = false;
if (null == DbHash || !DbHash.startsWith("$2a$")) {
throw new java.lang.IllegalArgumentException("Invalid hash provided for comparison");
}
password_verified = BCrypt.checkpw(passwordText, DbHash);
return (password_verified);
}
passwordText you actual password , DbHash stored hash
This code check a password hash if password match or not
there's a trick symfony hashed password start with $2y$ so to make this work you need to need change $2y$ to $2a$
for exemple i have password with a hash value that is stored in my database
String passwordText = "admin";
String DbHash = "$2y$13$VVmaKXzaS2QWgU1S4I8h5eJgC/DduF2fXmnhvcynro004GCUAQfr2";
change this :
String DbHash = "$2y$13$VVmaKXzaS2QWgU1S4I8h5eJgC/DduF2fXmnhvcynro004GCUAQfr2";
to this :
String DbHash = "$2a$13$VVmaKXzaS2QWgU1S4I8h5eJgC/DduF2fXmnhvcynro004GCUAQfr2";

Related

How do I compare salt with a generated password?

So I'm trying to compare my original password to a password that was salted. I know how to compare a hash password, I take the original password add hash to it and it works. However, I don't know how to compare the salt.
public static String saltPassword(String password) throws NoSuchAlgorithmException{
String salt = getSalt();
return password + salt;
}
public static String getSalt(){
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return Base64.getEncoder().encodeToString(saltBytes);
}
What do I have to do to compare the original password with this?
this is literally what my assignment says,
"Compare the generated password with the stored salt and hashed password".
You should also store the salt. Salt is used to prevenet generating the same hashed password when two user choose same password. something like the following codes can be used for saving password as hashedPassord and verifying entered password.It's not complete but can be used as a sample code.
private static void savePassword(String rawPassword) throws InvalidKeySpecException, NoSuchAlgorithmException {
byte[] salt = getSalt();
String hashedPassword = getHashedPassword(rawPassword, salt);
String encodedSalt = base64Encode(salt);
/* todo: store hashPassword and encodedSalt */
}
private static boolean verifyPassword(String rawPassword, String hashedPassword, String encodedSalt) throws InvalidKeySpecException, NoSuchAlgorithmException {
return Objects.equals(hashedPassword, getHashedPassword(rawPassword, base64Decode(encodedSalt)));
}
private static String getHashedPassword(String rawPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(rawPassword.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] hash = factory.generateSecret(spec).getEncoded();
return base64Encode(hash);
}
private static byte[] getSalt() {
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return saltBytes;
}
private static String base64Encode(byte[] src) {
return Base64.getEncoder().encodeToString(src);
}
private static byte[] base64Decode(String src) {
return Base64.getDecoder().decode(src);
}
Ok here is what i have. I would love to look up a stored password but my teacher is not doing it that way in her solution video
public static String saltPassword(String password) throws NoSuchAlgorithmException{
String salt = getSalt();
return hashPassword(password + salt);
}
public static String getSalt(){
Random r = new SecureRandom();
byte[] saltBytes = new byte[32];
r.nextBytes(saltBytes);
return Base64.getEncoder().encodeToString(saltBytes);
}
public static String generatePassword(){
String charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-+!##$%";
String password = "";
int start = 0;
int stop = 0;
int minLength = 8;
for (int i = 0; i <= minLength; i++) {
// get a random character from the chars string
start = getRandomNumber(charSet.length());
stop = start + 1;
password += charSet.substring(start, stop);
}
return password;
}
private static int getRandomNumber(int maxValue){
double randomNumber;
randomNumber = Math.floor(Math.random() * maxValue);
return (int)randomNumber;
}
public static String hashPassword(String password)throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte[] mdArray = md.digest();
StringBuilder sb = new StringBuilder(mdArray.length * 2);
for (byte b : mdArray){
int v = b & 0xff;
if(v < 16){
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString();
}
Then to create it I am going to go
String newPassword = PasswordUtil.generatePassword();
String hashedPassword = "";
String saltedPassword = "";
try{
hashedPassword = PasswordUtil.hashPassword(newPassword);
}
catch(NoSuchAlgorithmException e){
System.out.println();
}
try{
saltedPassword = PasswordUtil.saltPassword(hashedPassword);
}
catch(NoSuchAlgorithmException e) {
System.out.println();
}
What happens next?
this is the hashed password:
50f99d2a635cc9bac7e001506789b55a7c603d93c89d362cc5d95ab257fc2666
and this is the hash with the salt
e954fbc2309cc359cd603effb6d0644947a3253110ad6c3b2416dd49168331a3
How do I compare salt with a generated password?
What do I have to do to compare the original password with this?
The answer is that you don't do either if these things.
To register the original password you do the following:
Obtain a salt1
Combine the original password with the salt
Hash that.
Store the salt and the hash.
You then discard the original password.
To check that a supplied password you do the following:
Lookup the stored hash and the corresponding salt that were created when registering; see above.
Combine the supplied password and salt in the same way as above.
Hash that as above.
Compare the resulting hash with the stored hash. If they are the same, then the supplied password is the correct password.
As you can see, you don't compare either the salt or the original password with anything.
But it is also essential that you use the same salt when generating the hashes for the original password and the password that you are checking. If you don't, the password check doesn't work.
1 - The salt is just a number or string. Ideally the salt values should be different. The purpose of the salt is to avoid a so-called "rainbow table" attack to recover the original password from a stolen (un-salted) password hash. If there are (say) a million possible salt values, then the bad guys need to generate a million different rainbow tables. Generating and storing many rainbow tables becomes impractical.

Hashing vulnerability

I want to add some security to my project so I added a password field. In, order to store the password I was going to use a txt and save it in there, to add a bit more security I used the below code to hash the password(theirs more than one password saved this way if that's important). This is just and example of how I have done the hashing, the actual program uses text files etc.
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println("Enter Password: ");
Scanner scanner = new Scanner(System.in);
String enteredPassword = scanner.nextLine();
String storedPassword = "�D�Ϛ-�UK�c�=�,�}��}��D��Zj>�m";
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(enteredPassword.getBytes());
String hashedString = new String(messageDigest.digest());
System.out.println(hashedString);
if(storedPassword.equals(hashedString)){
System.out.println("Passwords Match!");
}else{
System.out.println("Passwords Do Not Match!");
}
}
My question is am I doing this securely, besides decompiling my project and bypassing this feature is my project secure or can this method be exploited? Also, is there a way to secure a project against being decompiled and the code re-written to bypass security features?? Thank You
The approach itself is good; SHA-256 by itself is a strong, one-way hashing function. It cannot be "decrypted". But it's fast, thus allowing rapid brute-forcing of the password using a dictionary.
For better security you can slow things down with e.g. bcrypt or PBKDF2. Some 100ms will not be noticeable by the user, but makes brute-forcing impractical.
Here's an example with PBKDF2 using 100000 iterations of SHA-256. It also uses a random salt.
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec("my-secret-password".toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
System.out.printf("salt: %s%n", enc.encodeToString(salt));
System.out.printf("hash: %s%n", enc.encodeToString(hash));
Note: PBKDF2WithHmacSHA256 is available since Java 8.
Here's a more complete example:
private static final SecureRandom random = new SecureRandom();
/**
* One-way encrypts (hashes) the given password.
*
* #param saltpw the salt (will be generated when null)
* #param pw the password to encrypt
* #return encrypted salted password
*/
public static String encrypt(String saltpw, String pw) throws GeneralSecurityException {
byte[] salt;
if (saltpw == null) {
salt = new byte[16];
random.nextBytes(salt);
} else {
salt = Base64.getDecoder().decode(saltpw.replaceFirst("\\$.*", ""));
}
KeySpec spec = new PBEKeySpec(pw.toCharArray(), salt, 100000, 256);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = f.generateSecret(spec).getEncoded();
Base64.Encoder enc = Base64.getEncoder();
return enc.encodeToString(salt) + "$" + enc.encodeToString(hash);
}
public static void main(String[] args) throws Exception {
String enc = encrypt(null, "my-secret-password");
System.out.printf("enc : %s\n", enc);
String test1 = encrypt(enc, "my-secret-password");
System.out.printf("test 1: %s, valid: %b\n", test1, enc.equals(test1));
String test2 = encrypt(enc, "some-other-password");
System.out.printf("test 2: %s, valid: %b\n", test2, enc.equals(test2));
}
Prints:
enc : B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=
test 1: B5V6SjkjJpeOxvMAkPf7EA==$NNDA7o+Dpd+M+H99WVxY0B8adqVWJHZ+HIjgPxMljwo=, valid: true
test 2: B5V6SjkjJpeOxvMAkPf7EA==$4H1SpH8N+/jqU40G6RWb+ReHUB3C58iAaU4l39j+TV8=, valid: false
Notice how test 1 results in exactly the same encrypted string as the original password, and that test 2 (with a wrong password) doesn't. So that's how you can verify that the provided password is valid or not, by just comparing the hashes.
There is no way to prohibit decompiling of java.
But you can make it hard to understand the decompiled code if you use an obfuscator.
E.g. https://www.guardsquare.com/en/products/proguard
This changes all you method-, class-, variable- names to meaningless short names.
A side-effect is that your class file will shrink too.

Android Apache Codecs Base64 Error

I'm trying to implement a more advanced password hashing algorithm (PBKDF2) that uses the Base64 class that is found in the java util library, but since this class is outdated I need to get the Apache Codecs library that supports the updated Base64 class. The amazing thing is that on a normal java class this works flawlessly, but when I use the same piece of code in an android activity it gives me an error saying that the method that I'm trying to call from Base64 does not exist!
I think the problem here is that in the activity, the Base64 is called from the util library that has the outdated version of Base64.
Here is an example of the code.
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;
public class Password {
// The higher the number of iterations the more
// expensive computing the hash is for us and
// also for an attacker.
private final int iterations = 20 * 1000;
private final int saltLen = 32;
private final int desiredKeyLen = 256;
/**
* Computes a salted PBKDF2 hash of given plaintext password
* suitable for storing in a database.
* Empty passwords are not supported.
*/
public String getSaltedHash(String password) throws Exception {
byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen);
// store the salt with the password
return Base64.encodeBase64String(salt) + "$" + hash(password, salt);
}
/**
* Checks whether given plaintext password corresponds
* to a stored salted hash of the password.
*/
public boolean check(String password, String stored) throws Exception {
String[] saltAndPass = stored.split("\\$");
if (saltAndPass.length != 2) {
throw new IllegalStateException(
"The stored password have the form 'salt$hash'");
}
String hashOfInput = hash(password, Base64.decodeBase64(saltAndPass[0]));
return hashOfInput.equals(saltAndPass[1]);
}
// using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt
// cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html
private String hash(String password, byte[] salt) throws Exception {
if (password == null || password.length() == 0)
throw new IllegalArgumentException("Empty passwords are not supported.");
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey key = f.generateSecret(new PBEKeySpec(
password.toCharArray(), salt, iterations, desiredKeyLen)
);
return Base64.encodeBase64String(key.getEncoded());
}
public static void main(String[] args) throws Exception {
Password passwordHash = new Password();
String password = passwordHash.getSaltedHash("password");
String password2 = passwordHash.getSaltedHash("password");
System.out.println("P1-HASH: " + password);
System.out.println("P2-HASH: " + password2);
System.out.println(passwordHash.check("password", password2));
}
}
The method seems to be called encodeToString. I really don't know where you found your particular method, but it isn't documented; I think you were just referring to the wrong class.

Similar sha512 of php for android password login

I have my php application where when I created the user I ran this.
$random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
// Create salted password
$userPwd = hash('sha512', $userPwd . $random_salt);
Next when I try to login upon the having captured the password I hash via this javascript
p.value = hex_sha512(userPwdControl.value);
Then in the ran this
$hashPassword = hash('sha512', $userPassword . $row1['userSalt']);
All above codes works via php.
Now via my android I want to do this function p.value = hex_sha512(userPwdControl.value); to get the hash and I am trying out first via java codes as below. But I got empty results below.
StringBuffer stringBuffer = new StringBuffer();
try {
String message = "myPass";
MessageDigest digest = MessageDigest.getInstance("512");
byte[] hashedBytes = digest.digest(message.getBytes("UTF-8"));
for (int i = 0; i < hashedBytes.length; i++) {
stringBuffer.append(Integer.toString((hashedBytes[i] & 0xff) + 0x100, 16)
.substring(1));
}
stringBuffer.toString();
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
}
System.out.println("TEST :"+stringBuffer);
Can you try the code below. Did some minor changes in your code.
String resultString = "";
try {
byte[] buffer = password.getBytes();
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(buffer);
byte[] digest = md.digest();
for(int i = 0 ; i < digest.length ; i++) {
int b = digest[i] & 0xff;
if(Integer.toHexString(b).length() == 1)
resultString = resultString + "0";
resultString = resultString + Integer.toHexString(b);
}
} catch(NoSuchAlgorithmException e) {
e.printStackTrace();
}
Your problem seems to be solved already, but I would strongly recommend to switch to a more safe hashing algorithm. A single SHA-512 cannot protect your users passwords because it is way too fast (1 Giga SHA-512 per second) and therefore can be brute-forced too easily.
What you need, is hash function with a cost factor, like BCrypt, PBKDF2 or SCrypt. PHPs function password_hash() currently implements BCrypt, a compatible implementation you can get with jBCrypt.

How should I convert this java DES program to PHP?

I have a DES Algorithm use java ,now I need convert this java program for php, I don't know java cipher.init method's third parameters SecureRandom ,So I use my php Des program to encrypt a string ,but I got a different result with java Des.
Here is my Java DES:
public static String encode(String srcStr) {
if (srcStr == null)
return null;
String dst = null;
byte[] result = encrypt2(srcStr.getBytes(), "h43au76U");
if (result == null)
return null;
System.out.println(result);
dst = byte2HexStr(result, result.length);
return dst;
}
private static final char[] mChars = "0123456789ABCDEF".toCharArray();
public static String byte2HexStr(byte[] b, int iLen) {
if (b == null)
return null;
StringBuilder sb = new StringBuilder();
for (int n = 0; n < iLen; n++) {
sb.append(mChars[(b[n] & 0xff) >> 4]);
sb.append(mChars[b[n] & 0xf]);
}
return sb.toString().trim().toUpperCase(Locale.US);
}
private static byte[] encrypt2(byte[] datasource, String password) {
byte[] is;
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes("UTF-8"));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
javax.crypto.SecretKey securekey
= keyFactory.generateSecret(desKey);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(1, securekey, random);
is = cipher.doFinal(datasource);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
return is;
}
And this is my php des:
function encrypt($input,$key,$iv=0){
$size = mcrypt_get_block_size(MCRYPT_DES,MCRYPT_MODE_CBC); //3DES加密将MCRYPT_DES改为MCRYPT_3DES
$input =pkcs5_pad($input, $size); //如果采用PaddingPKCS7,请更换成PaddingPKCS7方法。
$td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_CBC, '');
#mcrypt_generic_init($td, $key,$iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
// return $data;
return strtoupper(bin2hex($data));
}
I got a different result, why? And I don't know if SecureRandom is a iv ?
Always use a fully qualified Cipher string. Cipher.getInstance("DES"); may result in different ciphers depending on the default security provider. It most likely results in "DES/ECB/PKCS5Padding", but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs.
What you need to do in PHP to achieve compatibility with Java is to use ECB mode instead of CBC mode and apply PKCS#5 padding (same as PKCS#7 padding). This answer shows an implementation of that padding. You just have to use the correct block size which is 8 for DES.
Never use ECB mode. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.
The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.
public static function encryptDes($data, $key)
{
$paddedData = static::pad($data);
$opts = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA;
return strtoupper(bin2hex(openssl_encrypt($paddedData, 'DES-ECB', $key, $opts)));
}
public static function decryptDes($data, $key)
{
$data = hex2bin($data);
$opts = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA;
return static::unpad(openssl_decrypt($data, 'DES-ECB', $key, $opts));
}
private static function pad($text)
{
$blockSize = 8;
$length = strlen($text);
$pad = $blockSize - ($length % $blockSize);
return str_pad($text, $length + $pad, chr($pad));
}
private static function unpad($text)
{
$length = ord($text[strlen($text) - 1]);
return substr($text, 0, -$length);
}

Categories