This is the code used in c#
public static string Encode_SHA512(string input) {
try {
using (SHA512 sha = SHA512.Create()) {
byte[] hash = sha.ComputeHash(Encoding.Unicode.GetBytes(input));
return Convert.ToBase64String(hash);
}
} catch (Exception ex) {
throw new Exception("Error al generar hash SHA512", ex);
}
}
And this is the code used in java (One of many attempts)
public static String Encode_SHA512(String input) {
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] digest = md.digest(input.getBytes("UTF-16LE"));
return String.format("%0128x", new BigInteger(1, digest));
}
But always the result is different. How can I use the same encryption of the C # code in java?
The problem is in your Java version you are not converting to a base64 encoded string correctly. If you update your Java code to the following then they both produce the same hash:
public static String Encode_SHA512(String input) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte [] inputBytes = input.getBytes("UTF-16LE");
byte[] digest = md.digest(inputBytes);
return Base64.getEncoder().encodeToString(digest);
}
The line return String.format("%0128x", new BigInteger(1, digest)); is replaced with return Base64.getEncoder().encodeToString(digest); which currently base 64 encodes the resultant hash. Perhaps why the code was confusing is that the byte[] produced by the digest method looked different as in Java the byte type is twos complement (which is signed) so -128 to + 127 whereas in C# it is unsigned so 0 to 255 hence in the debugger any byte with starting with a 1 would look different as it would appear negative in Java but positive in C#.
Related
This question already has answers here:
convert password encryption from java to php
(4 answers)
Closed 7 years ago.
I have JAVA AES encryption logic
private static byte[] getMD5(String input) {
try {
byte[] bytesOfMessage = input.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytesOfMessage);
} catch (Exception e) {
}
return null;
}
What will be the php equivalent of this function?
I have used md5($string) in php but the output is different in both the cases.
In the code that you have posted you get the byte array of the md5 hash. PHP's md5() function returns the md5 hash as a hex.
So, if you want to get the md5 hash as string in java you can like this:
private static String getMD5(String input) {
try {
byte[] bytesOfMessage = input.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
// byte array of md5 hash
byte[] md5 = md.digest(bytesOfMessage);
// we convert bytes to hex as php's md5() would do
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < md5.length; i++) {
stringBuffer.append(Integer.toString((md5[i] & 0xff) + 0x100, 16).substring(1));
}
return stringBuffer.toString();
} catch (Exception e) {
}
return null;
}
From PHP you can get the row md5 binary by doing md5('some string', true). See md5() function documentation about it.
To get the byte array you can do unpack('c*', md5('some string',true)). See unpack() function and the possible formats for more info.
I have two objects based on which SHA 256 Hash needs to be generated.
First value is a JSONObject
Second value is a String variable.
Ideally, what i need is
Hash hash= new Hash(JSONObject, String);
I couldn't find any hash generation methods which takes two values.
Could anyone help me with this?.
SHA 256 works on a byte array as input. You need to convert your JSONObject and your String to byte arrays, then calculate the SHA 256 hash on the concatenation of these byte arrays.
The proper way of generating a sha256 hashcode using key and value
public static String hashMac(String text, String secretKey)
throws SignatureException {
try {
Key sk = new SecretKeySpec(secretKey.getBytes(), HASH_ALGORITHM);
Mac mac = Mac.getInstance(sk.getAlgorithm());
mac.init(sk);
final byte[] hmac = mac.doFinal(text.getBytes());
return toHexString(hmac);
} catch (NoSuchAlgorithmException e1) {
// throw an exception or pick a different encryption method
throw new SignatureException(
"error building signature, no such algorithm in device "
+ HASH_ALGORITHM);
} catch (InvalidKeyException e) {
throw new SignatureException(
"error building signature, invalid key " + HASH_ALGORITHM);
}
}
public static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
Formatter formatter = new Formatter(sb);
for (byte b : bytes) {
formatter.format("%02x", b);
}
return sb.toString();
}
I am not an expert in cryptography and I am getting some interesting results when I use the encryption method below.
The server is .NET C# and the client runs JAVA. Basically, We encrypt credit card information and for the 12 credit cards I have, 11 works perfectly with the methods below.
However, one of the cards (real VISA credit CARD) the result returned by encrypt() and converted to hex has a negative symbol in the start of the string, like this:
-6d9830a52b2c3add7a78fd9897bca19d....., it fails when the server tries to decrypt it and I think it should be positive not negative based on this explanation RSA - Encryption with negative exponent
private static byte[] encrypt(String text, PublicKey pubRSA) throws Exception
{
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, pubRSA);
return cipher.doFinal(text.getBytes());
}
//Using this encryption method one card could not be decrypted by vPAY due to negative (exponential) symbol.
//It may have the same affect with other cards
public final static byte[] encrypt(String text)
{
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(Base64.decode(pkBase64));
PublicKey pk = keyFactory.generatePublic(x509Spec);
return encrypt(text, pk);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
Has anyone faced something like that and found a workaround?
I have tried three other algorithms with different KeySpec and the same publicKey (the source is a string in base64 format) but none of them could be decrypted by the server even with the cards the were working before...
UPDATE 1
This is how a convert the encrypted result in bytes to HEX:
public static String byteToHex(byte[] string)
{
try {
return String.format("%04x", new BigInteger(string));
} catch (Exception e) {
// TODO Auto-generated catch block
return null;
}
}
You should print out the hexadecimal string directly from byte[]. This can be done using the following code:
StringBuilder sb = new StringBuilder(data.length * 2);
for (int i = 0; i < data.length; i++) {
sb.append(String.format("%02X", data[i] & 0xFF));
}
return sb.toString();
There is no need to use BigInteger. In fact, it is dangerous to use BigInteger. One reason is the one you've already encountered: BigInteger conversion to/from byte[] is using signed big endian encoding by default. The other thing is that the output of the RSA signature (as integer) may be smaller than the modulus size in hexadecimals. This is why EJP's solution will fail now and then.
RSA output has been defined in bytes, as an unsigned big endian encoded in the same number of bits as the key size (using integer to octet string encoding in the standard documents).
public static String byteToHex(byte[] string)
A byte[] is not a string. It's a byte array. Don't confuse yourself with inappropriate variable names. String is not a container for binary data.
return String.format("%04x", new BigInteger(string));
Try return new BigInteger(1,string).toString(16), and have a look at the Javadoc to see why this works where new BigInteger(string) didn't.
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
byte[] output = digest.digest(password);
digest.update(salt);
digest.update(output);
return new BigInteger(1, digest.digest());
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
}
But I got Exception in thread "main" java.security.NoSuchAlgorithmException: SHA_512 MessageDigest not available error
The following are the standard hashing algorithms provided by the Java MessageDigest:
MD2
MD5
SHA-1
SHA-256
SHA-384
SHA-512
You may want to verify the name you are supplying to the factory method.
I would say that the most likely explanation is that your REAL code has "SHA_512" rather than "SHA-512". Certainly, that would explain why there is an underscore in the exception message.
The other possibility is that you have a JVM with the "military strength" crypto algorithms removed because of US export restrictions. However, I think that is pretty unlikely ...
(And in fact, my reading of this is that SHA-512 was included in all versions of the default "Sun" provider anyway.)
Here is the sample method which can be used to get hash string through SHA-512:
private static String getHashCodeFromString(String algorithm, String str) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(str.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer hashCodeBuffer = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
hashCodeBuffer.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
return hashCodeBuffer.toString();
}
use SHA-512 as algorithm. go to following link for other possible algorithm name you can pass in method. https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest
The MessageDigest class is an engine class designed to provide the
functionality of cryptographically secure message digests such as
SHA-1 or MD5. A cryptographically secure message digest takes
arbitrary-sized input (a byte array), and generates a fixed-size
output.
Reference
To print all the MessageDigest provider -
Provider provider[] = Security.getProviders();
for (Provider pro : provider) {
System.out.println(pro);
for (Enumeration e = pro.keys(); e.hasMoreElements();)
System.out.println("\t" + e.nextElement());
}
And fortunatly SHA-512 is there but SHA_512 is not. :)
In Groovy language you can use below method to generate hash string through SHA-512.
It's completely working for me.
public String getHashCodeFromString(String algorithm, String str) throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(str.getBytes());
def byteData = md.digest() as byte[];
//convert the byte to hex format method 1
StringBuffer hashCodeBuffer = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
hashCodeBuffer.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
return hashCodeBuffer.toString();
}
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