Alpha2k
Alpha2k

Reputation: 2241

Base64 Linux and Windows

Given this string: ÑIóÝ7áÔtV†°dvÔ抄!Ï­=4à)µ Å!Úã̓¸§cî£ÖošaUÕÝ€÷÷p³6ò¥ˆa, generated with SecureRandom with the next method:

public String getSalt() throws UnsupportedEncodingException {
    String salt = null;

    SecureRandom random = new SecureRandom();
    byte[] saltArr = new byte[64];
    random.nextBytes(saltArr);

    salt = new String(saltArr).trim();

    return salt;
}

TLDR: scroll to bottom

Then the returned string is "formated" to avoid special characters:

String salt = getSalt();
salt = salt.replace("<", "!");
salt = salt.replace(">", "!");
salt = salt.replace("\"", "!");
salt = salt.replace("'", "!");
salt = salt.replace("\\", "!");
salt = salt.replace("&", "!");

Encoding the salt:

public String getEncryptedSalt(String chain) throws UnsupportedEncodingException {
    byte[] bytes = chain.getBytes();
    byte[] encodedBytes = Base64.encodeBase64(bytes);
    String salt = new String(encodedBytes);

    return salt;
}

Decoding the salt:

public String getDecryptedSalt(String chain) throws UnsupportedEncodingException {
    byte[] bytes = chain.getBytes();
    byte[] decodedBytes = Base64.decodeBase64(bytes);
    String decrypted = new String(decodedBytes);

    return decrypted;
}

Hashing the password (decoded salt+pwd):

public String getHash(String target) throws NoSuchAlgorithmException {
    MessageDigest sh = MessageDigest.getInstance("SHA-512");
    sh.update(target.getBytes());
    StringBuilder sb = new StringBuilder();
    for (byte b : sh.digest()) {
        sb.append(Integer.toHexString(0xff & b));
    }

    return sb.toString();
}

Why am I getting different results on the same string (above) on different OS?

Code sample:

 String salt = "ÑIóÝ7áÔtV†°dvÔ抄!Ï­=4à)µ Å!Úã̓¸§cî£ÖošaUÕÝ€÷÷p³6ò¥ˆ`a,";
 String encodedSalt = getEncryptedSalt(salt);
 String decodedSalt = getDecryptedSalt(encodedSalt);
 String pwd = "AbcD12345";
 String hashed = getHash(salt+pwd);

Windows sample:

 SALT: ÑIóÝ7áÔtV†°dvÔ抄!Ï­=4à)µ Å!Úã̓¸§cî£ÖošaUÕÝ€÷÷p³6ò¥ˆ`a, 
 SALT ENCODED: 0Unz3TfhAx3UdFaGsGR21OaKhCHPrT004Cm1IBnFIdrjzYO4p2Puo9ZvmmFV1RndgPcb93CzAgg28qWIYGEDLA== 
 SALT DECODED: ÑIóÝ7áÔtV†°dvÔ抄!Ï­=4à)µ Å!Úã̓¸§cî£ÖošaUÕÝ€÷÷p³6ò¥ˆ`a, 

 PWD: AbcD12345 
 SALT+PWD: b0d87c79895a59bb52227eaf4aac01437676c3494a5493690c87b76efbe260e41082b6c53d811e8de4c612142eca82b970d6bba42e71cc90efa26c74e08155 

Linux - Debian7 sample:

 SALT: ÑIóÝ7áÔtV†°dvÔ抄!Ï­=4à)µ Å!Úã̓¸§cî£ÖošaUÕÝ€÷÷p³6ò¥ˆ`a, 
 SALT ENCODED: w5FJw7PDnTfDoQMdw5R0VuKAoMKwZHbDlMOmxaDigJ4hw4/CrT00w6ApwrUgGcOFIcOaw6PDjcaSwrjCp2PDrsKjw5ZvxaFhVcOVGcOd4oKsw7cbw7dwwrMCCDbDssKly4ZgYQMs 
 SALT DECODED: ÑIóÝ7áÔtV†°dvÔ抄!Ï­=4à)µ Å!Úã̓¸§cî£ÖošaUÕÝ€÷÷p³6ò¥ˆ`a, 

 PWD: AbcD12345 
 SALT+PWD: e0c31f603f36a6d1c5db1a64ebe01bbc3d51f0544d319535bbf8c345a1b7fe2fb68a98d1175a98eedf26e1a441528583a4cc285954e26a56f9d23d7174ea2 

Even tough the salt is the same on both systems, the encoded salts are different but the decoded salts are the same, why? Why does this affect the password if its only a string sum of salt+password?

PD: the least I dont understand is that: the salt and pwd are saved in a MySQL database. If I create a user in Windows then export the database to Linux he wont be able to authenticate due to incorrect password. But if then I create a user in Linux and export the database to Windows he will be able to authenticate...

Upvotes: 0

Views: 2354

Answers (2)

Alpha2k
Alpha2k

Reputation: 2241

Changed the salt from:

public String getSalt() throws UnsupportedEncodingException {
String salt = null;

SecureRandom random = new SecureRandom();
byte[] saltArr = new byte[64];
random.nextBytes(saltArr);

salt = new String(saltArr).trim();

return salt;
}

To

public String getSalt() throws UnsupportedEncodingException {
    return new BigInteger(130, new SecureRandom()).toString(32);
}

Less complex but less errors.

Upvotes: 0

Jesper
Jesper

Reputation: 206856

You are using new String(bytes) in a number of places. This will interpret the bytes and convert them to characters using the default character encoding of your system.

The default character encoding on Windows is different from the default character encoding on Linux, therefore the results will be different.

Avoid using the default character encoding; specify the character encoding explicitly. For example:

salt = new String(saltArr, "UTF-8").trim();

String salt = new String(encodedBytes, "UTF-8");

String decrypted = new String(decodedBytes, "UTF-8");

edit Even if you do this, this is probably not going to work:

SecureRandom random = new SecureRandom();
byte[] saltArr = new byte[64];
random.nextBytes(saltArr, "UTF-8");

You are generating random bytes and then you are interpreting those bytes as if they are encoded characters (using some character encoding). This might throw an exception if the random bytes are for example not valid UTF-8 sequences.

Strings are not suitable as containers for random bytes. Don't try to create strings out of random bytes this way. Instead of this, do Base 64 encoding before you put the bytes in a String. Or generate random characters instead of random bytes for the salt.

Upvotes: 1

Related Questions