The Openbravo software and its derivatives (e.g. unicentaopos) have the following implementation of encryption to store the database password in a plain configuration file.
package com.openbravo.pos.util;
import java.io.UnsupportedEncodingException;
import java.security.*;
import javax.crypto.*;
/**
*
* #author JG uniCenta
*/
public class AltEncrypter {
private Cipher cipherDecrypt;
private Cipher cipherEncrypt;
/** Creates a new instance of Encrypter
* #param passPhrase */
public AltEncrypter(String passPhrase) {
try {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(passPhrase.getBytes("UTF8"));
KeyGenerator kGen = KeyGenerator.getInstance("DESEDE");
kGen.init(168, sr);
Key key = kGen.generateKey();
cipherEncrypt = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");
cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);
cipherDecrypt = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, key);
} catch (UnsupportedEncodingException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
}
}
/**
*
* #param str
* #return
*/
public String encrypt(String str) {
try {
return StringUtils.byte2hex(cipherEncrypt.doFinal(str.getBytes("UTF8")));
} catch (UnsupportedEncodingException | BadPaddingException | IllegalBlockSizeException e) {
}
return null;
}
/**
*
* #param str
* #return
*/
public String decrypt(String str) {
try {
return new String(cipherDecrypt.doFinal(StringUtils.hex2byte(str)), "UTF8");
} catch (UnsupportedEncodingException | BadPaddingException | IllegalBlockSizeException e) {
}
return null;
}
}
To encrypt, the following is used (only the password is encrypted):
config.setProperty("db.user", jtxtDbUser.getText());
AltEncrypter cypher = new AltEncrypter("cypherkey" + jtxtDbUser.getText());
config.setProperty("db.password", "crypt:" + cypher.encrypt(new String(jtxtDbPassword.getPassword())));
To decrypt, the following is used:
String sDBUser = m_App.getProperties().getProperty("db.user");
String sDBPassword = m_App.getProperties().getProperty("db.password");
if (sDBUser != null && sDBPassword != null && sDBPassword.startsWith("crypt:")) {
AltEncrypter cypher = new AltEncrypter("cypherkey" + sDBUser);
sDBPassword = cypher.decrypt(sDBPassword.substring(6));
}
I am working on an independent software module in C# and I'd like to read the database password from that configuration file. Any advice on how to accomplish this?
From analyzing the code, I can deduce that:
The password "encryption" is reversible because it is later used in the software to build database connection strings.
The base passphrase is "cypherkey" + username
The password is stored in the plain file with the format
db.password=crypt:XXX
where XXX is the encrypted password.
Please help me to work out how to decrypt the password. Help on actually reading the plain file is not necessary. Please assume that I already have stored the username and encrypted password (without the "crypt:" part) in variables in the C# program.
I've been trying to modify the existing examples on similar question but they focus on AES and so far I have not been successful with this.
Basically, the following function in C# should be built:
private string DecryptPassword(string username, string encryptedPassword)
How would I do this?
The software is open source and can be found here
One test case: DecryptPassword("mark", "19215E9576DE6A96D5F03FE1D3073DCC") should return the password getmeback. The base passphrase would be cypherkeymark. I have tested in different machines and the "hashed" password is always the same using the same username.
The method used by AltEncrypter to derive a key from the password is terrible. This approach should not be used.
First of all, it's not secure. A key derivation algorithm is not secure unless it is computationally intensive. Instead, use an algorithm like scrypt, bcrypt, or PBKDF2.
Second, the SHA1PRNG algorithm is not well defined. Saying, "it uses SHA-1" isn't sufficient. How often is a hash performed? It's not standardized; you won't be able to request a "SHA1PRNG" on another platform (like .Net), and get the same output.
So, scrap this encryption method and use something easy and secure, written and maintained by knowledgeable people.
Unfortunately, the problems don't end there. The AltEncrypter utility is used in the worst way possible, with a key that isn't secret, to reversibly encrypt an authentication password. This is not secure at all. It allows an attacker to decrypt user passwords and use them against the user's accounts on other systems.
It's almost like the author of this system wanted to create a security catastrophe.
This is a note. I cannot add comments but I think that the algorithm used to encrypt is not SHA1. It is "DESEDE/ECB/PKCS5Padding" look at the line where the cipher to encrypt is created (obtained)
cipherEncrypt = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");
SHA1PRNG is a pseudo-random number generator used to generate a first random number used into the encryption process in order to generate "different" encryptions even when the same plain text is encrypted.
Another important thing is the key used to encrypt, I mean:
KeyGenerator kGen = KeyGenerator.getInstance("DESEDE");
kGen.init(168, sr);
Key key = kGen.generateKey(); <-- this key
this key is used to encrypt and decrypt but I cannot see where it is stored. I mean that it is regenerated every time. It should be stored and retrieved from somewhere and not regenerated because, it is not possible to decrypt any cipher text if it is not used the same key.
This is an answer using some workarounds.
I've tried reimplementing the SHA1PRNG provided the GNU implementation (which is opensource), but it doesn't give the same results as the properitary SUN implementation (so either they're different or I have implemented it in a wrong way). So I've implemented a workaround: Call a java-program to derive the key for us. Yes, this is very cheap, but a working work-around for the time being. If someone sees the mistake in my SHA1PRNG implementation, let me know.
So first, here's a simple Java program which will derive a 168-bit key given a seed using the SHA1PRNG generator. Simply outputs it on stdout, space seperated.
import java.io.UnsupportedEncodingException;
import java.security.*;
import javax.crypto.*;
public class PasswordDeriver {
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
if(args.length == 0){
System.out.println("You need to give the seed as the first argument.");
return;
}
//Use Java to generate the key used for encryption and decryption.
String passPhrase = args[args.length-1];
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(passPhrase.getBytes("UTF8"));
KeyGenerator kGen = KeyGenerator.getInstance("DESEDE");
kGen.init(168, sr);
Key key = kGen.generateKey();
//Key is generated, now output it.
//System.out.println("Format: " + key.getFormat());
byte[] k = key.getEncoded();
for(int i=0; i < k.length; i++){
System.out.print(String.format((i == k.length - 1) ? "%X" : "%X ", k[i]));
}
}
}
This is saved as PasswordDeriver.java, compiled using javac <file> and the resulting PasswordDeriver.class is then placed in the same folder as this compiled program: (The actual C# program)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;
namespace OpenbravoDecrypter
{
class Program
{
static void Main(string[] args)
{
var decrypted = Decrypt("19215E9576DE6A96D5F03FE1D3073DCC", "mark");
Console.ReadLine();
}
static string Decrypt(string ciphertext, string username)
{
//Ciphertext is given as a hex string, convert it back to bytes
if(ciphertext.Length % 2 == 1) ciphertext = "0" + ciphertext; //pad a zero left is necessary
byte[] ciphertext_bytes = new byte[ciphertext.Length / 2];
for(int i=0; i < ciphertext.Length; i+=2)
ciphertext_bytes[i / 2] = Convert.ToByte(ciphertext.Substring(i, 2), 16);
//Get an instance of a tripple-des descryption
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Mode = CipherMode.ECB; //ECB as Cipher Mode
tdes.Padding = PaddingMode.PKCS7; //PKCS7 padding (same as PKCS5, good enough)
byte[] key_bytes = DeriveKeyWorkAround(username);
Console.WriteLine("Derived Key: " + BitConverter.ToString(key_bytes));
//Start the decryption, give it the key, and null for the IV.
var decryptor = tdes.CreateDecryptor(key_bytes, null);
//Decrypt it.
var plain = decryptor.TransformFinalBlock(ciphertext_bytes, 0, ciphertext_bytes.Length);
//Output the result as hex string and as UTF8 encoded string
Console.WriteLine("Plaintext Bytes: " + BitConverter.ToString(plain));
var s = Encoding.UTF8.GetString(plain);
Console.WriteLine("Plaintext UTF-8: " + s);
return s;
}
/* Work around the fact that we don't have a C# implementation of SHA1PRNG by calling into a custom-prepared java file..*/
static byte[] DeriveKeyWorkAround(string username)
{
username = "cypherkey" + username;
string procOutput = "";
//Invoke java on our file
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c java PasswordDeriver \"" + username + "\"";
p.StartInfo.RedirectStandardOutput = true;
p.OutputDataReceived += (e, d) => procOutput += d.Data;
p.StartInfo.UseShellExecute = false;
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
//Convert it back
byte[] key = procOutput.Split(' ').Select(hex => Convert.ToByte(hex, 16)).ToArray();
return key;
}
/* This function copies the functionality of the GNU Implementation of SHA1PRNG.
* Currently, it's broken, meaning that it doesn't produce the same output as the SUN implenetation of SHA1PRNG.
* Case 1: the GNU implementation is the same as the SUN implementation, and this re-implementation is just wrong somewhere
* Case 2: the GNU implementation is not the same the SUN implementation, therefore you'd need to reverse engineer some existing
* SUN implementation and correct this method.
*/
static byte[] DeriveKey(string username)
{
//adjust
username = "cypherkey" + username;
byte[] user = Encoding.UTF8.GetBytes(username);
//Do SHA1 magic
var sha1 = new SHA1CryptoServiceProvider();
var seed = new byte[20];
byte[] data = new byte[40];
int seedpos = 0;
int datapos = 0;
//init stuff
byte[] digestdata;
digestdata = sha1.ComputeHash(data);
Array.Copy(digestdata, 0, data, 0, 20);
/* seeding part */
for (int i=0; i < user.Length; i++)
{
seed[seedpos++ % 20] ^= user[i];
}
seedpos %= 20;
/* Generate output bytes */
byte[] bytes = new byte[24]; //we need 24 bytes (= 192 bit / 8)
int loc = 0;
while (loc < bytes.Length)
{
int copy = Math.Min(bytes.Length - loc, 20 - datapos);
if (copy > 0)
{
Array.Copy(data, datapos, bytes, loc, copy);
datapos += copy;
loc += copy;
}
else
{
// No data ready for copying, so refill our buffer.
Array.Copy(seed, 0, data, 20, 20);
byte[] digestdata2 = sha1.ComputeHash(data);
Array.Copy(digestdata2, 0, data, 0, 20);
datapos = 0;
}
}
Console.WriteLine("GENERATED KEY:\n");
for(int i=0; i < bytes.Length; i++)
{
Console.Write(bytes[i].ToString("X").PadLeft(2, '0'));
}
return bytes;
}
}
}
You can see the standard stuff such as initializing a tripple-DES cryptoprovider, giving it a key and computing the decryption of the ciphertext in there. It also contains the currently broken implementation of the SHA1PRNG and the workaround. Given that java is in the PATH of the current environment variable, this program produces the output:
Derived Key: 86-EF-C1-F2-2F-97-D3-F1-34-49-23-89-E3-EC-29-80-02-92-52-40-49-5D-CD-C1
Plaintext Bytes: 67-65-74-6D-65-62-61-63-6B
Plaintext UTF-8: getmeback
So, here you have the decrypt function (encrypting it would the same, just change .CreateDecryptor() to .CreateEncryptor()). If you forget about the code doing the key derivation, the decryption code does its work in only ~20 lines of code. So in review, my answer is a starting point for others who want to make this solution 100% C#. Hope this helps.
I have an Android app that is the "server" in a client/server design. In the app, I need to compute an MD5 hash against a set of strings and return the result to the client in order to let the conversation between them to continue. My code to do this has been pieced together from numerous examples out there. The algorithm of computing the hash (not designed by me) goes like this:
Convert the string into an array of bytes
Use the MessageDigest class to generate a hash
Convert resulting hash back to a string
The hash seems to be correct for 99% of my customers. One of the customers seeing the wrong hash is running with a German locale, and it started to make me wonder if language could be factoring into the result I get. This is the code to make the byte array out of the string:
public static byte[] hexStringToByteArray(String s)
{
byte[] data = null;
if(s.length() % 2 != 0)
{
s = "0" + s;
}
int len = s.length();
data = new byte[len / 2];
for (int i = 0; i < len; i += 2)
{
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
And here's the current version of the hashing function:
public static String hashDataAsString(String dataToHash)
{
MessageDigest messageDigest;
try
{
messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
byte[] data = hexStringToByteArray(dataToHash);
messageDigest.update(data);
final byte[] resultByte = messageDigest.digest();
return new String(Hex.encodeHex(resultByte));
}
catch(NoSuchAlgorithmException e)
{
throw new RuntimeException("Failed to hash data values", e);
}
}
I'm using the Hex.encodeHex function from Apache Commons.
I've tried switching my phone to a German locale, but my unit tests still produce the correct hash result. This customer is using stock Froyo, so that eliminates the risk that a custom ROM is at fault here. I've also found this alternative for converting from bytes to a string:
public static String MD5_Hash(String s) {
MessageDigest m = null;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//m.update(s.getBytes(),0,s.length());
byte [] data = hexStringToByteArray(s);
m.update(data, 0, data.length);
String hash = new BigInteger(1, m.digest()).toString(16);
return hash;
}
In my unit tests, it results in the same answer. Could BigInteger be a safer alternative to use here?
In your hashDataAsString method, do you need to do hexStringToByteArray? Is the incoming data a hex string or just an arbitrary string? Could you not use String.getBytes()?
If you are doing string/byte conversions, do you know the encoding of the incoming data and the encoding assumptions of your data consumers? Do you need to use a consistent encoding at both ends (e.g. ASCII or UTF-8)?
Do you include non-ASCII data in your unit tests?
I find myself in a need to change website platforms from Java to PHP but I'd like to keep all my user's passwords...
I had this code do the password hashing prior to writting the hashed value as the password to the website:
MessageDigest md = null;
md = MessageDigest.getInstance("SHA");
md.update(plaintext.getBytes("UTF-8"));
byte raw[] = md.digest();
hash = new Base64().encodeToString(raw).replaceAll("\n", "").replaceAll("\r", "");
I think the Java code did SHA-1 hashing of the password but just prior to that it was byte encoded to UTF-8 and afterwards it was Base64 encoded.
I'd like to have a PHP code do the same, i.e. return the same value of a hash for the same password as in Java, only it seems that the PHP code doing SHA-1 hashing I have won't return the same SHA(-1, not Base64 encoded, I think?) value when compared to a Java Base64 decoded value of the hash...could it have something to do with the fact that my passwords in PHP are not UTF-8 byte encoded first (and how can I do that in PHP) please?
p.s.
Another strange thing...my passwords in Java are all 28characters long (usually something like this rnwn4zTNgH30l4pP8V05lRVGmF4=)...but the Base64().decode(hash) value of those password hashes is 10 characters long (an example [B#14e1f2b).
I thought Base64 did an additional 1 character to each 3 charters (28 or 27, excluding the padding = charter, is much more that a third larger than those 10 charcters) so am I doing the decoding call wrong somehow maybe???
And on top of all that the SHA-1 password hashed values in PHP are 40 characters long (in a UTF-8 mysql database) like so dd94709528bb1c83d08f3088d4043f4742891f4f?
[B#14e1f2b is definitely not a hash. It's a result of implicit conversion from byte[] to String.
It looks like you do something like this:
String decodedHash = Base64().decode(hash); // Produces [B#14e1f2b
However, the correct representation of the hash is a byte array:
byte[] decodedHash = Base64().decode(hash);
What I normally do with Java to compute a SHA-1 hash that is exactly identical to the PHP sha1() function is the following. The key is that toHexString is used to show the raw bytes in a printable way. If you use the PHP function and want to obtain the same result of your convoluted process, you need to use the parameter $raw_output to true in PHP to get the raw bytes and apply Base64. Full source code.
/**
* Compute a SHA-1 hash of a String argument
*
* #param arg the UTF-8 String to encode
* #return the sha1 hash as a string.
*/
public static String computeSha1OfString(String arg) {
try {
return computeSha1OfByteArray(arg.getBytes(("UTF-8")));
} catch (UnsupportedEncodingException ex) {
throw new UnsupportedOperationException(ex);
}
}
private static String computeSha1OfByteArray(byte[] arg) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(arg);
byte[] res = md.digest();
return toHexString(res);
} catch (NoSuchAlgorithmException ex) {
throw new UnsupportedOperationException(ex);
}
}
private static String toHexString(byte[] v) {
StringBuilder sb = new StringBuilder(v.length * 2);
for (int i = 0; i < v.length; i++) {
int b = v[i] & 0xFF;
sb.append(HEX_DIGITS.charAt(b >>> 4)).append(HEX_DIGITS.charAt(b & 0xF));
}
return sb.toString();
}
PHP's sha1() encodes each byte of the output as hexadecimal by default, but you can get the raw output by passing true as the second argument:
$digest = sha1($password, true); // This returns the same string of bytes as md.digest()
Then pass the digest to base64_encode and you are done:
base64_encode(sha1($password, true));
This returns the exact same SHA-1 hash as your java code.
Is there any method to generate MD5 hash of a string in Java?
The MessageDigest class can provide you with an instance of the MD5 digest.
When working with strings and the crypto classes be sure to always specify the encoding you want the byte representation in. If you just use string.getBytes() it will use the platform default. (Not all platforms use the same defaults)
import java.security.*;
..
byte[] bytesOfMessage = yourString.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] theMD5digest = md.digest(bytesOfMessage);
If you have a lot of data take a look at the .update(xxx) methods which can be called repeatedly. Then call .digest() to obtain the resulting hash.
You need java.security.MessageDigest.
Call MessageDigest.getInstance("MD5") to get a MD5 instance of MessageDigest you can use.
The compute the hash by doing one of:
Feed the entire input as a byte[] and calculate the hash in one operation with md.digest(bytes).
Feed the MessageDigest one byte[] chunk at a time by calling md.update(bytes). When you're done adding input bytes, calculate the hash with
md.digest().
The byte[] returned by md.digest() is the MD5 hash.
If you actually want the answer back as a string as opposed to a byte array, you could always do something like this:
String plaintext = "your text here";
MessageDigest m = MessageDigest.getInstance("MD5");
m.reset();
m.update(plaintext.getBytes());
byte[] digest = m.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;
}
You might also want to look at the DigestUtils class of the apache commons codec project, which provides very convenient methods to create MD5 or SHA digests.
Found this:
public String MD5(String md5) {
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(md5.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; ++i) {
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {
}
return null;
}
on the site below, I take no credit for it, but its a solution that works!
For me lots of other code didnt work properly, I ended up missing 0s in the hash.
This one seems to be the same as PHP has.
source: http://m2tec.be/blog/2010/02/03/java-md5-hex-0093
Here is how I use it:
final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(string.getBytes(Charset.forName("UTF8")));
final byte[] resultByte = messageDigest.digest();
final String result = new String(Hex.encodeHex(resultByte));
where Hex is: org.apache.commons.codec.binary.Hex from the Apache Commons project.
I've found this to be the most clear and concise way to do it:
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(StandardCharsets.UTF_8.encode(string));
return String.format("%032x", new BigInteger(1, md5.digest()));
I just downloaded commons-codec.jar and got perfect php like md5. Here is manual.
Just import it to your project and use
String Url = "your_url";
System.out.println( DigestUtils.md5Hex( Url ) );
and there you have it.
No need to make it too complicated.
DigestUtils works fine and makes you comfortable while working with md5 hashes.
DigestUtils.md5Hex(_hash);
or
DigestUtils.md5(_hash);
Either you can use any other encryption methods such as sha or md.
Found this solution which is much cleaner in terms of getting a String representation back from an MD5 hash.
import java.security.*;
import java.math.*;
public class MD5 {
public static void main(String args[]) throws Exception{
String s="This is a test";
MessageDigest m=MessageDigest.getInstance("MD5");
m.update(s.getBytes(),0,s.length());
System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16));
}
}
The code was extracted from here.
Another implementation:
import javax.xml.bind.DatatypeConverter;
String hash = DatatypeConverter.printHexBinary(
MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));
Another option is to use the Guava Hashing methods:
Hasher hasher = Hashing.md5().newHasher();
hasher.putString("my string");
byte[] md5 = hasher.hash().asBytes();
Handy if you are already using Guava (which if you're not, you probably should be).
I have a Class (Hash) to convert plain text in hash in formats: md5 or sha1, simillar that php functions (md5, sha1):
public class Hash {
/**
*
* #param txt, text in plain format
* #param hashType MD5 OR SHA1
* #return hash in hashType
*/
public static String getHash(String txt, String hashType) {
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance(hashType);
byte[] array = md.digest(txt.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; ++i) {
sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
}
return sb.toString();
} catch (java.security.NoSuchAlgorithmException e) {
//error action
}
return null;
}
public static String md5(String txt) {
return Hash.getHash(txt, "MD5");
}
public static String sha1(String txt) {
return Hash.getHash(txt, "SHA1");
}
}
Testing with JUnit and PHP
PHP Script:
<?php
echo 'MD5 :' . md5('Hello World') . "\n";
echo 'SHA1:' . sha1('Hello World') . "\n";
Output PHP script:
MD5 :b10a8db164e0754105b7a99be72e3fe5
SHA1:0a4d55a8d778e5022fab701977c5d840bbc486d0
Using example and Testing with JUnit:
public class HashTest {
#Test
public void test() {
String txt = "Hello World";
assertEquals("b10a8db164e0754105b7a99be72e3fe5", Hash.md5(txt));
assertEquals("0a4d55a8d778e5022fab701977c5d840bbc486d0", Hash.sha1(txt));
}
}
Code in GitHub
https://github.com/fitorec/java-hashes
My not very revealing answer:
private String md5(String s) {
try {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
BigInteger i = new BigInteger(1,m.digest());
return String.format("%1$032x", i);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
There is a DigestUtils class in Spring also:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/util/DigestUtils.html
This class contains the method md5DigestAsHex() that does the job.
You can try following. See details and download codes here: http://jkssweetlife.com/java-hashgenerator-md5-sha-1/
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Example {
public static void main(String[] args) throws Exception {
final String inputString = "Hello MD5";
System.out.println("MD5 hex for '" + inputString + "' :");
System.out.println(getMD5Hex(inputString));
}
public static String getMD5Hex(final String inputString) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(inputString.getBytes());
byte[] digest = md.digest();
return convertByteToHex(digest);
}
private static String convertByteToHex(byte[] byteData) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
}
Bombe's answer is correct, however note that unless you absolutely must use MD5 (e.g. forced on you for interoperability), a better choice is SHA1 as MD5 has weaknesses for long term use.
I should add that SHA1 also has theoretical vulnerabilities, but not as severe. The current state of the art in hashing is that there are a number of candidate replacement hash functions but none have yet emerged as the standard best practice to replace SHA1. So, depending on your needs you would be well advised to make your hash algorithm configurable so it can be replaced in future.
Another implementation: Fast MD5 Implementation in Java
String hash = MD5.asHex(MD5.getHash(new File(filename)));
I do not know if this is relevant for anyone reading this, but I just had the problem that I wanted to
download a file from a given URL and
compare its MD5 to a known value.
I wanted to do it with JRE classes only (no Apache Commons or similar). A quick web search did not show me sample code snippets doing both at the same time, only each task separately. Because this requires to read the same file twice, I figured it might be worth the while to write some code which unifies both tasks, calculating the checksum on the fly while downloading the file. This is my result (sorry if it is not perfect Java, but I guess you get the idea anyway):
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.DigestOutputStream; // new
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
void downloadFile(String fromURL, String toFile, BigInteger md5)
throws IOException, NoSuchAlgorithmException
{
ReadableByteChannel in = Channels.newChannel(new URL(fromURL).openStream());
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
WritableByteChannel out = Channels.newChannel(
//new FileOutputStream(toFile)); // old
new DigestOutputStream(new FileOutputStream(toFile), md5Digest)); // new
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); // 1 MB
while (in.read(buffer) != -1) {
buffer.flip();
//md5Digest.update(buffer.asReadOnlyBuffer()); // old
out.write(buffer);
buffer.clear();
}
BigInteger md5Actual = new BigInteger(1, md5Digest.digest());
if (! md5Actual.equals(md5))
throw new RuntimeException(
"MD5 mismatch for file " + toFile +
": expected " + md5.toString(16) +
", got " + md5Actual.toString(16)
);
}
import java.security.*;
import javax.xml.bind.*;
byte[] bytesOfMessage = yourString.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytesOfDigest = md.digest(bytesOfMessage);
String digest = DatatypeConverter.printHexBinary(bytesOfDigest).toLowerCase();
Unlike PHP where you can do an MD5 hashing of your text by just calling md5 function ie md5($text), in Java it was made little bit complicated. I usually implemented it by calling a function which returns the md5 hash text.
Here is how I implemented it, First create a function named md5hashing inside your main class as given below.
public static String md5hashing(String text)
{ String hashtext = null;
try
{
String plaintext = text;
MessageDigest m = MessageDigest.getInstance("MD5");
m.reset();
m.update(plaintext.getBytes());
byte[] digest = m.digest();
BigInteger bigInt = new BigInteger(1,digest);
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;
}
} catch (Exception e1)
{
// TODO: handle exception
JOptionPane.showMessageDialog(null,e1.getClass().getName() + ": " + e1.getMessage());
}
return hashtext;
}
Now call the function whenever you needed as given below.
String text = textFieldName.getText();
String pass = md5hashing(text);
Here you can see that hashtext is appended with a zero to make it match with md5 hashing in PHP.
For what it's worth, I stumbled upon this because I want to synthesize GUIDs from a natural key for a program that will install COM components; I want to syhthesize so as not to manage GUID lifecycle. I'll use MD5 and then use the UUID class to get a string out of it. (http://stackoverflow.com/questions/2190890/how-can-i-generate-guid-for-a-string-values/12867439 raises this issue).
In any case, java.util.UUID can get you a nice String from the MD5 bytes.
return UUID.nameUUIDFromBytes(md5Bytes).toString();
MD5 is perfectly fine if you don't need the best security, and if you're doing something like checking file integrity then security is not a consideration. In such as case you might want to consider something simpler and faster, such as Adler32, which is also supported by the Java libraries.
this one gives the exact md5 as you get from mysql's md5 function or php's md5 functions etc. This is the one I use (you can change according to your needs)
public static String md5( String input ) {
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(input.getBytes( "UTF-8" ));
StringBuffer sb = new StringBuffer();
for (int i = 0; i < array.length; i++) {
sb.append( String.format( "%02x", array[i]));
}
return sb.toString();
} catch ( NoSuchAlgorithmException | UnsupportedEncodingException e) {
return null;
}
}
import java.security.MessageDigest
val digest = MessageDigest.getInstance("MD5")
//Quick MD5 of text
val text = "MD5 this text!"
val md5hash1 = digest.digest(text.getBytes).map("%02x".format(_)).mkString
//MD5 of text with updates
digest.update("MD5 ".getBytes())
digest.update("this ".getBytes())
digest.update("text!".getBytes())
val md5hash2 = digest.digest().map(0xFF & _).map("%02x".format(_)).mkString
//Output
println(md5hash1 + " should be the same as " + md5hash2)
You can generate MD5 hash for a given text by making use of the methods in the MessageDigest class in the java.security package. Below is the complete code snippet,
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.DatatypeConverter;
public class MD5HashGenerator
{
public static void main(String args[]) throws NoSuchAlgorithmException
{
String stringToHash = "MyJavaCode";
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(stringToHash.getBytes());
byte[] digiest = messageDigest.digest();
String hashedOutput = DatatypeConverter.printHexBinary(digiest);
System.out.println(hashedOutput);
}
}
The output from the MD5 function is a 128 bit hash represented by 32 hexadecimal numbers.
In case, if you are using a database like MySQL, you can do this in a more simpler way as well. The query Select MD5(“text here”) will return the MD5 hash of the text in the bracket.
try this:
public static String getHashMD5(String string) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
BigInteger bi = new BigInteger(1, md.digest(string.getBytes()));
return bi.toString(16);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(MD5Utils.class
.getName()).log(Level.SEVERE, null, ex);
return "";
}
}
This is what I came here for- a handy scala function that returns string of MD5 hash:
def md5(text: String) : String = java.security.MessageDigest.getInstance("MD5").digest(text.getBytes()).map(0xFF & _).map { "%02x".format(_) }.foldLeft(""){_ + _}
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* MD5 encryption
*
* #author Hongten
*
*/
public class MD5 {
public static void main(String[] args) {
System.out.println(MD5.getMD5("123456"));
}
/**
* Use md5 encoded code value
*
* #param sInput
* clearly
* # return md5 encrypted password
*/
public static String getMD5(String sInput) {
String algorithm = "";
if (sInput == null) {
return "null";
}
try {
algorithm = System.getProperty("MD5.algorithm", "MD5");
} catch (SecurityException se) {
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte buffer[] = sInput.getBytes();
for (int count = 0; count < sInput.length(); count++) {
md.update(buffer, 0, count);
}
byte bDigest[] = md.digest();
BigInteger bi = new BigInteger(bDigest);
return (bi.toString(16));
}
}
There is an article on Codingkit about that. Check out: http://codingkit.com/a/JAVA/2013/1020/2216.html
You could try using Caesar.
First option:
byte[] hash =
new Hash(
new ImmutableMessageDigest(
MessageDigest.getInstance("MD5")
),
new PlainText("String to hash...")
).asArray();
Second option:
byte[] hash =
new ImmutableMessageDigest(
MessageDigest.getInstance("MD5")
).update(
new PlainText("String to hash...")
).digest();