How to turn a MD5 Hash to a String? - java

I want to turn an MD5 Hash to a string:
public String MD5ToString(String plain) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(plain.getBytes());
byte[] digest = md.digest();
BigInteger bigInt = new BigInteger(1,digest);
String hashtext = bigInt.toString(16);
// Now we need to zero pad it if you actually want the full 32 chars.
while(hashtext.length() < 32 ){
hashtext = "0"+hashtext;
}
return plain;
} catch (Exception e) {
System.out.println("Cannot encrypt String to Hash");
e.printStackTrace();
}
return null;
}
However i just get the Md5 back? Whats ms mistake?
UPDATE:
I changed the return type to hashtext, BUT when I want to convert a hash to a string I just get another has back:
String: test
Hash: 098f6bcd4621d373cade4e832627b4f6
String: fb469d7ef430b0baf0cab6c436e70375

I didn't analyze the code carefully but you return the object plain which has not changed. You should return hashText object if you want to get MD5 string returned from the method.

To have a usable string that you can send or store easily, the usual solution is to encode it in base64 (it's about 33% shorter than in hexa).
Here's one of the numerous tutorials you can find with Google : http://www.javatips.net/blog/2011/08/how-to-encode-and-decode-in-base64-using-java
In your precise case, as you seem to want the hexa representation, maybe you simply want to change
return plain;
to
return hashtext;

I changed the return type to hashtext, BUT when I want to convert a hash to a string I just get another hash back.
You seem to be under a misapprehension of what hashes are.
In general, hashing is a non-reversible transformation. You turn the hash back into a copy of the original string / object / whatever ... because much / most of the information content of the original has been thrown away. Indeed, there are an infinite number of possible input strings that hash to a given hash value, and there is no way of knowing which one is the right one. (They are all right.)
In the case of cryptographic hash functions like MD5, it is even worse. These functions are specifically designed to be non-reversible. Or more precisely, they are designed such that for a given the hash, the problem of recovering a possible input is computationally intractable.
Now it so happens that MD5 is weak ... and that if you have a large (but technically feasible) amount computational resources and time it is possible to reverse the hash. However, that doesn't address the first bullet point.
The bottom line is that if you want to be able to recover the original string you need to encrypt it rather than hash it.

Related

How to generate an MD5 Hash in this way?

I know how to generate an MD5 Hash for a single string,
But what if I want to generate it like this:
String hash1 = GenHash(username:realm:password);
where the username and realm is fixed, the password is read from a text file which contain many words, and I want each of the words convert into md5 hash...
How can I do this ?
The reason why Neil is so adamant about not using MD5 (and he's right, by the way) is that MD5 is vulnerable to attack. This means that passwords could be recovered if an attacker finds the hash output. Since hashing passwords is generally done so that the preimage (i.e. the password) won't be revealed if the hash is found, you are strongly (oh so strongly) advised against using MD5. (In fact, if you're in business and you use MD5 for passwords, have fun with the negligence lawsuit. [Not legal advice]) Neil recommends some good hash algorithms. (Details of why MD5 is vulnerable are far beyond the scope of this question.)
Okay. Your question is how you hash multiple things together.
In order to hash multiple things together, you generally just concatenate them or otherwise just hash them in order without calling "digest()". (The order does matter, by the way.) In your case, since you have a wrapper on the hashing function, you would merely concatenate the strings together before hashing them.
String username = "myName";
String realm = "Narnia";
String password = "secret";
String hash = GenHash(username + realm + password);
In everyone else's case, they are probably using the standard Java MessageDigest, so they would call digest multiple times... after converting their strings to byte arrays. (Note that you're going to want to specify an encoding when converting a String to a byte array to ensure it's always done the same way, otherwise your hash function may return different results on different machines.)
byte[] usernameBytes; //Set equal to perhaps UTF32 encoding of the string
byte[] realmBytes; //Set equal to perhaps UTF32 encoding of the string
byte[] passwordBytes; //Set equal to perhaps UTF32 encoding of the string
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(usernameBytes); //Updates digest with these bytes
md.update(realmBytes); //Updates digest with these bytes
md.update(passwordBytes); //Updates digest with these bytes
byte[] hashResult = md.digest(); //Outputs result
//Insert code to convert the byte array to an outputtable form (or perhaps you're writing to a binary file)
But remember: using Strings presents a security vulnerability!
Strings should never be used for passwords since the string values cannot be guaranteed to be deleted (since they reside on the heap and are therefore "deleted" by the garbage collector whenever it maybe gets around to it, and by "deleted" I mean deallocated, not deleted). An attacker obtaining access to a memory dump could read the password. (Admittedly you have other problems if an attacker gets a memory dump, but don't make it worse.)
It is preferred that a char[] is used for all passwords or other very-sensitive text values. You would therefore create a new char array of size (username.length() + realm.length() + password.length()) then iterate over each of your strings and add each character to the new array... which you would then hash... then you would wipe all sensitive text values that you are no longer using (by iterating over each array and setting each element equal to (char)0).
Again, you cannot manually delete or wipe a string, but you can manually wipe a char or char[].
Why is char[] preferred over String for passwords?
While you're at it, look up password or hash salting. It may be useful for what you're doing.

Proper way to find the SHA-1 hash of two big integers and return it as a string

I would like to hash two BigIntegers in Java with the MessageDigest class.
So far I have the following code
// SHA(v concantenated with n)
public void calculateProversCertificate(BigInteger v, BigInteger n)
{
MessageDigest md;
try
{
md = MessageDigest.getInstance("SHA-1");
md.update(v.toByteArray());
md.update(n.toByteArray());
byte[] byteData = md.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteData.length; i++)
{
sb.append(Integer.toString((byteData[i] & 0xFF) + 0x100, 16).substring(1));
}
String hash = sb.toString();
System.out.println("Certificate:" + hash);
}
catch (NoSuchAlgorithmException ex)
{
System.out.println("Could not create SHA MessageDigest class");
}
}
The code I have there is works to calculate a hash but it is not the proper length when printed as a string. I used this code to create "cookies" from user passwords and I would like to adapt it to find the hash of two BigIntegers. I am specifically not sure about the for loop and how it works. I assume it is rejoining the Byte[] into something that can be represented as a string. Though this is a little over my head on how it does this.
Could someone explain the idea behind the loop, and how it is building the string? Also how I might adapt it to produce an output like the example below?
Basically I am looking for output something like this
1tdgsp8bs0gk72dbvpu0be33tv2dobimc4mg07d209401mrhbe23qe1tdh7jcd78so46ffet20lqemlakv4mfvbk6fjp9a2th9bhb2
But I am getting something like this (Produced by the print statement in the code)
9aa1770b83257b2c7b2a6fb9684253930781c0cf
And example V and N (Produced by BigInteger.toString();)
V: 1678202601632665039275603893340186995409970283833828187403506666684692322312620073622777464636561237395218125410336245265888297965169878433803688272535099
N: 8449118772240198089422438092628650298318511756191052993769148184590886001852753186246607550316706472668220614311553576373631078947139889888957411418229019
That loop looks like it's a convoluted way of turning a byte array into a hexadecimal string. It takes each byte value, applies a hideous function to turn it into two hex characters, and appends them to a StringBuilder.
I don't know why the author didn't just use Integer.toHexString, or, even better, String.format inside the loop. Either of those would be much easier than what you have now.
Note that byteData[i] & 0xFF does nothing (except promote to int, which you don't need since byte values can auto-promote to int). byteData[i] is a byte, and executing & 0xFF on a byte value is a no-op.
Anyway, this code appears to be generating the right output. SHA-1 generates a 160-bit hash, and that looks like a 40-character hex string. Hex encodes 4 bits per character, so that seems to be a valid encoding of the hash value (40 characters * 4 bits per character = 160 bits in the hash)
Basically I am looking for output something like this
1tdgsp8bs0gk72dbvpu0be33tv2dobimc4mg07d209401mrhbe23qe1tdh7jcd78so46ffet20lqemlakv4mfvbk6fjp9a2th9bhb2
Where did you get that string from? Why do you expect your hash output to look like that?
Incidentally, I hope you are not really implementing your own certificate check. Crypto code is notoriously difficult to get right so you should be using an existing library. If you roll your own crypto you will have a vulnerability (probably many vulnerabilities).

SHA hashes same string into different blobs

I am using the following code to hash an incoming string, in expecting that same thing applied to the method multiple times will always get the same results. The scenario will be for password hashing and later verification. But it doesn't seem to work - I got two different blobs for the same input string. Is there anything wrong or missing with my code?
public synchronized String encrypt(String token) {
try {
MessageDigest sha = MessageDigest.getInstance("SHA");
sha.reset();
sha.update(token.getBytes("UTF-8"));
byte[] raw = sha.digest();
System.out.println("raw = " + raw.toString());
String hash = Base64.encodeBase64(raw).toString();
return hash;
} catch (Exception e) {
}
return token;
}
You haven't really given enough information, but I suspect you're being distracted by this:
System.out.println("raw = " + raw.toString());
That's going to print out something like [B#30a4effe which has nothing to do with the data in the byte array. You should print out hash instead - which should be the same for all calls, if your token is genuinely the same.
(As noted by Dan, your method is inappropriately named: hashing isn't encryption. Also, please don't catch Exception or just swallow exceptions like this. It seems pretty odd to just return token on failure, too.)
EDIT: As noted, I've assumed that Base64.encode actually returns a String, which it may not. I'd recommend this base64 implementation which is public domain and has a sensible API - the encoding calls return a String, which is entirely appropriate. Of course, you then don't need the explicit toString() call as well...
I don't know what Base64 class you are using, but I will assume the one from Apache Commons. You are doing this:
String hash = Base64.encodeBase64(raw).toString();
Which is calling the toString method on whatever random byte array is returned from the Base64.encodeBase64() method. That is why your result is random every time, you are just returning an object reference as a String. Try this instead:
String hash = Base64.encodeBase64String(raw);
EDIT
As pointed out in another post, converting directly to String is probably a bad idea. I edited my answer slightly to reflect that.

Need algorithm to protect string with password?

I am looking for a simple and FAST algorithm to encrypt/decrypt a string (length is about 128 bytes) with a password.
Any good algorithms?
ADDED: Custom algorithm is absolutely OK. Less memory it take - better it is (for my case). No extra classes - perfect.
AES Algorithm : Implementation
AES is a federal standard for
private-key or symmetric cryptography.
It supports combinations of key and
block sizes of 128, 192, and 256.
How about IDEA - International Data
Encryption Algorithm ?
IDEA is the name of the patented and
universally applicable block
encryption algorithm, which permits
the effective protection of
transmitted and stored data against
unauthorized access by third parties.
See for the implementation : How to implement IDEA?
AES or 3DES are pretty "standard" symmetrical key encryptions. Blowfish is another.
Check http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html for using AES with Java, for instance.
Side note: If this is intended for securing something like passwords, you should really use a one-way hashing method instead (like MD5 or similar). Unless you absolutely have to be able to decrypt the text, one-way hashing is much safer. When, for instance, storing passwords in a database you would hash the password (with something like MD5) and store it. Validating a login is then done by hashing the user input and comparing it with the hashed value stored in the database.
See Java Crypto! for Encryption and Decryption
There is the Tiny Encryption Algorithm ( http://en.wikipedia.org/wiki/XXTEA ).
It's pretty simple and fast (for an encryption algorithm) and there are Java implementations.
Here is a simple encryption/decryption method. It is pretty weak, so I present it for, say education purpose:
public static String encDec(String input, String password) {
byte[] in = input.getBytes();
byte[] key = password.getBytes();
byte[] result = new byte[in.length];
int k = 0;
for (int i = 0; i < in.length; i++) {
result[i] = (byte)(in[i] ^ key[k]);
k++;
if (k == key.length)
k=0;
}
return new String(result);
}
It simply xors the bytes of a phrase with the bytes of a password. The same method can be used to encrypt and decrypt. Not a big challenge for a crypto analyst, by the way, but an easy start if you just need to obfuscate some data.
To make it a slightly better: don't pass a password String but a byte array with random values. But you wanted a method with a password, that's why I've implemented it that way ;)

Why doesn't my implementation of ElGamal work for long text strings?

I'm playing with the El Gamal cryptosystem, and my goal is to be able to encipher and decipher long sequences of text.
El Gamal requires the plaintext to be an integer. I have turned my string into a byte[] using the .getBytes() method for Strings, and then created a BigInteger out of the byte[]. After encryption/decryption, I turn the BigInteger into a byte[] using the .toByteArray() method for BigIntegers, and then create a new String object from the byte[].
I am using a 1035 bit key, and this works perfectly when I encipher/decipher with strings up to 129 characters. With 130 or more characters, the output produced from my decipher method is garbled.
Can someone suggest how to solve this issue?
Just like in RSA, you cannot encrypt a value larger than the modulus in ElGamal.
You can try
BigInteger pText = new BigInteger(plaintext.getBytes("UTF-8"));
to make the encoding/decoding and enciphering/deciphering more symmetric, but I'm not sure if that's the root cause.
By the way, you should never silently consume an Exception. The very least you can do is just catch (UnsupportedEncodingException e).
You need to use positive numbers for your operations. So you must construct BigInteger like this,
BigInteger pText = new BigInteger(1, plaintext.getBytes());
// 1: select a random integer k such that 1 <= k <= p-2
BigInteger k = abs(new BigInteger(p.bitLength() - 2, sr));
If you want to encrypt certain data with asymmetric cryptographic algorithm, you can do this only for really short data block. The reasons are both "technical" (the algorithm works this way) and "practical" (asymmetric cryptography is slow).
The right way to encrypt the large block of data using asymmetric cryptographic algorithm is
generate random ("session") key for some symmetric algorithm (AES, RC4, 3DES, you name it).
use this algorithm to encrypt the data
use your asymmetric algorithm to encrypt the session key
store the encrypted key near the data.
stop reinventing the wheel

Categories

Resources