How can I generate an MD5 hash in Java? - java

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

Related

Encrypt string using given modulus and exponent

I need to replicate the functionality of the following JAVA code that receives a string with the exponent and modulus of a public key to generate a public key with said parameters and encrypt a string:
package snippet;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
public class Snippet {
public static void main(String ... strings) {
try {
// Needed if you don't have this provider
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//String and received public key example
String ReceivedString = "1234";
String publicRSA = "010001|0097152d7034a8b48383d3dba20c43d049";
EncryptFunc(ReceivedString, publicRSA);
//The result obtained from the ReceivedString and the publicRSA is as follows:
//Result in hex [1234] -> [777786fe162598689a8dc172ed9418cb]
} catch (Exception ex) {
System.out.println("Error: " );
ex.printStackTrace();
}
}
public static String EncryptFunc(String ReceivedString, String clavePublica) throws Exception {
String result = "";
//We separate the received public string into exponent and modulus
//We receive it as "exponent|modulus"
String[] SplitKey = clavePublica.split("\\|");
KeyFactory keyFactory = KeyFactory.getInstance("RSA","BC");
RSAPublicKeySpec ks = new RSAPublicKeySpec(new BigInteger(hex2byte(SplitKey[1])), new BigInteger(hex2byte(SplitKey[0])));
//With these specs, we generate the public key
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(ks);
//We instantiate the cypher, with the EncryptFunc and the obtained public key
Cipher cipher= Cipher.getInstance("RSA/None/NoPadding","BC");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
//We reverse the ReceivedString and encrypt it
String ReceivedStringReverse = reverse(ReceivedString);
byte[] cipherText2 = cipher.doFinal(ReceivedStringReverse.getBytes("UTF8"));
result = byte2hex(cipherText2);
System.out.println("result in hex ["+ReceivedString+"] -> ["+result+"]");
return result;
}
public static byte[] hex2byte(String s) {
int len = s.length();
byte[] 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;
}
public static String byte2hex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte aByte : bytes) {
result.append(String.format("%02x", aByte));
// upper case
// result.append(String.format("%02X", aByte));
}
return result.toString();
}
public static String reverse(String source) {
int i, len = source.length();
StringBuilder dest = new StringBuilder(len);
for (i = (len - 1); i >= 0; i--){
dest.append(source.charAt(i));
}
return dest.toString();
}
}
I've tried several approaches with this one, And I have done some searching here, here, here, here and here.
I Managed to create the public key with the given parameters, but the results are always different when I encrypt the string:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace RSACypherTest
{
public class Program
{
public static RSACryptoServiceProvider rsa;
static void Main(string[] args)
{
string str = "1234";
string publicRSA = "010001|0097152d7034a8b48383d3dba20c43d049";
string encrypted = "";
Console.WriteLine("Original text: " + str);
encrypted = Encrypt(str, publicRSA);
Console.WriteLine("Encrypted text: " + encrypted);
Console.ReadLine();
}
public static string Encrypt(string str, string PublicRSA)
{
string[] Separated = PublicRSA.Split('|');
RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);
IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(true, pubParameters);
byte[] plaintext = Encoding.UTF8.GetBytes(Reverse(str));
byte[] encdata = eng.ProcessBlock(plaintext, 0, plaintext.Length);
return ByteArrayToString(encdata);
}
public static string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
public static string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba).Replace("-", "");
}
public static byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
{
var modulus = new BigInteger(modulusHexString, 16);
var exponent = new BigInteger(exponentHexString, 16);
return new RsaKeyParameters(isPrivateKey, modulus, exponent);
}
}
}
I'm trying to use BouncyCastle because it seems to be the most effcient way of dealing with the key generation and everything. Any help concerning this would be very much appreciated.
Thanks in advance.
This is not the answer to your question but may help you in understanding RSA encryption.
I setup a sample encryption program in C# and used your given public key (converted the BigInteger modulus & exponent to Base64 values and further just wrote the XML-String representation of the public to use this key for encryption. The keylength is good for a length of maximum 5 byte data.
When running the encryption 5 times you will receive different encodedData (here in Base64 encoding) each run. So it's the expected behavior of the RSA encryption.
As C# allows me to "build" a short key it is not possible to generate a fresh keypair of such length and I doubt that Bouncy Castle would do (but here on SO there are many colleagues with a much better understanding of BC :-).
If you would like the program you can use the following external link to the program: https://jdoodle.com/ia/40.
Result:
load a pre created public key
publicKeyXML2: lxUtcDSotIOD09uiDEPQSQ==AQAB
encryptedData in Base64: JIFfO7HXCvdi0nSxKb0eLA==
encryptedData in Base64: dvtRw0U0KtT/pDJZW2X0FA==
encryptedData in Base64: CqJJKZevO6jWH6DQ1dnkhQ==
encryptedData in Base64: G7cL6BBwxysItvD/Rg0PuA==
encryptedData in Base64: HcfZJITu/PzN84WgI8yc6g==
code:
using System;
using System.Security.Cryptography;
using System.Text;
class RSACSPSample
{
static void Main()
{
try
{
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = System.Text.Encoding.UTF8.GetBytes("1234");
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
Console.WriteLine("load a pre created public key");
string publicKeyXML = "<RSAKeyValue><Modulus>AJcVLXA0qLSDg9PbogxD0Ek=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
RSA.FromXmlString(publicKeyXML);
string publicKeyXML2 = RSA.ToXmlString(false);
Console.WriteLine("publicKeyXML2: " + publicKeyXML2);
Console.WriteLine();
//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
for (int i = 0; i < 5; i++)
{
encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
string encryptedDataBase64 = Convert.ToBase64String(encryptedData);
Console.WriteLine("encryptedData in Base64: " + encryptedDataBase64);
}
}
}
catch (ArgumentNullException)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine("Encryption failed.");
}
}
public static byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
}
While I won't mark my own answer as the correct one, I've found that there's the possibility to recreate the entire functionality of the java code mentioned in my question.
As Michael Fehr mentions in his answer, Its absolutely logical that any encryption method will try to avoid creating repeating or predictable patterns, as this answer perfectly describes.
Since in this particular situation the aim is to replicate the java code functionality, and said functionality revolves around getting the same results when encrypting a string with a given public key, we can use the answer in this post to generate a pice of code like the following:
private static string EncryptMessage(string str, string publicRSA)
{
string[] Separated = publicRSA.Split('|');
RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);
var eng = new RsaEngine();
eng.Init(true, pubParameters);
string x = Reverse(str);
byte[] plaintext = Encoding.UTF8.GetBytes(x);
var encdata = ByteArrayToString(eng.ProcessBlock(plaintext, 0, plaintext.Length));
return encdata;
}
private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
{
byte[] mod = StringToByteArray(modulusHexString);
byte[] exp = StringToByteArray(exponentHexString);
var modulus = new BigInteger(mod);
var exponent = new BigInteger(exp);
return new RsaKeyParameters(isPrivateKey, modulus, exponent);
}
To recap:
As Michael Fehr says, it is not only normal but expected of a crypyography engine to NOT generate repeatable/predictable patterns
To deliver on the previous point, they add random "padding" to the messages
It's possible (but not recommended) to use BouncyCastle to generate a No-padding engine, emulating the functionality of Java code such as this Cipher rsa = Cipher.getInstance("RSA/ECB/nopadding");

SHA-1 hashing on Java and C#

I'm trying to validate the content of an XML node with SHA-1 , basically, we generate an SHA-1 hash with the content of that node and both sides (client C# and server Java) should have exactly the same hash.
The problem is , I have checked with a diff tool the content of both texts and there is not any difference. But I'm getting a different hash than the client.
C# hash : 60-53-58-69-29-EB-53-BD-85-31-79-28-A0-F9-42-B6-DE-1B-A6-0A
Java hash: E79D7E6F2A6F5D776447714D896D4C3A0CBC793
The way the client (C#) is generating the hash is this:
try
{
Byte[] stream = null;
using (System.Security.Cryptography.SHA1CryptoServiceProvider shaProvider = new System.Security.Cryptography.SHA1CryptoServiceProvider())
{
stream = shaProvider.ComputeHash(System.Text.Encoding.UTF8.GetBytes(text));
if (stream == null)
{
hash = "Error";
}
else
{
hash = System.BitConverter.ToString(stream);
}
}
}
catch (Exception error)
{
hash = string.Format("Error SHA-1: {0}", error);
}
return hash;
and this is how the server (Java) is generating the hash:
byte[] key = content.getBytes();
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] hash = md.digest(key);
String result = "";
for (byte b : hash) {
result += Integer.toHexString(b & 255);
}
return result.toUpperCase();
can someone help me ? .. thanks :)
UPDATE:
In order to check what's going on I have checked other ways to get a SHA1 hash in C# and I found this:
/// <summary>
/// Compute hash for string encoded as UTF8
/// </summary>
/// <param name="s">String to be hashed</param>
/// <returns>40-character hex string</returns>
public static string SHA1HashStringForUTF8String(string s)
{
byte[] bytes = Encoding.UTF8.GetBytes(s);
using (var sha1 = SHA1.Create())
{
byte[] hashBytes = sha1.ComputeHash(bytes);
return System.BitConverter.ToString(hashBytes).Replace("-",string.Empty);
}
}
This code gives this output:
E79D07E6F2A6F5D776447714D896D4C3A0CBC793
AND !! I just noticed that Python is giving the same output (sorry, I should double checked this)
So this is the deal
Using this provider: System.Security.Cryptography.SHA1CryptoServiceProvider shaProvider = new System.Security.Cryptography.SHA1CryptoServiceProvider()
Is giving a completly different output on three different machines ..
Using the above method in C# gives the same result as python does, also, for some reason Java is giving a sightly different output:
E79D7E6F2A6F5D776447714D896D4C3A0CBC793
Ideas?, is java the problem? the byte to hex method on java is the problem? there is another alternative?
Try using this as your hashing in C#:
static string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
// can be "x2" if you want lowercase
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
Hash("test"); //a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
And then use this as your Java hashing:
private static String convertToHex(byte[] data) {
StringBuilder buf = new StringBuilder();
for (byte b : data) {
int halfbyte = (b >>> 4) & 0x0F;
int two_halfs = 0;
do {
buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
halfbyte = b & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString();
}
public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] textBytes = text.getBytes("iso-8859-1");
md.update(textBytes, 0, textBytes.length);
byte[] sha1hash = md.digest();
return convertToHex(sha1hash);
}
SHA1("test"); //a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Note you need the following imports:
import java.io.UnsupportedEncodingException; import
java.security.MessageDigest; import
java.security.NoSuchAlgorithmException;
Throws declarations are option, adjust to best fit your code!
Your problem is that you're not hashing the same bytes in both API.
If you choose to modify java's version, it should look like this:
byte[] key = content.getBytes("UTF8");
[...]
If you choose to modify c#' version, it should look like this:
stream = shaProvider.ComputeHash(System.Text.Encoding.UTF16.GetBytes(text));
[...]
Either way, both api should get the key's bytes through the same encoding.

Decrypt in C# a password encrypted in Java

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.

Simple one line, native encrypt/decrypt method in Java

Is there a dead-simple native method in Java to encrypt/decrypt a string with a key? I don't really care what type of encryption (AES, DES, etc..), I just care that it's bound by with a key and not easily breakable.
Ideally, I would like it to be a one line solution like so:
String encryptedString = NativeEncryptionClass.encrypt("this is the data", "key123");
Thanks
Not sure you can do it in a [legiable] one-liner, but you can achieve simple symmetrical encryption relatively easily - take a look at the following example:
PrivateExample using DES
I've used the Bouncy Castle library to good effect in the past.
If by native you mean, not depending on platform specific libraries, maybe jasypt might be interesting for you.
May be you should try using simple XOR encryption
Ok, maybe it's not 'one line' but it seems easy enough:
make use of java's Cipher class. look here... (there are other examples on this page...)
http://download.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#BlowKeyEx
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SimpleMD5Example {
public static void main(String[] args) {
String passwordToHash = "0";
String generatedPassword = null;
try {
// Create MessageDigest instance for MD5
MessageDigest md = MessageDigest.getInstance("MD5");
// Add password bytes to digest
md.update(passwordToHash.getBytes());
// Get the hash's bytes
byte[] bytes = md.digest();
System.out.println(bytes);
// This bytes[] has bytes in decimal format;
// Convert it to hexadecimal format
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff), 16).substring(1));
}
// Get complete hashed password in hex format
generatedPassword = sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
System.out.println(generatedPassword);
}
}

Getting a File's MD5 Checksum in Java

I am looking to use Java to get the MD5 checksum of a file. I was really surprised but I haven't been able to find anything that shows how to get the MD5 checksum of a file.
How is it done?
There's an input stream decorator, java.security.DigestInputStream, so that you can compute the digest while using the input stream as you normally would, instead of having to make an extra pass over the data.
MessageDigest md = MessageDigest.getInstance("MD5");
try (InputStream is = Files.newInputStream(Paths.get("file.txt"));
DigestInputStream dis = new DigestInputStream(is, md))
{
/* Read decorated stream (dis) to EOF as normal... */
}
byte[] digest = md.digest();
Use DigestUtils from Apache Commons Codec library:
try (InputStream is = Files.newInputStream(Paths.get("file.zip"))) {
String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
}
There's an example at Real's Java-How-to using the MessageDigest class.
Check that page for examples using CRC32 and SHA-1 as well.
import java.io.*;
import java.security.MessageDigest;
public class MD5Checksum {
public static byte[] createChecksum(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5");
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
complete.update(buffer, 0, numRead);
}
} while (numRead != -1);
fis.close();
return complete.digest();
}
// see this How-to for a faster way to convert
// a byte array to a HEX string
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;
}
public static void main(String args[]) {
try {
System.out.println(getMD5Checksum("apache-tomcat-5.5.17.exe"));
// output :
// 0bb2827c5eacf570b6064e24e0e6653b
// ref :
// http://www.apache.org/dist/
// tomcat/tomcat-5/v5.5.17/bin
// /apache-tomcat-5.5.17.exe.MD5
// 0bb2827c5eacf570b6064e24e0e6653b *apache-tomcat-5.5.17.exe
}
catch (Exception e) {
e.printStackTrace();
}
}
}
The com.google.common.hash API offers:
A unified user-friendly API for all hash functions
Seedable 32- and 128-bit implementations of murmur3
md5(), sha1(), sha256(), sha512() adapters, change only one line of code to switch between these, and murmur.
goodFastHash(int bits), for when you don't care what algorithm you use
General utilities for HashCode instances, like combineOrdered / combineUnordered
Read the User Guide (IO Explained, Hashing Explained).
For your use-case Files.hash() computes and returns the digest value for a file.
For example a sha-1 digest calculation (change SHA-1 to MD5 to get MD5 digest)
HashCode hc = Files.asByteSource(file).hash(Hashing.sha1());
"SHA-1: " + hc.toString();
Note that crc32 is much faster than md5, so use crc32 if you do not need a cryptographically secure checksum. Note also that md5 should not be used to store passwords and the like since it is to easy to brute force, for passwords use bcrypt, scrypt or sha-256 instead.
For long term protection with hashes a Merkle signature scheme adds to the security and The Post Quantum Cryptography Study Group sponsored by the European Commission has recommended use of this cryptography for long term protection against quantum computers (ref).
Note that crc32 has a higher collision rate than the others.
Using nio2 (Java 7+) and no external libraries:
byte[] b = Files.readAllBytes(Paths.get("/path/to/file"));
byte[] hash = MessageDigest.getInstance("MD5").digest(b);
To compare the result with an expected checksum:
String expected = "2252290BC44BEAD16AA1BF89948472E8";
String actual = DatatypeConverter.printHexBinary(hash);
System.out.println(expected.equalsIgnoreCase(actual) ? "MATCH" : "NO MATCH");
Guava now provides a new, consistent hashing API that is much more user-friendly than the various hashing APIs provided in the JDK. See Hashing Explained. For a file, you can get the MD5 sum, CRC32 (with version 14.0+) or many other hashes easily:
HashCode md5 = Files.hash(file, Hashing.md5());
byte[] md5Bytes = md5.asBytes();
String md5Hex = md5.toString();
HashCode crc32 = Files.hash(file, Hashing.crc32());
int crc32Int = crc32.asInt();
// the Checksum API returns a long, but it's padded with 0s for 32-bit CRC
// this is the value you would get if using that API directly
long checksumResult = crc32.padToLong();
Ok. I had to add. One line implementation for those who already have Spring and Apache Commons dependency or are planning to add it:
DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))
For and Apache commons only option (credit #duleshi):
DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))
Hope this helps someone.
A simple approach with no third party libraries using Java 7
String path = "your complete file path";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
byte[] digest = md.digest();
If you need to print this byte array. Use as below
System.out.println(Arrays.toString(digest));
If you need hex string out of this digest. Use as below
String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
System.out.println(digestInHex);
where DatatypeConverter is javax.xml.bind.DatatypeConverter
I recently had to do this for just a dynamic string, MessageDigest can represent the hash in numerous ways. To get the signature of the file like you would get with the md5sum command I had to do something like the this:
try {
String s = "TEST STRING";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(s.getBytes(),0,s.length());
String signature = new BigInteger(1,md5.digest()).toString(16);
System.out.println("Signature: "+signature);
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
This obviously doesn't answer your question about how to do it specifically for a file, the above answer deals with that quiet nicely. I just spent a lot of time getting the sum to look like most application's display it, and thought you might run into the same trouble.
public static void main(String[] args) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
FileInputStream fis = new FileInputStream("c:\\apache\\cxf.jar");
byte[] dataBytes = new byte[1024];
int nread = 0;
while ((nread = fis.read(dataBytes)) != -1) {
md.update(dataBytes, 0, nread);
};
byte[] mdbytes = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < mdbytes.length; i++) {
sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Digest(in hex format):: " + sb.toString());
}
Or you may get more info
http://www.asjava.com/core-java/java-md5-example/
We were using code that resembles the code above in a previous post using
...
String signature = new BigInteger(1,md5.digest()).toString(16);
...
However, watch out for using BigInteger.toString() here, as it will truncate leading zeros...
(for an example, try s = "27", checksum should be "02e74f10e0327ad868d138f2b4fdd6f0")
I second the suggestion to use Apache Commons Codec, I replaced our own code with that.
public static String MD5Hash(String toHash) throws RuntimeException {
try{
return String.format("%032x", // produces lower case 32 char wide hexa left-padded with 0
new BigInteger(1, // handles large POSITIVE numbers
MessageDigest.getInstance("MD5").digest(toHash.getBytes())));
}
catch (NoSuchAlgorithmException e) {
// do whatever seems relevant
}
}
Very fast & clean Java-method that doesn't rely on external libraries:
(Simply replace MD5 with SHA-1, SHA-256, SHA-384 or SHA-512 if you want those)
public String calcMD5() throws Exception{
byte[] buffer = new byte[8192];
MessageDigest md = MessageDigest.getInstance("MD5");
DigestInputStream dis = new DigestInputStream(new FileInputStream(new File("Path to file")), md);
try {
while (dis.read(buffer) != -1);
}finally{
dis.close();
}
byte[] bytes = md.digest();
// bytesToHex-method
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);
}
Here is a handy variation that makes use of InputStream.transferTo() from Java 9, and OutputStream.nullOutputStream() from Java 11. It requires no external libraries and does not need to load the entire file into memory.
public static String hashFile(String algorithm, File f) throws IOException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm);
try(BufferedInputStream in = new BufferedInputStream((new FileInputStream(f)));
DigestOutputStream out = new DigestOutputStream(OutputStream.nullOutputStream(), md)) {
in.transferTo(out);
}
String fx = "%0" + (md.getDigestLength()*2) + "x";
return String.format(fx, new BigInteger(1, md.digest()));
}
and
hashFile("SHA-512", Path.of("src", "test", "resources", "some.txt").toFile());
returns
"e30fa2784ba15be37833d569280e2163c6f106506dfb9b07dde67a24bfb90da65c661110cf2c5c6f71185754ee5ae3fd83a5465c92f72abd888b03187229da29"
String checksum = DigestUtils.md5Hex(new FileInputStream(filePath));
Another implementation: Fast MD5 Implementation in Java
String hash = MD5.asHex(MD5.getHash(new File(filename)));
Standard Java Runtime Environment way:
public String checksum(File file) {
try {
InputStream fin = new FileInputStream(file);
java.security.MessageDigest md5er =
MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024];
int read;
do {
read = fin.read(buffer);
if (read > 0)
md5er.update(buffer, 0, read);
} while (read != -1);
fin.close();
byte[] digest = md5er.digest();
if (digest == null)
return null;
String strDigest = "0x";
for (int i = 0; i < digest.length; i++) {
strDigest += Integer.toString((digest[i] & 0xff)
+ 0x100, 16).substring(1).toUpperCase();
}
return strDigest;
} catch (Exception e) {
return null;
}
}
The result is equal of linux md5sum utility.
Here is a simple function that wraps around Sunil's code so that it takes a File as a parameter. The function does not need any external libraries, but it does require Java 7.
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.DatatypeConverter;
public class Checksum {
/**
* Generates an MD5 checksum as a String.
* #param file The file that is being checksummed.
* #return Hex string of the checksum value.
* #throws NoSuchAlgorithmException
* #throws IOException
*/
public static String generate(File file) throws NoSuchAlgorithmException,IOException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(Files.readAllBytes(file.toPath()));
byte[] hash = messageDigest.digest();
return DatatypeConverter.printHexBinary(hash).toUpperCase();
}
public static void main(String argv[]) throws NoSuchAlgorithmException, IOException {
File file = new File("/Users/foo.bar/Documents/file.jar");
String hex = Checksum.generate(file);
System.out.printf("hex=%s\n", hex);
}
}
Example output:
hex=B117DD0C3CBBD009AC4EF65B6D75C97B
If you're using ANT to build, this is dead-simple. Add the following to your build.xml:
<checksum file="${jarFile}" todir="${toDir}"/>
Where jarFile is the JAR you want to generate the MD5 against, and toDir is the directory you want to place the MD5 file.
More info here.
Google guava provides a new API. Find the one below :
public static HashCode hash(File file,
HashFunction hashFunction)
throws IOException
Computes the hash code of the file using hashFunction.
Parameters:
file - the file to read
hashFunction - the hash function to use to hash the data
Returns:
the HashCode of all of the bytes in the file
Throws:
IOException - if an I/O error occurs
Since:
12.0
public static String getMd5OfFile(String filePath)
{
String returnVal = "";
try
{
InputStream input = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
MessageDigest md5Hash = MessageDigest.getInstance("MD5");
int numRead = 0;
while (numRead != -1)
{
numRead = input.read(buffer);
if (numRead > 0)
{
md5Hash.update(buffer, 0, numRead);
}
}
input.close();
byte [] md5Bytes = md5Hash.digest();
for (int i=0; i < md5Bytes.length; i++)
{
returnVal += Integer.toString( ( md5Bytes[i] & 0xff ) + 0x100, 16).substring( 1 );
}
}
catch(Throwable t) {t.printStackTrace();}
return returnVal.toUpperCase();
}
Pulling together ideas from other answers, here's simple code with no third party dependencies (or DatatypeConverter which is longer in the latest JDKs) that generates this as a hex string compatible with output of the md5sum tool:
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
...
static String calculateMD5(String path) throws IOException
{
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
return String.format("%032x", new BigInteger(1, md.digest())); // hex, padded to 32 chars
} catch (NoSuchAlgorithmException ex)
{
throw new RuntimeException(ex); // MD5 is always available so this should be impossible
}
}

Categories

Resources