I am trying to translate java code to c#. I'm kind of stuck on this exercise below:
MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(pass.getBytes());
byte[] enc = md.digest();
StringBuilder hex = new StringBuilder();
for (int i = 0; i < enc.length; i++) {
String h = Integer.toHexString(0xFF & enc[i]);
hex.append((h.length() == 2) ? h : ("0" + h));
}
This is what I have tried but I am not getting the desired result which would be the following string: "e81e26d88d62aba9ab55b632f25f117d"
My Code:
using System.Security.Cryptography;
using System.Text;
string user_password = "HELLOWORLD";
byte[] hashBytes = Encoding.UTF8.GetBytes(user_password);
SHA1 sha1 = SHA1Managed.Create();
byte[] cryptPassword = sha1.ComputeHash(hashBytes);
user_password = Encoding.Default.GetString(cryptPassword);
StringBuilder hex = new StringBuilder();
for (int i = 0; i < cryptPassword.Length; i++)
{
// Store integer 182
int intValue = cryptPassword[i];
// Convert integer 182 as a hex in a string variable
string hexValue = intValue.ToString("X");
// Convert the hex string back to the number
int intAgain = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);
hex.Append((intAgain.ToString().Length == 2) ? intAgain : ("0" + intAgain.ToString()));
}
Console.WriteLine("pass: " + hex.ToString());
Does anyone know the answer?
Main issue is you are using SHA1 function instead of MD5. Also Im not sure why you are looping over the password length. Every MD5 hash will be the same length regardless of input size.
using System;
using System.Security.Cryptography;
using System.Text;
string user_password = "HELLOWORLD";
byte[] hashBytes = Encoding.UTF8.GetBytes(user_password);
var md5 = MD5.Create();
var hash = md5.ComputeHash(hashBytes);
StringBuilder hex = new StringBuilder();
foreach (byte b in hash)
hex.AppendFormat("{0:x2}", b);
Console.WriteLine("pass: " + hex);
return ;
Related
I need to implement 256 bit AES encryption for cash flow i have c# answer but the answer is not the same,for a newbie, I am not sure if my direction is correct.
this is my code
public static void main(String[] args) {
String key = "12345678901234567890123456789012";
String hashIv = "1234567890123456";
String value = "MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest";
String result = encrypt(key, hashIv, value);
System.out.println(result);
System.out.println();
String sha256 = encrySha256("HashKey=" + key + "&" + result + "&HashIV=" + hashIv);
System.out.println(sha256.trim());
}
public static String encrypt(String hashKey, String hashIv, String text) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(hashKey.getBytes("UTF-8"), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(hashIv.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal((text.getBytes("UTF-8")));
String test = bytesToHex(encrypted);
return test.toLowerCase();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return null;
}
public static String bytesToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
public static String encrySha256(String value) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(value.getBytes());
byte byteBuffer[] = messageDigest.digest();
StringBuffer strHexString = new StringBuffer();
for (int i = 0; i < byteBuffer.length; i++) {
String hex = Integer.toHexString(0xff & byteBuffer[i]);
if (hex.length() == 1) {
strHexString.append('0');
}
strHexString.append(hex);
}
return strHexString.toString().toUpperCase();
} catch (Exception e) {
}
return null;
}
sample encrypt answer :
ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d
9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9
974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f
984b9d41304ffd879612177c622f75f4214fa
encryptSha256 answer : EA0A6CC37F40C1EA5692E7CBB8AE097653DF3E91365E6A9CD7E91312413C7BB8
this is c# code and this is sample data
[MerchantID] => 3430112 [RespondType] => JSON [TimeStamp] => 1485232229
[Version] => 1.4 [MerchantOrderNo] => S_1485232229 [Amt] => 40 [ItemDesc] =>
UnitTest
public string EncryptAES256(string source)//加密
{
string sSecretKey = "12345678901234567890123456789012";
string iv = "1234567890123456";
byte[] sourceBytes =
AddPKCS7Padding(Encoding.UTF8.GetBytes(source), 32);
var aes = new RijndaelManaged();
aes.Key = Encoding.UTF8.GetBytes(sSecretKey);
aes.IV = Encoding.UTF8.GetBytes(iv);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
ICryptoTransform transform = aes.CreateEncryptor();
return ByteArrayToHex(transform.TransformFinalBlock(sourceBytes, 0,
sourceBytes.Length)).ToLower();
}
private static byte[] AddPKCS7Padding(byte[] data, int iBlockSize)
{
int iLength = data.Length;
byte cPadding = (byte)(iBlockSize - (iLength % iBlockSize));
var output = new byte[iLength + cPadding];
Buffer.BlockCopy(data, 0, output, 0, iLength);
for (var i = iLength; i < output.Length; i++)
output[i] = (byte)cPadding;
return output;
}
private static string ByteArrayToHex(byte[] barray)
{
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
The reason for the different encrypted data is that you compare different plain texts. In your Java code you encrypt the plain text
MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest
and you compare the encrypted data with your reference data
ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa
However, these reference data correspond to a different plain text. The latter you can easily derive by decrypting the reference data with the C# DecryptAES256-method which provides
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest
Here, in contrast to the plain text in your Java code, a &-delimiter is used.
If you use the same plain text the Java encrypt- and the C# EncryptAES256-method provide the same encrypted data (same key, IV and padding supposed; for the latter see EDIT-section).
In the following testcase the plain text from your Java code is used:
encrypt("12345678901234567890123456789012", "1234567890123456", "MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest")
and
EncryptAES256("MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest")
both provide the encrypted data:
ff91c8aa01379e4de621a44e5f11f72ef45b7b9f9663d386da51af13f7f3b8f2b1ed4a3b7ac6b7783402193ea1d766e3046b6acf612d62568ccdbc475e5a14d114273735b069464dcc8281f4e5bf8486eb97d31602c3fe79cfe7140d2848413edad9d96fabf54d103f3d7a9b401c83fa5e4f17b10a280df10b3d61f23e69bbb8
which (as expected) differs from your reference data (with the exception of the first block).
EDIT
There is a second issue concerning the padding: Your C# EncryptAES256-method uses a custom padding provided by the C# AddPKCS7Padding-method which pads to a multiple of 32 bytes.
In contrast, your Java encrypt-method uses PKCS5Padding which pads to a multiple of 16 bytes.
Thus, the encrypted data of the Java encrypt- and the C# EncryptAES256-method differ if the length of the plain text is between 16 * n byte and 16 * (n + 1) - 1 byte with even n (0,2,4,...).
For odd n (1,3,5,...) the encrypted data are identical. In the example above the byte array of the plain text has 116 bytes that is n = 7 (112 <= 116 <= 127) and therefore the encrypted data are the same.
If the Java encrypt-method should use the same padding as the C# EncryptAES256-method you additionally have to implement an analogous Java-method e.g.:
private static byte[] addPKCS7Padding(byte[] data, int iBlockSize)
{
int iLength = data.length;
byte cPadding = (byte)(iBlockSize - (iLength % iBlockSize));
byte[] output = new byte[iLength + cPadding];
System.arraycopy(data, 0, output, 0, iLength);
for (int i = iLength; i < output.length; i++)
output[i] = (byte)cPadding;
return output;
}
and in the Java encrypt-method you have to replace:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
with
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
and also
byte[] encrypted = cipher.doFinal(text.getBytes("UTF-8"));
with
byte[] encrypted = cipher.doFinal(addPKCS7Padding(text.getBytes("UTF-8"), 32));
before:
MerchantID=3430112RespondType=JSONTimeStamp=1485232229Version=1.4MerchantOrderNo=S_1485232229Amt=40ItemDesc=UnitTest
After:
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest
I only add "&" with each parameter, it's work!!!!
try it!!!
(我只加了&就成功拉,你的代碼沒問題,只是參數要加&而已)
I get a problem with php.sha1 and my java code.
My php code
echo base64_encode(sha1("test", TRUE));
qUqP5cyxm6YcTAhz05Hph5gvu9M=
And my java code is:
static String Hash(String input) throws Exception {
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(input.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
sb.append((result[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
}
return base64_encode(sb.toString());
}
output MTAxMDEwMDEwMTAwMTAxMDEwMDA=
How should I change the loop to get equal strings?
This one should works like RAW SHA-1
String base64 =
Base64.getEncoder().encodeToString(MessageDigest.
getInstance("SHA-1").digest(s.getBytes("ISO-8859-1")));
I have a problem to communicating between C# and JAVA. I have to hash a value in my program with SHA1 in JAVA. The problem is, computing hash in JAVA results a byte[] (so do C#, but:) byte type in JAVA is signed, while it's unsigned in C#. So I have to get rid of extra bits in JAVA (the C# side can not be touched). Here is what I'm doing:
private static int[] Hash(byte[] plainBytes, byte[] saltBytes)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
byte[] sourceBytes = new byte[plainBytes.length + saltBytes.length];
for (int i = 0, il = plainBytes.length; i < il; i++)
sourceBytes[i] = plainBytes[i];
for (int i = 0, il = saltBytes.length, pil = plainBytes.length; i < il; i++)
sourceBytes[pil + i] = saltBytes[i];
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
byte[] resultBytes = digest.digest(sourceBytes);
int[] result = new int[resultBytes.length];
for (int i = 0, il = resultBytes.length; i < il; i++)
result[i] = ((int) resultBytes[i]) & 255;
return result;
}
It gives me the correct array. But, the problem is base64 encoding the result. How can I do that without falling in signed byte trap again? I mean how to complete this snippet:
var resultArray = Hash(someSource, someSalt);
var resultBase64EncodedString = HOW_TO_BASE64_ENCODE_HERE(resultArray);
Thanks in advance.
Base64 encoding your resultBytes array with
String base64EncodedString = DatatypeConverter.printBase64Binary(resultBytes);
should give you the same base64 coded string as you get in C# with
SHA1 sha1 = SHA1.Create();
byte[] currentHash = new byte[0];
currentHash = sha1.ComputeHash(sourceBytes);
String base64EncodedString = Convert.ToBase64String(currentHash);
I required to convert string in MD5 hash.
I am using
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
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 );
}
It is giving output like this website http://www.md5.cz/
but I required to generate hash as this http://webcodertools.com/hashstring giving output.
Please use test in both sites.
with using above function I am getting o/p like first site but I need as second site is giving.
Is there any different function or am I missing something in this?
Thanks.
The second web site is simply using base64 instead of hex to represent the binary data as text. So you can get rid of your bytesToHex method entirely, and just use Base64:
String base64Digest = Base64.encodeToString(thedigest, Base64.DEFAULT);
(As an aside, I'd avoid using the as a prefix in variable names - it provides no benefit, and is just cruft.)
Use this method it will return in the same format
public static String getMd5Hash(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes());
BigInteger number = new BigInteger(1, messageDigest);
String md5 = number.toString(16);
while (md5.length() < 32)
md5 = "0" + md5;
return md5;
} catch (NoSuchAlgorithmException e) {
Log.e("MD5", e.getLocalizedMessage());
return null;
}
}
This returns in //4a2028eceac5e1f4d252ea13c71ecec6 format MD5 of "WHAT" and
String base64format = Base64.encodeToString(thedigest, Base64.DEFAULT); //as given by #Jon Skeet
will return in the format as SiAo7OrF4fTSUuoTxx7Oxg==
Sorry for vice-versa solution.
EDIT
I changed $checksum = md5($someString+$bkey); to $checksum = md5($someString.$bkey);
I need to perform the following operations in Java:
$hexString = '90aa';#sample value
$bkey = pack('H*',$hexString);
$someString='qwe';#sample value
$checksum = md5($someString.$bkey);
echo $checksum;
I can't convert hexString to bkey in Java to get the same result as php script. Except bkey everything is working properly.
If I remove bkey then:
PHP:
$someString='qwe';#sample value
$checksum = md5($someString);
echo $checksum;
result: 76d80224611fc919a5d54f0ff9fba446
Java:
String someString = "qwe";
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
String checksum = new BigInteger(1, messageDigest.digest(someString
.getBytes())).toString(16);
System.out.println(checksum);
result: 76d80224611fc919a5d54f0ff9fba446
As you can see, it works
With bkey:
PHP:
$hexString = '90aa';#sample value
$bkey = pack('H*',$hexString);
$someString='qwe';#sample value
$checksum = md5($someString.$bkey);
echo $checksum;
result: 18f5f1a9bf898131945dd9e315759fe4
Java:
public static void main(String[] args) throws NoSuchAlgorithmException {
String hexString = "90aa";
String bkey = hexToString(hexString);
String someString = "qwe";
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
String input = someString + bkey;
String checksum = new BigInteger(1, messageDigest.digest(input
.getBytes())).toString(16);
System.out.println(checksum);
}
public static String hexToString(String hex) {
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i += 2) {
String str = hex.substring(i, i + 2);
output.append((char) Integer.parseInt(str, 16));
}
return output.toString();
}
result: 44bb634dee436833dd65caa5043ffeb9
As you can see results are different.
How to convert hex String to String to get the same result?
The problem is not actually in your Java code, but in the PHP code.
The line $checksum = md5($someString+$bkey); does not do what you think it does, it should be:
$checksum = md5($someString . $bkey); # use concatenate, not sum
Although, that gives abetter PHP MD5, but does not help make the Java code match the PHP
EDIT
The problem on the Java side is in the character encoding. The Java char values for the inoacked versions of 90aa are not valid unicode characters. Thus the toByteArray() ,ethods ar enot doing great things. If you treat all of the Java code at a byte level (and ignore any high-bytes in any chars in the Java), then you get the same result as the PHP:
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
String hexString = "90aa";
byte[] bkey = hexToString(hexString);
String someString = "qwe";
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] input = join(stringToBytes(someString), bkey);
String checksum = new BigInteger(1, messageDigest.digest(input)).toString(16);
System.out.println(checksum);
System.out.println(Charset.defaultCharset().displayName());
}
private static byte[] join(byte[] a, byte[] b) {
// join two byte arrays
final byte[] ret = new byte[a.length + b.length];
System.arraycopy(a, 0, ret, 0, a.length);
System.arraycopy(b, 0, ret, a.length, b.length);
return ret;
}
public static byte[] hexToString(String hex) {
// hexToString that works at a byte level, not a character level
byte[] output = new byte[(hex.length() + 1) / 2];
for (int i = hex.length() - 1; i >= 0; i -= 2) {
int from = i - 1;
if (from < 0) {
from = 0;
}
String str = hex.substring(from, i + 1);
output[i/2] = (byte)Integer.parseInt(str, 16);
}
return output;
}
public static byte[] stringToBytes(final String input) {
// unlike Stirng.toByteArray(), we ignore any high-byte values of the characters.
byte[] ret = new byte[input.length()];
for (int i = input.length() - 1; i >=0; i--) {
ret[i] = (byte)input.charAt(i);
}
return ret;
}
The above Java code produces the MD5sum 18f5f1a9bf898131945dd9e315759fe4 which is what PHP gives too