I have a strange problem in getting equivalent hash code from C# code translated into Java. I don't know, what MessageDigest update method do. It should only update the contents of digest and should compute hash after calling digest.
Same thing I am doing in C# with SHAManaged512.ComputeHash(content). But I am not getting same hash code.
Following is the Java code.
public static String hash(String body, String secret) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(body.getBytes("UTF-8"));
byte[] bytes = md.digest(secret.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException();
}
}
Following is C# Code
private byte[] ComputeContentHash(string contentBody)
{
using (var shaM = new SHA512Managed())
{
var content = string.Concat(contentBody, Options.SecretKey);
var hashedValue = shaM.ComputeHash(ToJsonStream(content));
return hashedValue;
}
}
public static Stream ToJsonStream(object obj)
{
return new MemoryStream(Encoding.Unicode.GetBytes(obj.ToString()));
}
I had the exact same issue. Its been two years since you asked but just in case someone comes across this question, here's the solution
public static string encryptHash(string APIkey, string RequestBodyJson)
{
var secretBytes = Encoding.UTF8.GetBytes(APIkey);
var saltBytes = Encoding.UTF8.GetBytes(RequestBodyJson);
using (var sHA256 = new SHA256Managed())
{
byte[] bytes = sHA256.ComputeHash(saltBytes.Concat(secretBytes).ToArray());
//convert to hex
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
return builder.ToString();
}
}
The solution was to put first Secret Key and concate it with pay load data.
Encoding.Unicode (which you are using in the C# ToJsonStream method) is not UTF8. It's UTF16. See MSDN. (Also keep in mind that UTF16 can be little or big endian.) You're looking for Encoding.UTF8.
First thing to do is check if the byte array you're hashing is the same.
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 use this code in PHP to encrypt the password:
return sha1("kD0a1".md5("xA4".$password)."f4A");
Does anyone know an effective replacement for use in Android? I tried different functions for MD5 and SHA1 but in Java it always generates a different HASH than in PHP.
For example, as follows:
public static String passwordHash(String password) {
return sha1("kD0a1"+md5("xA4"+password)+"f4A");
}
public static String md5(String s) {
try {
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0; i<messageDigest.length; i++)
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
public static String sha1(String clearString) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
messageDigest.update(clearString.getBytes("UTF-8"));
byte[] bytes = messageDigest.digest();
StringBuilder buffer = new StringBuilder();
for (byte b : bytes) {
buffer.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
return buffer.toString();
}
catch (Exception ignored) {
ignored.printStackTrace();
return null;
}
}
However, PHP and Java will return a different HASH string to me.
PASS: test
PHP: 17bf2c08f4b9447cf8316736e13833316d3edc23
JAVA: 8434696e252b89af0db033eb255c88a91a42ce14
However, if I enter "passTest" for example, it will generate a hash correctly
PASS: passTest
PHP: db4aedf1d4072b7b645996394aa74743f14eeb7a
JAVA: db4aedf1d4072b7b645996394aa74743f14eeb7a
And "passwordTest" is wrong again.
PASS: passwordTest
PHP: 1ad47c24d556187f1de5db66ff623bbe08a27f33
JAVA: 0f058b3aea48e69c028a7ee2693a98d6074b10a8
I can't explain that sometimes it works and sometimes it doesn't, and at the same time it just changes the String for the password.
Do you think there could be a problem with coding or something? I thought TextView did it, but even if I enter a String outside of TextView, it behaves the same way.
Thank you in advance for any advice.
I would add that I am testing on SDK 31
M.
following code may help you to achieve what you want, it's a method named hashing and salt password, furthermore, the salt method prevents the collision of passwords that have been registered on your database
public static String hashPassword(String password) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-512");
md.reset();
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();
}
here is the salt method
public static String getSalt() throws NoSuchAlgorithmException {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[32];
sr.nextBytes(salt);
return Base64.getEncoder().encodeToString(salt);
}
for further reading about different hashing&salting password, consult the below link, it might help you to solid your understands
https://howtodoinjava.com/java/java-security/how-to-generate-secure-password-hash-md5-sha-pbkdf2-bcrypt-examples/
NB: you should use a strong implementation to hash your password to prevent cracking
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 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.
Hello everybody I am working on the first piece of communication between server and client of my game. Obviously due to the fact that I am starting from zero, I am projecting each part of the program carefully.
I was looking in Swing API and I found the JPasswordField that is a normal InputField, but for passwords.
It returns as you know a string if the deprecated method getText() is called or an array of chars if is called getPassword.
Reading in SO I understood that is not a good idea to use getText, nor something like
String password = String.valueOf(passwordField.getPassword());
because doing so I am creating a String that can stay in memory for long time.
What I tried to create is something that can convert that password without using strings and I created this:
public static String digest(char[] in) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
ArrayList<Byte> list = new ArrayList<Byte>();
for(int i = 0; i<in.length; i++){
String ch = String.valueOf(in[i]);
byte[] b = ch.getBytes();
for(int j = 0; j<b.length;j++){
list.add(b[j]);
}
}
byte[] inputInByte = new byte[list.size()];
for(int i =0;i<list.size();i++){
inputInByte[i] = list.get(i);
}
md.update(inputInByte);
byte byteData[] = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
String hex = Integer.toHexString(0xff & byteData[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
The question is: is this algorithm correct and good for the security of the password? I had to use a String to convert from char to byte.
Also I return an hashed string, is there any problem in that? It should be quite difficult to find the password starting from the hash ;)
How about database connection? Hsqldb allow me to create query, but each query is a string......
Using SHA-256 digest is a hash method, not a cryptologic one. It is like a fingerprint. Can you get a person from his fingerprints without testing everybody's (6 billions) fingerprint ? No. It used to store password in databases in php, for example. We just store the pass's hash, and when the user want to connect, we compute the newly entered password hash, and compare it with the database's hash.
This prevents users from stealing passwords if the database is hacked. But you cannot get the password from the hash. I hope i answered to your question.
By the way, consider using apache lib for message digest, it is easier and more safe i think
I think your code is quite ok, but you are still working with String to create the byte value, so you maybe better change String.valueOf(in[i]); to something like this:
public static String digest(char[] in) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
ArrayList<Byte> list = new ArrayList<Byte>();
for(int i = 0; i<in.length; i++){
byte b = (byte) in[i]
list.add(b);
}
byte[] inputInByte = new byte[list.size()];
for(int i =0;i<list.size();i++){
inputInByte[i] = list.get(i);
}
md.update(inputInByte);
byte byteData[] = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
String hex = Integer.toHexString(0xff & byteData[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
that is also easier than using that for cycle and two step conversion to byte.