I use the following code for generating md5 for blob data in database.
md5Checksum.update(byte[] --- read from database);
String result = new BigInteger(1,md5Checksum.digest()).toString(16);
The checksum i obtain is varying in length(30-32) for different byte arrays.
For 31 char length checksum, as I understood can be an effect of the removal of leading zeros. (I handled it by adding leading zeros)
Can any one tell me why I am getting a 30 char hash in some cases?
Thanks,
Mithun
Do not convert a digest to a number!
Use something like:
byte[] b = md5Checksum.digest();
// now convert these bytes to chars
There are many different methods to convert byte[] to HexStrings:
public class HexConverter {
// thanks to http://www.rgagnon.com/javadetails/java-0596.html
static private final String HEXES = "0123456789ABCDEF";
public String toHex(byte[] raw) {
if (raw == null) {
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
}
or from Getting a File's MD5 Checksum in Java
(this link also shows how to se DigestUtils from Apache Commons Codec)
public static String getMD5Checksum(String filename) throws Exception {
byte[] b = createChecksum(filename);
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
There is a chance that the high n bits could be zero. As you convert the byte[] to a number.If n=4,then you could lose one '0' char at the beginning.
If n=8, then you lose '00' at the beginning of your md5 hex code.
Related
private String getString(byte[] bytes)
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
sb.append(0xFF & b);
}
return sb.toString();
}
public String encrypt(String source)
{
try
{
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(source.getBytes());
return getString(bytes);
}
catch (Exception e)
{
e.printStackTrace(); }
return null;
}
If my text = "test"
The First Part toString()) produces a value of "Encryption$2#6966b26b"
And the second part then gets that and produces a value of "91431072057033211115202222781313839180246"
But why is the md5 a number and not 31f521a06d5060d1f38159c74a1f7cf2 or something similar?
The function "encrypt()" returns a MD5 hash. You should rename it to "hash", because hashing != encrypting.
If you want to encrypt a string, you can look here: https://gist.github.com/bricef/2436364
It's clearly stated in code yuou are using MD5 hashing algorithm
Now your question is why:
But why is the md5 a number and not 31f521a06d5060d1f38159c74a1f7cf2 or something similar?
your answer is simple, look at code which generates you string from your byte array.
byte b = bytes[i];
sb.append(0xFF & b);
you take byte, ie 0x20 then you perform logical and operation with integer 0x255 and then you add decimal representation of result yo your StringBuilder.
What you want to do is more like
sb.append(Integer.toHexString(0xff&b));
I would say MD5 hash, because the code says MessageDigest.getInstance("MD5") :D
I am using this function to calculate the SHA 256
public static String getSHA1(String plainText) {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(plainText.getBytes(Charset.forName("UTF-8")));
StringBuffer hexString = new StringBuffer();
byte[] bytes = md.digest();
for (int i = 0; i < bytes.length; i++) {
hexString.append(Integer.toHexString(0xFF & bytes[i]));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
And to be sure of my results, I check this online website
http://onlinemd5.com/
the results between my code and the online is almost the same, but you know that it must be equal. for instance
my plain testis:
1234567
the website result
8BB0CF6EB9B17D0F7D22B456F121257DC1254E1F01665370476383EA776DF414
my code result
8bb0cf6eb9b17df7d22b456f121257dc1254e1f1665370476383ea776df414
and this is more examples:
7777777
8C1CDB9CB4DBAC6DBB6EBD118EC8F9523D22E4E4CB8CC9DF5F7E1E499BBA3C10
8c1cdb9cb4dbac6dbb6ebd118ec8f9523d22e4e4cb8cc9df5f7e1e499bba3c10
147258
7A2EC40FF8A1247C532309355F798A779E00ACFF579C63EEC3636FFB2902C1AC
7a2ec4ff8a1247c53239355f798a779e0acff579c63eec3636ffb292c1ac
888888
92925488B28AB12584AC8FCAA8A27A0F497B2C62940C8F4FBC8EF19EBC87C43E
92925488b28ab12584ac8fcaa8a27af497b2c6294c8f4fbc8ef19ebc87c43e
I do know that this is maybe about the encoding. but look i used utf-8 which is what the website used
This is the problem:
hexString.append(Integer.toHexString(0xFF & bytes[i]));
This will lose any leading 0s - in other words, any byte less than 16 will come out as a single hex digit instead of two.
There are plenty of fixes for this. For example:
Manually append 0 if the value is between 0 and 15 (ick)
Use String.format("%02x", bytes[i] & 0xff)
Use a full "byte array to hex conversion" method in a utility library (there are loads around)
I'm trying to create a program that will enable me to convert a MEID (a hex number of length 14) to pseudo ESN (a hex number of length 8). The way to obtain a pESN from MEID is fairly simple in theory. For example, given MEID 0xA0000000002329, to make a pESN, SHA-1 needs to be applied to the MEID. SHA-1 on A0000000002329 gives e3be267a2cd5c861f3c7ea4224df829a3551f1ab. Take the last 6 hex numbers of this result, and append it to 0x80 - the result is 0x8051F1AB.
Now here is the code I have so far:
public void sha1() throws NoSuchAlgorithmException {
String hexMEID = "A0000000002329";
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] b = new BigInteger(hexMEID,16).toByteArray();
byte[] result = mDigest.digest(b);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < result.length; i++) {
sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println(sb.toString());
}
The problem is that using this method, SHA-1 on A0000000002329 gives 6ad447f040941bf43c0693d2b391c6c79fa58320 instead of e3be267a2cd5c861f3c7ea4224df829a3551f1ab. What am I doing wrong here??
Someone gave me a hint that
The trick is to apply SHA-1 to the number representing the MEID, not
the string representing the MEID. You'll need to process it
byte-by-byte, so you must give it two hex numbers at a time (since two
hex numbers make a byte) and make sure they are interpreted as numbers
and not ASCII characters.
If these instructions are true, then how do I apply SHA-1 to my hex number byte by byte??
You have a tiny little issue which is the consequence of using BigInteger to get your byte array. Since the MEID is only 7 bytes long, when you pump it through the BigInteger, you will get a byte array of length 8 because the BigInteger outputs the exta byte which holds the sign. This extra byte causes the SHA-1 hash of your input to be completely different, of course. You need to strip it off.
So here is what the HEX MEID to ESN code will look like:
String hexMEID = "A0000000002329";
MessageDigest mDigest = MessageDigest.getInstance( "SHA1" );
byte[] input = new byte[ 7 ]; // MEIDs are only 7 bytes
// Now copy the bytes from BigInteger skipping the extra byte added by it
System.arraycopy( new BigInteger( hexMEID, 16 ).toByteArray(), 1, input, 0, 7 );
// Get the SHA-1 bytes
byte[] result = mDigest.digest( input );
// Build the SHA-1 String
StringBuilder sb = new StringBuilder();
for ( int i = 0; i < result.length; i++ )
{
String hex = Integer.toHexString( 0xFF & result[ i ] );
if ( hex.length() == 1 )
{
sb.append( '0' );
}
sb.append( hex );
}
String sha1 = sb.toString();
// Grab the last 6 characters of the SHA-1 hash
String lastSix = sha1.substring( sha1.length() - 6 );
// And prepend '80', now you have the ESN
System.out.println( "80" + lastSix );
// Will print 8051f1ab which is exactly what you want
Strelok has found the problem about BigInteger adding an extra byte in the returned array. This simpler version also gives the expected result :
String hexMEID = "A0000000002329";
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] b = new BigInteger(hexMEID,16).toByteArray();
// skip the first byte set by BigInteger and retain only 7 bytes (length of MEID)
byte[] result = mDigest.digest(Arrays.copyOfRange(b, 1, 8));
StringBuilder sb = new StringBuilder("80");
// need only the last 3 bytes
for (int i=17; i<20; i++) {
sb.append(Integer.toHexString((result[i] & 0xff) | 0x100).substring(1));
}
String pESN = sb.toString();
System.out.println(pESN);
// -> 8051f1ab
I'm trying to achieve this:
I have a PDF byte[] in java web service that I must send as a base64 string to a .NET client that does this to reconstruct the file.
Encoding.Convert(Encoding.Unicode, Encoding.Default, Convert.FromBase64String(inputJava))
I cannot change the client code and right now the java web service is calling another .NET web service that does this to turn the byte[] into a base64 string:
System.Text.Encoding.Convert(System.Text.Encoding.GetEncoding(1252), System.Text.Encoding.Unicode, b);
Beside the base64 that I can make in various ways (e.g. with org.apache.commons.codec.binary.Base64), I have to turn the original byte[] into a UTF-16LE byte[]...
I tried this:
byte[] output = new byte[b.length * 2];
for(int i=0; i < b.length; i++)
{
int val = b[i];
if(val < 0) val += 256;
output[2*i + 0] = (byte) (val);
output[2*i + 1] = 0;
}
This works fine for values below 128 (e.g. for 1 => 0100, 2 => 0200, ... , 127 => 7F00) but for values above (128 -> 255) I don't know how to get the equivalent 2bytes values; I know that for byte 156 (9C) the corresponding value is 8301 (0x5301) and for byte 224 (E0) the corresponding value is 12501 (0x7D01) but I didn't manage to find an algorithm to get all the other values.
Is there a mapping table between byte value and the corresponding UTF-16LE surrogate pair or an algorithm to map values from 128 to 255?
Thanks in advance!
You don’t need surrogate pairs; they are a construct for dealing with characters outside Basic Multilingual Plane (BMP), and all windows-1252 characters are in BMP.
The official windows-1252 (alias cp1252) to Unicode mapping table is
http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
It’s a plain text file in easy-to-process format, so if you don’t find an existing tool for the conversion, it should be rather straightforward to write mapping based on that file.
The file is indirectly cited in the official IANA registry:
http://www.iana.org/assignments/character-sets
byte[] encoded = new String(b, "windows-1252").getBytes("UTF-16LE");
I finally found a solution. It looks like that only bytes from 128 to 159 need the surrogate pairs. I use this piece of code to emulate .NET Unicode encoding:
public class Encoder {
static Map<Integer, Integer> mapTiny = new HashMap<Integer, Integer>() {
public Integer get(Object key) {
Integer code = super.get(key);
if (code == null)
code = (Integer) key;
return code;
}
};
static {
mapTiny.put(128,8364);
mapTiny.put(130,8218);
mapTiny.put(131,402);
mapTiny.put(132,8222);
mapTiny.put(133,8230);
mapTiny.put(134,8224);
mapTiny.put(135,8225);
mapTiny.put(136,710);
mapTiny.put(137,8240);
mapTiny.put(138,352);
mapTiny.put(139,8249);
mapTiny.put(140,338);
mapTiny.put(142,381);
mapTiny.put(145,8216);
mapTiny.put(146,8217);
mapTiny.put(147,8220);
mapTiny.put(148,8221);
mapTiny.put(149,8226);
mapTiny.put(150,8211);
mapTiny.put(151,8212);
mapTiny.put(152,732);
mapTiny.put(153,8482);
mapTiny.put(154,353);
mapTiny.put(155,8250);
mapTiny.put(156,339);
mapTiny.put(158,382);
mapTiny.put(159,376);
}
public static String encode(byte[] b) throws IOException {
ByteArrayInputStream in = new ByteArrayInputStream(b);
ByteArrayOutputStream convFileByteArray = new ByteArrayOutputStream();
int i = in.read();
while (i != -1) {
convFileByteArray.write(new byte[] { (byte) (mapTiny.get(i) & 0xff), (byte) ((mapTiny.get(i) >> 8) & 0xff) });
i = in.read();
}
return Base64.encodeToString(convFileByteArray.toByteArray(), false);
}
}
in the last 5 hours im trying to do something that should be very simple and did it in like 10 minutes in C#, but no luck with Java.
I got a 32 UpperCase and Numeric String (A-Z0-9), I need to convert this String to Dec, and then md5 it.
My problem is that I dont have unsgined bytes so I cant md5 my array :\
Here is what I need to do in python:
salt = words[1].decode("hex")
passwordHash = generatePasswordHash(salt, pw)
generatePasswordHash(salt, password):
m = md5.new()
m.update(salt)
m.update(password)
return m.digest()
and here it is in C# :
public static string GeneratePasswordHash(byte[] a_bSalt, string strData) {
MD5 md5Hasher = MD5.Create();
byte[] a_bCombined = new byte[a_bSalt.Length + strData.Length];
a_bSalt.CopyTo(a_bCombined, 0);
Encoding.Default.GetBytes(strData).CopyTo(a_bCombined, a_bSalt.Length);
byte[] a_bHash = md5Hasher.ComputeHash(a_bCombined);
StringBuilder sbStringifyHash = new StringBuilder();
for (int i = 0; i < a_bHash.Length; i++) {
sbStringifyHash.Append(a_bHash[i].ToString("X2"));
}
return sbStringifyHash.ToString();
}
protected byte[] HashToByteArray(string strHexString) {
byte[] a_bReturn = new byte[strHexString.Length / 2];
for (int i = 0; i < a_bReturn.Length; i++) {
a_bReturn[i] = Convert.ToByte(strHexString.Substring(i * 2, 2), 16);
}
return a_bReturn;
}
I will be very happy to get a help with this :)
To parse a hex string into a byte : (byte) Integer.parseInt(s, 16).
To transform your password string into a byte array, using the default encoding (which I suggest not to do : always specify a specific encoding) : password.getBytes() (or password.getBytes(encoding) for a specific encoding).
To hash a byte array : MessageDigest.getInstance("MD5").digest(byte[]).
To transform a byte to a hex String : See In Java, how do I convert a byte array to a string of hex digits while keeping leading zeros?
I believe that something like the following will work:
// convert your hex string to bytes
BigInteger bigInt = new BigInteger(salt, 16);
byte[] bytes = bigInt.toByteArray();
// get the MD5 digest library
MessageDigest md5Digest = null;
try {
md5Digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// error handling here...
}
// by default big integer outputs a 0 sign byte if the first bit is set
if (bigInt.testBit(0)) {
md5Digest.update(bytes, 1, bytes.length - 1);
} else {
md5Digest.update(bytes);
}
// get the digest bytes
byte[] digestBytes = md5Digest.digest();
Here's more ideas for converting a hex string to a byte[] array:
Convert a string representation of a hex dump to a byte array using Java?
You can use unsigned numbers in java with applying bit masks. Take a look details here.