I'm trying to hash data "text" to be transferred from Java Service to C# Service.
I'm using SHA256 as a Hashing algorithm, but despite the values and the salt being the same the result doesn't.
Here is my C# snippet
public string Sign(string textToHash, string salt){
byte[] convertedHash = new byte[salt.Length / 2];
for (int i = 0; i < salt.Length / 2; i++)
convertedHash[i] = (byte)int.Parse(salt.Substring(i * 2, 2), NumberStyles.HexNumber);
HMAC hasher = new HMACSHA256(convertedHash);
string hexHash = "";
using (hasher)
{
byte[] hashValue = hasher.ComputeHash(Encoding.UTF8.GetBytes(textToHash));
foreach (byte b in hashValue)
{
hexHash += b.ToString("X2");
}
}
return hexHash;
}
And, here is the Java snippet
public static String sign(String textToHash, String salt){
byte[] convertedHash = new byte[salt.length() / 2];
for (int i = 0; i < salt.length() / 2; i++)
{
convertedHash[i] = (byte)Integer.parseInt(salt.substring(i * 2, i * 2 + 2),16);
}
String hashedText = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(convertedHash);
byte[] bytes = md.digest(textToHash.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
}
hashedText = sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return hashedText;
}
In Java, I also tried
convertedHash = salt.getBytes();
But I got different results also.
Tests:
salt = ABCDEFG
text = hashme
Result in C#
70B38047C28FFEDCF7275C428E65310671CADB65F11A5C9A8CFBB3CF52112BA3
Result in Java
a8bc36606aade01591a1d12c8b3c87aca1fe55def79740def03a90b49f2c6b7c
So, any help about why the results aren't the same.
Thanks in advance.
To mimic the Java hashing, I used SHA256Managed rather than HMACSHA256 in C#
public static string Sign(string data, string salt)
{
UTF8Encoding encoder = new UTF8Encoding();
SHA256Managed sha256hasher = new SHA256Managed();
byte[] convertedHash = new byte[salt.Length / 2];
for (int i = 0; i < salt.Length / 2; i++)
convertedHash[i] = (byte)int.Parse(salt.Substring(i * 2, 2), NumberStyles.HexNumber);
byte[] dataBytes = encoder.GetBytes(data);
byte[] bytes = new byte[convertedHash.Length + dataBytes.Length];
Array.Copy(convertedHash, bytes, convertedHash.Length);
Array.Copy(dataBytes, 0, bytes, convertedHash.Length, dataBytes.Length);
byte[] hashedBytes = sha256hasher.ComputeHash(bytes);
return hashedBytes.Aggregate("", (current, t) => current + t.ToString("X2"));
}
HMACSHA256 is not a pure SHA-256.
Related
I received an encrypted string from Java, and I can see the Java encrypted source code.
I wrote the decryption code in C#. But always report an error at "FlushFinalBlock". Error message: "System.Security.Cryptography.CryptographicException. Additional information: Incorrect data."
Can any body point out where the problem is in my C# code?
this is java code:
private static byte[] coderByDES(byte[] plainText, String key, int mode)
throws InvalidKeyException, InvalidKeySpecException,
NoSuchAlgorithmException, NoSuchPaddingException,
BadPaddingException, IllegalBlockSizeException,
UnsupportedEncodingException {
SecureRandom sr = new SecureRandom();
byte[] resultKey = makeKey(key);
DESKeySpec desSpec = new DESKeySpec(resultKey);
SecretKey secretKey = SecretKeyFactory.getInstance("DES").generateSecret(desSpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(mode, secretKey, sr);
return cipher.doFinal(plainText);
}
private static byte[] makeKey(String key)
throws UnsupportedEncodingException {
byte[] keyByte = new byte[8];
byte[] keyResult = key.getBytes("UTF-8");
for (int i = 0; i < keyResult.length && i < keyByte.length; i++) {
keyByte[i] = keyResult[i];
}
return keyByte;
}
private static String byteArr2HexStr(byte[] arrB) {
int iLen = arrB.length;
StringBuilder sb = new StringBuilder(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
while (intTmp < 0) {
intTmp = intTmp + 256;
}
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}
this is C# code:
public static string DecryptForDES(string input, string key)
{
byte[] inputByteArray = HexStr2ByteArr(input);
byte[] buffArray = null;
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = Encoding.UTF8.GetBytes(key);
des.IV = Encoding.UTF8.GetBytes(key);
des.Mode = System.Security.Cryptography.CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();//
cs.Close();
}
buffArray = ms.ToArray();
ms.Close();
}
string str = string.Empty;
if (buffArray != null)
{
str = Encoding.UTF8.GetString(buffArray);
}
return str;
}
public static byte[] HexStr2ByteArr(string strIn)
{
byte[] arrB = Encoding.UTF8.GetBytes(strIn);
int iLen = arrB.Length;
byte[] arrOut = new byte[iLen / 2];
byte[] arrTmp = new byte[2];
for (int i = 0; i < iLen; i = i + 2)
{
string strTmp = Encoding.UTF8.GetString(arrB, i, 2);
arrOut[i / 2] = (byte)Convert.ToInt32(strTmp, 16);
}
return arrOut;
}
Both, the Java encryption part and the C# decryption part work on my machine if the passwords match. Otherwise a System.Security.Cryptography.CryptographicException: 'Bad Data' is thrown. To get the password match replace in the C#-method DecryptForDES
des.Key = Encoding.UTF8.GetBytes(key);
with
des.Key = MakeKey(key);
with the C#-method:
private static byte[] MakeKey(String key)
{
byte[] keyByte = new byte[8];
byte[] keyResult = Encoding.UTF8.GetBytes(key);
for (int i = 0; i<keyResult.Length && i<keyByte.Length; i++) {
keyByte[i] = keyResult[i];
}
return keyByte;
}
corresponding to the Java-method makeKey(String key).
Moreover, remove in the C#-method DecryptForDES
des.IV = Encoding.UTF8.GetBytes(key);
since the ECB-mode doesn't use an IV.
In the following testcase
coderByDES("This is a plain text that needs to be encrypted...", "This is the key used for encryption...", Cipher.ENCRYPT_MODE);
returns the byte-array
a47b1b2c90fb3b7a0ab1f51f328ff55aae3c1eb7789c31c28346696a8b1f27c7413c14e68fe977d3235b5a6f63c07d7a95d912ff22f17ad6
and
DecryptForDES("a47b1b2c90fb3b7a0ab1f51f328ff55aae3c1eb7789c31c28346696a8b1f27c7413c14e68fe977d3235b5a6f63c07d7a95d912ff22f17ad6", "This is the key used for encryption...");
returns the correct plain text.
By the way: As Flydog57 already stated DES is insecure (https://en.wikipedia.org/wiki/Data_Encryption_Standard). And also the ECB mode is not secure (https://crypto.stackexchange.com/questions/20941/why-shouldnt-i-use-ecb-encryption).
Better choices are AES (https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) with CBC or GCM mode (https://crypto.stackexchange.com/questions/2310/what-is-the-difference-between-cbc-and-gcm-mode).
I have the following Java code to generate hashes based on input text.
package main;
import java.util.Scanner;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class String_Hash_Generator {
public static void main(String args[]) throws NoSuchAlgorithmException {
Scanner inputScanner = new Scanner(System.in);
System.out.print("Input: ");
String input = inputScanner.next();
/* MD2 */
MessageDigest objMD2 = MessageDigest.getInstance("MD2");
byte[] bytMD2 = objMD2.digest(input.getBytes());
BigInteger intNumMD2 = new BigInteger(1, bytMD2);
String hcMD2 = intNumMD2.toString(16);
while (hcMD2.length() < 32) {
hcMD2 = "0" + hcMD2;
}
/* MD5 */
MessageDigest objMD5 = MessageDigest.getInstance("MD5");
byte[] bytMD5 = objMD5.digest(input.getBytes());
BigInteger intNumMD5 = new BigInteger(1, bytMD5);
String hcMD5 = intNumMD5.toString(16);
while (hcMD5.length() < 32) {
hcMD5 = "0" + hcMD5;
}
/* SHA-1 */
MessageDigest objSHA1 = MessageDigest.getInstance("SHA-1");
byte[] bytSHA1 = objSHA1.digest(input.getBytes());
BigInteger intNumSHA1 = new BigInteger(1, bytSHA1);
String hcSHA1 = intNumSHA1.toString(16);
while (hcSHA1.length() < 40) {
hcSHA1 = "0" + hcSHA1;
}
/* SHA-256 */
MessageDigest objSHA256 = MessageDigest.getInstance("SHA-256");
byte[] bytSHA256 = objSHA256.digest(input.getBytes());
BigInteger intNumSHA256 = new BigInteger(1, bytSHA256);
String hcSHA256 = intNumSHA256.toString(16);
while (hcSHA256.length() < 64) {
hcSHA256 = "0" + hcSHA256;
}
/* SHA-384 */
MessageDigest objSHA384 = MessageDigest.getInstance("SHA-384");
byte[] bytSHA384 = objSHA384.digest(input.getBytes());
BigInteger intNumSHA384 = new BigInteger(1, bytSHA384);
String hcSHA384 = intNumSHA384.toString(16);
while (hcSHA384.length() < 96) {
hcSHA384 = "0" + hcSHA384;
}
/* SHA-512 */
MessageDigest objSHA512 = MessageDigest.getInstance("SHA-512");
byte[] bytSHA512 = objSHA512.digest(input.getBytes());
BigInteger intNumSHA512 = new BigInteger(1, bytSHA512);
String hcSHA512 = intNumSHA512.toString(16);
while (hcSHA512.length() < 128) {
hcSHA512 = "0" + hcSHA512;
}
System.out.println("\nMD2: " + hcMD2
+ "\nMD5: " + hcMD5
+ "\nSHA-1: " + hcSHA1
+ "\nSHA-256: " + hcSHA256
+ "\nSHA-384: " + hcSHA384
+ "\nSHA-512: " + hcSHA512);
}
}
The input needs to be Scanner, because it is essential that it is run in a Command Prompt.
How could a file hash generator be created that takes the file path, such as C:\Program Files\WinRAR\Rar.exe and generates the hashes (MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512)?
Edit: The only solutions I have been able to find only use the file's name, not the entire path.
First, you need a mechanism to print a byte[] as hex. From the top answer to How to convert a byte array to a hex string in Java? you can do,
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
Then, you might use Files.readAllBytes(Path) to read your file(s). Finally, iterate an array of hash algorithms to calculate each hash. Something like,
public static void main(String args[]) {
Scanner inputScanner = new Scanner(System.in);
String[] hashAlgos = { "MD2", "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512" };
System.out.print("Input: ");
String input = inputScanner.next();
try {
byte[] fileContents = Files.readAllBytes(new File(input).toPath());
for (String algo : hashAlgos) {
MessageDigest md = MessageDigest.getInstance(algo);
byte[] hash = md.digest(fileContents);
System.out.printf("%s %s%n", algo, bytesToHex(hash));
}
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
}
I have tried to use java.security.MessageDigest or org.apache.commons.codec.digest.DigestUtils to do md5, but there comes out different results.
The sample code as below:
public static void main( String[] args )
{
System.out.println("MessageDigest: " + MD5("12345") );
MessageDigest md5Digest = DigestUtils.getMd5Digest();
System.out.println("MD5Hex with digest: " + DigestUtils.md5Hex(md5Digest.digest("12345".getBytes())));
System.out.println("MD5Hex: " + DigestUtils.md5Hex("12345"));
}
public final static String MD5(String s) {
char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
byte[] btInput = s.getBytes();
// 獲得MD5摘要算法的 MessageDigest 對象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字節更新摘要
mdInst.update(btInput);
// 獲得密文
byte[] md = mdInst.digest();
// 把密文轉換成十六進制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
System.out.println();
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
The results as below:
MessageDigest: 827CCB0EEA8A706C4C34A16891F84E7B
MD5Hex with digest: aad43635bbd353cef6ea6546093fa0c7
MD5Hex: 827ccb0eea8a706c4c34a16891f84e7b
If I have give md5Digest.digest() into DigestUtils.md5Hex, the result is different from MessageDigest. But if I just do md5Hex(), it will be the same. What's the different between this two way?
Thanks
When you are calling DigestUtils.md5Hex(md5Digest.digest("12345".getBytes()))), you actually calculate the MD5 of the result of the previous MD5 calculation. Thus no wonder that double-MD5 differs from single MD5.
I am using same MySQL table to store password from different program. One is written in Java and another is written in PHP.
I am saving password via PHP using this script:
encrypted_password= md5(md5('added_salt').md5(md5('plain_password')));
I need to encrypt password in Java using MD5 and salt like above. I write code in Java but it's output is different:
MessageDigest md = MessageDigest.getInstance("MD5");
String salts = "a,d,d,e,d,_,s,a,l,t";
String salttmps[] = salts.split(",");
byte salt[] = new byte[salttmps.length];
for (int i = 0; i < salt.length; i++) {
salt[i] = Byte.parseByte(salttmps[i]);
}
md.update(salt);
md.update(password.getBytes());
byte byteData[] = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
password = sb.toString();
I need to correct Java code and generate output same as PHP.
If you could post an example of output in your question, it would be better to reproduce the algorithm.
I guess you should do something like this:
public static void main(String[] args) {
try {
System.out.println(md5(md5("added_salt"), md5("plain_password")));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static String md5(String plainText) throws NoSuchAlgorithmException {
return md5(null, plainText);
}
public static String md5(String salt, String plainText)
throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
if (salt != null) {
md.update(salt.getBytes());
}
md.update(plainText.getBytes());
byte byteData[] = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16)
.substring(1));
}
return sb.toString();
}
md5(md5("added_salt"), md5("plain_password")) returns 3bd9e544ab1a3d3485f07af38cc1b415
I understand how it works but if I want to print out the MD5 as String how would I do that?
public static void getMD5(String fileName) throws Exception{
InputStream input = new FileInputStream(fileName);
byte[] buffer = new byte[1024];
MessageDigest hash = MessageDigest.getInstance("MD5");
int read;
do {
read = input.read(buffer);
if (read > 0) {
hash.update(buffer, 0, read);
}
} while (read != -1);
input.close();
}
You can get it writing less:
String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))
String input = "168";
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5sum = md.digest(input.getBytes());
String output = String.format("%032X", new BigInteger(1, md5sum));
or
DatatypeConverter.printHexBinary( MessageDigest.getInstance("MD5").digest("a".getBytes("UTF-8")))
Try this
StringBuffer hexString = new StringBuffer();
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest();
for (int i = 0; i < hash.length; i++) {
if ((0xff & hash[i]) < 0x10) {
hexString.append("0"
+ Integer.toHexString((0xFF & hash[i])));
} else {
hexString.append(Integer.toHexString(0xFF & hash[i]));
}
}
You can also use Apache Commons Codec library.
This library includes methods public static String md5Hex(InputStream data) and public static String md5Hex(byte[] data) in the DigestUtils class.
No need to invent this yourself ;)
First you need to get the byte[] output of the MessageDigest:
byte[] bytes = hash.digest();
You can't easily print this though (with e.g. new String(bytes)) because it's going to contain binary that won't have good output representations. You can convert it to hex for display like this however:
StringBuilder sb = new StringBuilder(2 * bytes.length);
for (byte b : bytes) {
sb.append("0123456789ABCDEF".charAt((b & 0xF0) >> 4));
sb.append("0123456789ABCDEF".charAt((b & 0x0F)));
}
String hex = sb.toString();
Shortest way:
String toMD5(String input) {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] raw = md.digest(input.getBytes());
return DatatypeConverter.printHexBinary(raw);
}
Just remember to handle the exception.
With the byte array, result from message digest:
...
byte hashgerado[] = md.digest(entrada);
...
for(byte b : hashgerado)
System.out.printf("%02x", Byte.toUnsignedInt(b));
Result (for example):
89e8a9f68ad3c4bba9b9d3581cf5201d
/**
* hashes:
* e7cfa2be5969e235138356a54bad7fc4
* 3c9ec110aa171b57bb41fc761130822c
*
* compiled with java 8 - 12 Dec 2015
*/
public static String generateHash() {
long r = new java.util.Random().nextLong();
String input = String.valueOf(r);
String md5 = null;
try {
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
//Update input string in message digest
digest.update(input.getBytes(), 0, input.length());
//Converts message digest value in base 16 (hex)
md5 = new java.math.BigInteger(1, digest.digest()).toString(16);
}
catch (java.security.NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5;
}
FYI...
In certain situations this did not work for me
md5 = new java.math.BigInteger(1, digest.digest()).toString(16);
but this did
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if ((0xff & digest[i]) < 0x10) {
sb.append("0").append(Integer.toHexString((0xFF & digest[i])));
} else {
sb.append(Integer.toHexString(0xFF & digest[i]));
}
}
String result = sb.toString();
Call hash.digest() to finish the process. It will return an array of bytes.
You can create a String from a byte[] using a String constructor, however if you want a hex string you'll have to loop through the byte array manually and work out the characters.
This is another version of #anything answer:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if ((0xff & digest[i]) < 0x10) {
sb.append("0").append(Integer.toHexString((0xFF & digest[i])));
} else {
sb.append(Integer.toHexString(0xFF & digest[i]));
}
}
String result = sb.toString();