private String getString(byte[] bytes)
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
sb.append(0xFF & b);
}
return sb.toString();
}
public String encrypt(String source)
{
try
{
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(source.getBytes());
return getString(bytes);
}
catch (Exception e)
{
e.printStackTrace(); }
return null;
}
If my text = "test"
The First Part toString()) produces a value of "Encryption$2#6966b26b"
And the second part then gets that and produces a value of "91431072057033211115202222781313839180246"
But why is the md5 a number and not 31f521a06d5060d1f38159c74a1f7cf2 or something similar?
The function "encrypt()" returns a MD5 hash. You should rename it to "hash", because hashing != encrypting.
If you want to encrypt a string, you can look here: https://gist.github.com/bricef/2436364
It's clearly stated in code yuou are using MD5 hashing algorithm
Now your question is why:
But why is the md5 a number and not 31f521a06d5060d1f38159c74a1f7cf2 or something similar?
your answer is simple, look at code which generates you string from your byte array.
byte b = bytes[i];
sb.append(0xFF & b);
you take byte, ie 0x20 then you perform logical and operation with integer 0x255 and then you add decimal representation of result yo your StringBuilder.
What you want to do is more like
sb.append(Integer.toHexString(0xff&b));
I would say MD5 hash, because the code says MessageDigest.getInstance("MD5") :D
Related
My job is to rewrite a bunch of Java codes is C#.
This is the JAVA code:
public static String CreateMD5(String str) {
try {
byte[] digest = MessageDigest.getInstance("MD5").digest(str.getBytes("UTF-8"));
StringBuffer stringBuffer = new StringBuffer();
for (byte b : digest) {
// i can not understand here
stringBuffer.append(Integer.toHexString((b & 255) | 256).substring(1, 3));
}
return stringBuffer.toString();
} catch (UnsupportedEncodingException | NoSuchAlgorithmException unused) {
return null;
}
}
Ok.As you can see this code is trying to make MD5 hash.But the thing i can not understand is the part that i have shown.
I tried this code in C# to rewrite this JAVA code:
public static string CreateMD5(string input)
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
Well both codes are making MD5 hash strings but the results are different.
There is a difference in encoding between the two code snippets you've shown - your Java code uses UTF-8, but your C# code uses ASCII. This will result in a different MD5 hash computation.
Change your C# code from:
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
to:
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
This should™ fix your problem, provided there are no other code conversion errors.
I want to implement SHA512 hashing using a salt. I started here, leading to this mcve:
import java.security.MessageDigest;
import org.junit.Test;
public class Sha512Mcve {
private final String ENCODING = "ISO-8859-1";
#Test
public void test() {
System.out.println(computeHashFor("whatever"));
}
private String computeHashFor(String toHash) {
String salt = "salt";
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-512");
// md.update(salt.getBytes(ENCODING));
byte[] bytes = md.digest(toHash.getBytes(ENCODING));
return toUnixRepresentation(salt, bytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String toUnixRepresentation(String salt, byte[] bytes) {
StringBuilder sb = new StringBuilder();
sb.append("$6$");
sb.append(salt);
sb.append("$");
for (int i = 0; i < bytes.length; i++) {
int c = bytes[i] & 0xFF;
if (c < 16) sb.append("0");
sb.append(Integer.toHexString(c));
}
return sb.toString();
}
}
Thing is: when I leave the line md.update() commented out, this code gives me the exact same results as some online hash generators (like this one).
For example, hashing the word "whatever" gives a hash value ae3d....63a.
But when I run my code with that salt operation; I get different results (again compared against that online tool, which allows to set a salt string, too).
My implementation results in 413...623; the online tool says F25...686.
Any explanation in which way "salting" leads to "implementation specific" results?
Is there something I should do differently in my code?
Salt before or after?
What the calculator does when you set the salt option
whateversalt
What you are doing in your code
saltwhatever
resutls from the calculator
whateversalt
F2527142C752B05467EE53B44735397F5B4C870DF0F154A0CF3AC23B31CF42EE7E1002D326B57DF60ED4B7449CF101290BDC0BECCB677AAAD846CFBE140DF686
saltwhatever
41333B9BAFC14CB3D1106D72A5D461F348B9EA1304A82989E00E5FC2D3239339492FCA12ED5EBF5F6802955C95B5F7ADA4CA035A911C2F29ABE905C3923CF623
Therefore to match the calculation you just have to reverse the order and add the salt last
md.update(toHash.getBytes(ENCODING));
byte[] bytes = md.digest(salt.getBytes(ENCODING));
Or even
md.update(toHash.getBytes(ENCODING));
md.update(salt.getBytes(ENCODING));
byte[] bytes = md.digest();
I am using this function to calculate the SHA 256
public static String getSHA1(String plainText) {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(plainText.getBytes(Charset.forName("UTF-8")));
StringBuffer hexString = new StringBuffer();
byte[] bytes = md.digest();
for (int i = 0; i < bytes.length; i++) {
hexString.append(Integer.toHexString(0xFF & bytes[i]));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
And to be sure of my results, I check this online website
http://onlinemd5.com/
the results between my code and the online is almost the same, but you know that it must be equal. for instance
my plain testis:
1234567
the website result
8BB0CF6EB9B17D0F7D22B456F121257DC1254E1F01665370476383EA776DF414
my code result
8bb0cf6eb9b17df7d22b456f121257dc1254e1f1665370476383ea776df414
and this is more examples:
7777777
8C1CDB9CB4DBAC6DBB6EBD118EC8F9523D22E4E4CB8CC9DF5F7E1E499BBA3C10
8c1cdb9cb4dbac6dbb6ebd118ec8f9523d22e4e4cb8cc9df5f7e1e499bba3c10
147258
7A2EC40FF8A1247C532309355F798A779E00ACFF579C63EEC3636FFB2902C1AC
7a2ec4ff8a1247c53239355f798a779e0acff579c63eec3636ffb292c1ac
888888
92925488B28AB12584AC8FCAA8A27A0F497B2C62940C8F4FBC8EF19EBC87C43E
92925488b28ab12584ac8fcaa8a27af497b2c6294c8f4fbc8ef19ebc87c43e
I do know that this is maybe about the encoding. but look i used utf-8 which is what the website used
This is the problem:
hexString.append(Integer.toHexString(0xFF & bytes[i]));
This will lose any leading 0s - in other words, any byte less than 16 will come out as a single hex digit instead of two.
There are plenty of fixes for this. For example:
Manually append 0 if the value is between 0 and 15 (ick)
Use String.format("%02x", bytes[i] & 0xff)
Use a full "byte array to hex conversion" method in a utility library (there are loads around)
I have a SQL table with usernames and passwords. The passwords are encoded using MessageDigest's digest() method. If I encode a password - let's say "abcdef12" - with MessageDigest's digest() method and then convert it to hexadecimal values, the String is different than if I do the same using PHP's SHA1-method. I'd expect these values to be exactly the same though.
Code that is used to encode the passwords:
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] passbyte;
passbyte = "abcdef12".getBytes("UTF-8");
passbyte = md.digest(passbyte);
The conversion of the String to hexadecimal is done using this method:
public static String convertStringToHex(String str) {
char[] chars = str.toCharArray();
StringBuffer hex = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
hex.append(Integer.toHexString((int) chars[i]));
}
return hex.toString();
}
Password: abcdef12
Here's the password as returned by a lot of SHA1-hash online generators and PHP SHA1()-function: d253e3bd69ce1e7ce6074345fd5faa1a3c2e89ef
Here's the password as encoded by MessageDigest: d253e3bd69ce1e7ce674345fd5faa1a3c2e2030ef
Am I forgetting something?
Igor.
Edit: I've found someone with a similar problem: C# SHA-1 vs. PHP SHA-1...Different Results? . The solution was to change encodings.. but I can't change encodings on the server-side since the passwords in that SQL-table are not created by my application.
I use client-side SHA1-encoding using a JavaScript SHA1-class (more precisely: a Google Web Toolkit-class). It works and encodes the string as expected, but apparently using ASCII characters?..
I have the same digest as PHP with my Java SHA-1 hashing function:
public static String computeSha1OfString(final String message)
throws UnsupportedOperationException, NullPointerException {
try {
return computeSha1OfByteArray(message.getBytes(("UTF-8")));
} catch (UnsupportedEncodingException ex) {
throw new UnsupportedOperationException(ex);
}
}
private static String computeSha1OfByteArray(final byte[] message)
throws UnsupportedOperationException {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(message);
byte[] res = md.digest();
return toHexString(res);
} catch (NoSuchAlgorithmException ex) {
throw new UnsupportedOperationException(ex);
}
}
I've added to my unit tests:
String sha1Hash = StringHelper.computeSha1OfString("abcdef12");
assertEquals("d253e3bd69ce1e7ce6074345fd5faa1a3c2e89ef", sha1Hash);
Full source code for the class is on github.
Try this - it is working for me:
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(original.getBytes());
byte[] digest = md.digest();
StringBuffer sb = new StringBuffer();
for (byte b : digest) {
sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
Regards,
Konki
It has nothing to do with the encodings. The output would be entirely different.
For starters, your function convertStringToHex() doesn't output leading zeros, that is, 07 becomes just 7.
The rest (changing 89 to 2030) is also likely to have something to do with that function. Try looking at the value of passbyte after passbyte = md.digest(passbyte);.
Or try this:
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(clearPassword.getBytes("UTF-8"));
return new BigInteger(1 ,md.digest()).toString(16));
Cheers Roy
I know that there is a lot of similar topics, but still... can someone provide me a working example of method which generates MD5 String.
I'm currently using MessageDigest, and I'm doing the following to get a string
sun.misc.BASE64Encoder().encode(messageDigest.digest())
I guess there is some better way to do that.
Thanks in advance!
I'd use commons-codec
Base64 - Base64.encodeBase64(digestBytes)
Hex-string - Hex.encodeHex(digestBytes)
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] arr = md.digest(bytesOfMessage);
return Base64.getEncoder().encodeToString(arr);
note: md5 is not considered as good hash algorithm anymore, consider choosing SHAs
// Convert to hex string
StringBuffer sb = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
if ((0xff & messageDigest[i]) < 0x10) {
sb.append('0');
}
sb.append(Integer.toHexString(0xff & messageDigest[i]));
}
String md5 = sb.toString();
This assumes you actually want your MD5 printed as an hex string, not BASE64-encoded. That's the way it is normally represented.
I've seen next solution:
byte[] digest = md.digest(someDataByteArray);
StringBuilder hex = new StringBuilder();
for (byte b : digest) {
hex.append(String.format("%02x", b));
}
import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
...
String input = "westerngun";
MessageDigest digest = MessageDigest.getInstance("MD5"); // not thread-safe, create instance for each thread
byte[] result = digest.digest(input.getBytes()); // get MD5 hash array, could contain negative
String hex = DatatypeConverter.printHexBinary(result).toLowerCase(); // convert byte array to hex string
If you want a number:
Integer number = Integer.parseInt(hex, 16); // parse hex number to integer. If overflowed, use Long.parseLong()