MD5 hash in android or java - java

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.

Related

Java 256-bit AES Encryption

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!!!
(我只加了&就成功拉,你的代碼沒問題,只是參數要加&而已)

SHA-512 hashing with Android

I was wondering if I can SHA-512 hash a string on Android Studio without a salt.
I've seen other questions, but they all involve the salt, but I want something like this:
TestBox.text = sha512("Hello, world!");
And TextBox will read c1527cd893c124773d811911970c8fe6e857d6df5dc9226bd8a160614c0cd963a4ddea2b94bb7d36021ef9d865d5cea294a82dd49a0bb269f51f6e7a57f79421;
The other questions you saw use salt so just don't use salt like so:
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] digest = md.digest("Hello, world!".getBytes());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
sb.append(Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println(sb);
Based on this answer.
Keds example is right, but .length will always be biger than 32, (127) so more correct answer should be
private fun getSHA512(input:String):String{
val md: MessageDigest = MessageDigest.getInstance("SHA-512")
val messageDigest = md.digest(input.toByteArray())
// Convert byte array into signum representation
val no = BigInteger(1, messageDigest)
// Convert message digest into hex value
var hashtext: String = no.toString(16)
// Add preceding 0s to make it 128 chars long
while (hashtext.length < 128) {
hashtext = "0$hashtext"
}
// return the HashText
return hashtext
}
method for calculating sha-512 in kotlin
fun getSHA256(input:String):String{
return MessageDigest
.getInstance("SHA-256")
.digest(input.toByteArray())
.fold("") { str, it -> str + "%02x".format(it) }
}
A more functional solution:
fun sha512(input: String): String {
return MessageDigest.getInstance("SHA-512")
.digest(input.toByteArray())
.joinToString(separator = "") {
((it.toInt() and 0xff) + 0x100)
.toString(16)
.substring(1)
}
}
I guess the equivalent in Kotlin is:
fun encriptar(cadena: String): String {
var md: MessageDigest = MessageDigest.getInstance("SHA-512")
var digest = md.digest(cadena.toByteArray())
var sb: StringBuilder = StringBuilder()
var i = 0
while (i < digest.count()) {
sb.append(((digest[i] and 0xff.toByte()) + 0x100).toString(16).substring(0, 1))
i++
}
return sb.toString()
}

how can i find php md5(sha1("test")) in java

In my existing system, i have hashed the password with the following algorithm in php.
$userId = "testusername";
$password = "testpassword";
echo md5(sha1($userId).sha1($password));
what will be the equivalent method in Java for the above, because i was migrating php to java.
when i tried to search in google, they are talking about MessageDigest method.
In PHP i have used the inbuild md5() and sha1() function
in java, i found the following, but still, its not equivalent.
public static String sha1(String input) {
StringBuilder sb = null;
try{
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.reset();
md.update(input.getBytes());
byte[] bytes = md.digest();
sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
}catch(RuntimeException | NoSuchAlgorithmException e){
throw new RuntimeException(e.getMessage());
}
return sb.toString();
}
public static String md5(String input) {
StringBuilder sb = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.getBytes());
byte[] bytes = md.digest();
sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
} catch (RuntimeException | NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage());
}
return sb.toString();
}
}
You can try bellow example :
class Main {
public static void main(String[] a) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String output, input = "ml";
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digest = md.digest(input.getBytes("UTF-8"));
BigInteger bigInt = new BigInteger(1, digest);
output = bigInt.toString(16);
System.out.println(""+output);
}
}
In the same way you also can generate sha1 just pass "sha1" in MessageDigest.getInstance(); function.
sha1($userId)+sha1($password) completely wrong. To do string concatenation in PHP you need sha1($userId).sha1($password)
The result you're seeing in PHP is actually md5(8) or c9f0f895fb98ab9159f51fd0297e236d. This is because the SHA1 of $password begins with an 8. The rest of the hash is thrown away.
This can not be used as a secure hashing function because there are too many collisions. For example, a password of 12345 has the same hash. You should require users to reset their passwords and use a standard password hashing mechanism instead.

how to base64 encode an unsigned byte array which is actually a int[]

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);

Java equivalent of php pack('H*', str)

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

Categories