Hashing a password in java and trying to convert in string - java

I actually have a problem with hashing a password and trying to convert in string to put it in a database.
Currently I have this code
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(motsDePasse.getBytes(StandardCharsets.UTF_8));
String fileString = Base64.getEncoder().encodeToString(hash);
The deal is that it does not give me the good hash. Let's say I try to hash "12345". It should give me 5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5.
But it actually return WZRHGrsBESr8wYFZ9sx0tPURuZgG2lmzyvWpwXPKz8U=

try using a hex encoder
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest("12345".getBytes(StandardCharsets.UTF_8));
String hex = DatatypeConverter.printHexBinary(hash);
System.out.println(hex);
output
5994471ABB01112AFCC18159F6CC74B4F511B99806DA59B3CAF5A9C173CACFC5

You are Base64 encoding it. If you Hex encode it, you will get the output you are looking for.

You're encoding your bytes in base 64. If you want to encode it in hexadecimal, try here: Java code To convert byte to Hexadecimal. If you're putting into a database as a string though, base64 should be fine for your needs.

Related

AES encrypted and decrypted values differ

In an Android app, I am trying to consume a WebAPI with an encrypted value in the JSON. I have a C# script which handles the encryption and I have adapted it to Android. The encryption method in short is adding a byte array a few variables, randomly generated IV, randomly generated salt and hmacsalt, adding the ciphertext which is generated from a Json String using AES/CBC/Pkcs7Padding and generating hmac and also adding that to the byte array. Converting this byte array to base64 gives me the encrypted string. I think everything works fine in this process since the WebAPI is able to decrypt my string. What the problem is the string is decrypted mostly correct but there is a date field and the date appears to be completely wrong.
I've been trying to adapt the C# to Android and what I am not sure about is how to specify the key length.
The key generators in both C# and Android are as follows.
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, pbkdf2_iterations).GetBytes(pbkdf2_keyLength);
Here the pbkdf2_iterations = 100 and pbkdf2_keyLength =32;
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, 100, 32);
byte[] key = factory.generateSecret(pbeKeySpec).getEncoded();
Here when initiating the PBEKeySpec, when I pass 32 for the key length, the byte[]key becomes 4 bytes and there is an exception saying unsupported key size 4 bytes but the WebAPI is able to decrypt my string with the date error. When I pass 256 for the key length, to make the byte[] 32 bytes, the WebAPI is not able to decrypt the string.
I am quite confused about what is the right way to do this.
To give an example about the faulty decrypted string, my plaintext to be encrypted is;
{"Username":"username","Password":"password","DateCreated":"2019-10-25T14:46:01.441Z"}
but the decrypted string is;
{"Username":"username","Password":"password","DateCreated":"2019-03-04T09:29:54.3516562Z"}
In this case, I suppose the encryption is correct but have no clue how the date value and format changes.
Any opinions about what may be wrong would be greatly appreciated.
Edit:
JSonObject Creation code
The Json data is created statically.
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String dateString = formatter.format(new java.util.Date());
JsonObject o = new JsonObject();
o.addProperty("Username", "username");
o.addProperty("Password","password");
o.addProperty("DateCreated", dateString);
String jsonString = o.toString();
And jsonString is passed for the encryption. I can see that its value is just the way I want.

How to get the same MD5 string in Java as in C#

I have code in C# which produces MD5 encoded byte[] from String and then this byte[] is converted to String. The C# code is
byte[] valueBytes = (new UnicodeEncoding()).GetBytes(value);
byte[] newHash = (new MD5CryptoServiceProvider()).ComputeHash(valueBytes);
I need to get the same result in Java. I'm trying to do this
Charset utf16 = Charset.forName("UTF-16");
return new String(DigestUtils.md5(value.getBytes(utf16)), utf16);
The code is using Apache Commons Codec library for MD5 calculations. I'm using UTF16 charset because I've read in other SO questions that C#'s UnicodeEncoding uses it by default.
So the code snippets look like they do the same thing, but when I'm passing the string byndyusoft2014, C# gives me hV7u6mQYRgBXXF9jOWWYJg== and Java gives me ﹡둛뭶魙ꇥ늺ꢑ. I've tried UTF16LE and UTF16BE as charsets with no luck.
Has anyone idea about what I'm doing wrong?
I think because of the java decode string to byte[] with utf-8,but the C# is not.So the java and C# encode the different byte array,and then get the different result.You can decode the string to byte[] at c# with utf-8,and see the result.Like following code:
UTF8Encoding utf8 = new UTF8Encoding();
byte[] bytes=utf8.GetBytes("byndyusoft2014");
byte[] en=(new MD5CryptoServiceProvider()).ComputeHash(bytes);
Console.WriteLine(Convert.ToBase64String(en));
and the java code:
byte[] en = DigestUtils.md5Digest("byndyusoft2014".getBytes());
byte[] base64 = Base64Utils.encode(en);
System.out.println(new String(base64));
Of course,in your description,the result of C# like be encoded with base64,so the java should encode the byte array with base64.
The result of them is same as swPvmbGDI1GbPKQwL9knjQ==
The DigestUtils and Base64Utils is some implementation of MD5 and BAS64 in spring library
As it turned out, the main difference was not presented in my original code snippet - it was convertation from MD5 encoded byte[] to String. You need to use Base64 to get final result. This is the working code snippet in Java
Charset utf16 = Charset.forName("UTF-16LE");
return new String(Base64.encodeBase64(DigestUtils.md5(value.getBytes(utf16))));
With this code I get the same result as with C#. Thank you all for good hints!

MessageDigges md5 differs from the database md5 string

MessageDigest md = MessageDigest.getInstance("MD5");
String md5password = new String(md.digest("test".getBytes("UTF-8")), "UTF-8");
I have the same string "test" in my database, but here I get something different like this:
�k�F!�s��N�&'��
database:
098f6bcd4621d373cade4e832627b4f6
This is the problem:
new String(md.digest("test".getBytes("UTF-8")), "UTF-8");
You're trying to decode the result of the MD5 digest as if it were a UTF-8 string. It's not. It's not text at all - it's just binary data. What you're doing is like trying to load an image or music file as a string - it's just a bad idea.
It looks like your database is either storing it as binary data and showing you a hex representation, or storing it as hex. I suggest you do the same. There are lots of Stack Overflow questions about converting byte arrays to hex in Java, so that part should be simple.

AES using Base64 Encryption

my target is to encrypt a String with AES
I am using Base64 for encryption, because AES needs a byte array as input.
Moreover i want every possible Char(including chinese and german Symbols) to be stored correctly
byte[] encryptedBytes = Base64.decodeBase64 ("some input");
System.out.println(new Base64().encodeToString(encryptedBytes));
I thought "some input" should be printed. Instead "someinpu" is printed.
It is impossible for me to use sun.misc.* Instead i am using apache.commons.codec
Does someone has a clue what's going wrong?
Yes - "some input" isn't a valid base64 encoded string.
The idea of base64 is that you encode binary data into text. You then decode that text data to a byte array. You can't just decode any arbitrary text as if it were a complete base64 message any more than you can try to decode an mp3 as a jpeg image.
Encrypting a string should be this process:
Encode the string to binary data, e.g. using UTF-8 (text.getBytes("UTF-8"))
Encrypt the binary data using AES
Encode the cyphertext using Base64 to get text
Decryption is then a matter of:
Decode the base64 text to the binary cyphertext
Decrypt the cyphertext to get the binary plaintext
Decode the binary plaintext into a string using the same encoding as the first step above, e.g. new String(bytes, "UTF-8")
You cannot use Base64 to turn arbitrary text into bytes; that's not what it's designed to do.
Instead, you should use UTF8:
byte[] plainTextBytes = inputString.getBytes("UTF8");
String output = new String(plainTextBytes, "UTF8");

Glassfish Security - jdbcRealm: How to configure login with SHA-256 digest

I use jdbcRealm for security in my glassfish v3.0.1 b22. It is set up so that it use the USER table inside my database for authentication by following this blog: http://blogs.oracle.com/foo/entry/mort_learns_jdbc_realm_authentication. I got it working fine, if I leave the digest algorithm as plain text. However when i try to use SHA-256 for digest algorithm, it stop working.
What I did is specify in Glassfish - Security - Realm - jdbcRealm - digest that I want SHA-256 (I just type SHA-256 inside digest field). Then I wrote a simple Java program to convert password text into SHA-256 hash. I then paste that hash inside my password field in the database. By the way, password field is type varchar(30). I cant log in anymore. One thing I notice that my simple Java program generated different hash every time for the same text field.
Below are my simple java program:
MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "admin";
md.update(text.getBytes("UTF-8"));
byte[] digest = md.digest();
System.out.println(digest.toString());
The jdbcRealm allows encoding values of hex or base64. You need to specify one of these in your realm configuration and in your code, convert the byte array into one of these formats:
Base64:
import com.sun.org.apache.xml.internal.security.utils.Base64;
...
byte[] digest = md.digest();
System.out.println(Base64.encode(digest));
Hex:
...
byte[] digest = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
String hex = Integer.toHexString(0xff & digest[i]);
if (hex.length() == 1) sb.append('0');
sb.append(hex);
}
System.out.println(sb.toString());
btw, password field is type varchar(30)
You'll need to increase the size of your password field. SHA-256 base64 and hex values are 45 and 64 characters in length, respectively.

Categories