상세 컨텐츠

본문 제목

MD5

IT 세상/자바세상

by 이현민 (지후지율아빠) 2010. 3. 22. 20:42

본문

import java.security.MessageDigest;

import java.security.GeneralSecurityException;

 

public class MD5class {

    public static String MD5(String inpara) {

        byte[] bpara = new byte[inpara.length()];

        byte[] rethash;

        int i;

 

        for (i=0; i < inpara.length(); i++)

            bpara[i] = (byte)(inpara.charAt(i) & 0xff );

 

        try {

            MessageDigest md5er = MessageDigest.getInstance("MD5");

            rethash = md5er.digest(bpara);

        } catch (GeneralSecurityException e) {

            throw new RuntimeException(e);

        }

 

        StringBuffer r = new StringBuffer(32);

        for (i=0; i < rethash.length; i++) {

            String x = Integer.toHexString(rethash[i] & 0xff).toUpperCase();

            if (x.length()<2)

                r.append("0");

            r.append(x);

        }

        return r.toString();

    }

}

자바 내장 함수인 MessageDigest를 사용하여 MD5 알고리즘을 적용하고 생성된 값을 16진수 문자열로 변환하여 32자리 스트링으로 돌려준다. 함수의 입출력은 모두 스트링이다.

PASSWORD() 함수

표준인 보안 해시 알고리즘 SHA1을 사용하여 MySQL PASSWORD 함수를 자바 저장 함수를 이용하여 작성한다.

import java.security.MessageDigest;

import java.security.GeneralSecurityException;

 

public class PASSWORDclass {

    public static String PASSWORD(String inpara) {

        byte[] bpara = new byte[inpara.length()];

        byte[] rethash;

        int i;

 

        for (i=0; i < inpara.length(); i++)

            bpara[i] = (byte)(inpara.charAt(i) & 0xff );

 

        try {

            MessageDigest sha1er = MessageDigest.getInstance("SHA1");

            rethash = sha1er.digest(bpara);     // stage1

            rethash = sha1er.digest(rethash);   // stage2

        } catch (GeneralSecurityException e) {

            throw new RuntimeException(e);

        }

 

        StringBuffer r = new StringBuffer(41);

        r.append("*");

        for (i=0; i < rethash.length; i++) {

            String x = Integer.toHexString(rethash[i] & 0xff).toUpperCase();

            if (x.length()<2)

                r.append("0");

            r.append(x);

        }

        return r.toString();

    }

}

자바 내장 함수인 MessageDigest를 사용하여 입력된 스트링에 SHA1 알고리즘을 적용하고 그 결과에 다시 한번 SHA1 알고리즘을 적용한다. 생성된 값을 16진수 문자열로 변환하여 맨처음에 ‘*’ 문자를 붙여 41자리 스트링으로 돌려준다. 함수의 입출력은 모두 스트링이다.

 OLD_PASSWORD() 함수

MySQLOLD_PASSWORD 함수를 자바 저장 함수를 이용하여 작성한다.

public class OLD_PASSWORDclass {

    public static String OLD_PASSWORD(String inpara) {

        byte[] bpara = new byte[inpara.length()];

        long lvar1 = 1345345333;

        long ladd = 7;

        long lvar2 = 0x12345671;

        int i;

       

        if (inpara.length() <= 0)

          return "";

 

        for (i=0; i < inpara.length(); i++)

          bpara[i] = (byte)(inpara.charAt(i) & 0xff );

 

        for (i=0; i < inpara.length(); i++) {

            if (bpara[i] == ' ' ||

                bpara[i] == 't') continue;

          lvar1 ^= (((lvar1 & 63) + ladd) * bpara[i]) + (lvar1 << 8);

          lvar2 += (lvar2 << 8) ^ lvar1;

          ladd += bpara[i];

        }

 

        lvar1 = lvar1 & 0x7fffffff;

        lvar2 = lvar2 & 0x7fffffff;

 

        StringBuffer r = new StringBuffer(16);

        String x = Long.toHexString(lvar1);

        for (i = 8; i > x.length(); i --)

          r.append("0");

        r.append(x);

       

        x = Long.toHexString(lvar2);

        for (i = 8; i > x.length(); i --)

          r.append("0");

        r.append(x);

        return r.toString();

    }

}







This is a quick tip for implementing md5 encryption in java. We use the MessageDigest class in the java.security package and some string manipulation to turn the plain text into a byte array. The digest is then updated from the bytes from the byte array and a hash computation is conducted upon them. To quote from the Sun java api docs, The MessageDigest class provides applications the functionality of a message digest algorithm, such as MD5 or SHA. Message digests are secure one-way hash functions that take arbitrary-sized data and output a fixed-length hash value.

Anyway the md5 example code below takes a session id (this is just a string which I wanted to encrypt - It could just as easily be a document, say a lump of xml or any old bit of text). This session id is pulled into the bytes array, defaultBytes and then the MessageDigest is instantiated as an instance of an md5 encryption.

Java developers who have come over from PERL or PHP often get frustrated with such a longwinded means of running what could simply be a single line of code, however the snippet below could be wrapped into an md5sum class which conducts the encryption and simply returns a string of cipher text.
include java.security.*;

... etc

sessionid="12345";
        
byte[] defaultBytes = sessionid.getBytes();
try{
	MessageDigest algorithm = MessageDigest.getInstance("MD5");
	algorithm.reset();
	algorithm.update(defaultBytes);
	byte messageDigest[] = algorithm.digest();
            
	StringBuffer hexString = new StringBuffer();
	for (int i=0;i<messageDigest.length;i++) {
		hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
	}
	String foo = messageDigest.toString();
	System.out.println("sessionid "+sessionid+" md5 version is "+hexString.toString());
	sessionid=hexString+"";
}catch(NoSuchAlgorithmException nsae){
            
}

Remember to import the java.security package. The original plain text and cipher text strings are echod to the java console just to demonstrate what has happened.


Hope that's useful,

christo

follow me on twitter:
http://www.twitter.com/planet_guru
Digg it! Submit to Slashdot Add to Blinklist Del.icio.us Add to Newsvine Add to Technorati Add it to Google Bookmarks Add to Magnolia
comment
2004-09-23 09:11:47

not exactly correct

if you use Integer.toHexString(int a), if a>=0 and a<=15 you will get a String consisting of only one char!!!! you need to do something like this:

StringBuffer sb=new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
     String hex=Integer.toHexString(0xff & bytes[i]);
     if(hex.length()==1) sb.append('0');
     sb.append(hex);
}
reply icon
2006-12-18 16:59:38

Java md5 example with MessageDigest - - immer 32 z

Vielen Dank für dieses Beispiel,
ich bin mal so frei und hab den Code aufbereitet, das er passt.
D.h. es kommt als Ergebnis immer ein gültiger 32 Zeichelänge MD5-String raus.

import java.security.*;

... etc

String pass = "123456";


byte[] defaultBytes = pass.getBytes();
try{
     MessageDigest algorithm = MessageDigest.getInstance("MD5");
     algorithm.reset();
     algorithm.update(defaultBytes);
     byte messageDigest[] = algorithm.digest();

     StringBuffer hexString = new StringBuffer();
     for (int i=0;i<messageDigest.length;i++) {
	String hex = Integer.toHexString(0xFF & messageDigest[i]); 
	if(hex.length()==1)
	hexString.append('0');

	hexString.append(hex);
     }
						     
						     
     //*** Testausgabe
     System.out.println("pass "+pass+"   md5 version is "+hexString.toString());
     pass = hexString+"";
}
catch(NoSuchAlgorithmException nsae){
						                    
}

Danke an Euch Zwei. ICh wäre da selbst nicht drauf gekommen.
reply icon
2006-11-28 16:43:09

Thanks!

These codes were very useful to me !
Thank you!
reply icon
2007-03-30 09:36:31

The following code works well if you only need to print the digest value:

for (byte b : md.digest())
System.out.printf("%02x", 0xFF&b);
reply icon
2007-03-30 15:38:19

SHA-256

Cheers.

package test;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Test
{
    public static void main(String[] args)
    {
        String md5val = "";
        MessageDigest algorithm = null;

        try
        {
            algorithm = MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException nsae)
        {
            System.out.println("Cannot find digest algorithm");
            System.exit(1);
        }
        
        for (String arg : args)
        {
            byte[] defaultBytes = arg.getBytes();
            algorithm.reset();
            algorithm.update(defaultBytes);
            byte messageDigest[] = algorithm.digest();
            StringBuffer hexString = new StringBuffer();

            for (int i = 0; i < messageDigest.length; i++)
            {
                String hex = Integer.toHexString(0xFF & messageDigest[i]);
                if (hex.length() == 1)
                {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            md5val = hexString.toString();
            System.out.println("MD5 ("" + arg + "") = " + md5val);
        }
    }
}

this lets you test on the command line against the command line md5 command to check it works correctly:

g@h ~/bin$ md5 -s dammitjanet
MD5 ("dammitjanet") = ea309a2eb146a4d8bdf8946c4df23c71
g@h ~/bin$ java -cp . test.MD5Test dammitjanet
MD5 ("dammitjanet") = ea309a2eb146a4d8bdf8946c4df23c71

Please note that if you are using MD5 for authentication means, you really really should consider using a salt alongside the value you wish to create an md5 of to increase security. Better to use SHA-256 although you need to use more characters in your database password table.

algorithm = MessageDigest.getInstance("SHA-256");

g@h ~/bin$ java -cp . test.MD5Test "bark at the moon"  
SHA-256 ("bark at the moon") = a5bb786220762b74c9569cd9f150a4176f9da3c2ac29d776a65487b2a77d4429
reply icon
2007-05-17 17:27:19

shorter version

You can use BigInteger to do the byte array conversion....
    static String getMd5Digest(String input)
        {
            try
            {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] messageDigest = md.digest(input.getBytes());
                BigInteger number = new BigInteger(1,messageDigest);
                return number.toString(16);
            }
            catch(NoSuchAlgorithmException e)
            {
                throw new RuntimeException(e);
            }
        }
reply icon
2007-05-21 19:35:08

Short correction

I liked the short version, so I used it but it didn't match during my testing.

I tried with the following input:
"bbb": 8F8E0260C64418510CEFB2B06EEE5CD

So I checked against MySQL md5():
08F8E0260C64418510CEFB2B06EEE5CD

You have to prepend zero's until you get 32 chars to simulate this behaviour.

Regards,
Pedro

reply icon
2008-05-26 06:07:07

You can use BigInteger to do the byte array conversion....
    static String getMd5Digest(String input)
        {
            try
            {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] messageDigest = md.digest(input.getBytes());
                BigInteger number = new BigInteger(1,messageDigest);
                return number.toString(16);
            }
            catch(NoSuchAlgorithmException e)
            {
                throw new RuntimeException(e);
            }
        }

ty so much, never thought of using BigInteger, best solution ever :) (after the PHP solution in 1 line :P)
reply iconedit reply
2008-11-24 11:17:28

Thank you very much, it is really useful.
reply iconedit reply
2008-11-27 09:49:17

error desicion

BAD TEST:

public class CheckSumUtils {

public static String calcPlayerPasswordChecksum(String pass) {
byte[] passBytes = pass.getBytes();
try {
MessageDigest algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(passBytes);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(passBytes);
BigInteger number = new BigInteger(1, messageDigest);
return number.toString(16).toUpperCase();
} catch (NoSuchAlgorithmException e) {
throw new Error("invalid JRE: have not 'MD5' impl.", e);
}
}

public static void main(String[] args) {
System.out.println(calcPlayerPasswordChecksum("a"));
System.out.println(calcPlayerPasswordChecksum("aa"));
System.out.println(calcPlayerPasswordChecksum("aaa"));
}
}

running this test return answ:
CC175B9C0F1B6A831C399E269772661
4124BC0A9335C27F086F24BA207A4912
47BCE5C74F589F4867DBD57E9CA9F808

so, arg 'a' translate to 31 (not 32) lenth result :(
reply iconedit reply
2009-02-15 14:26:57

I have to side with Ivan - the Big Integer approach does not seem to work properly. I did this:-


public static void main(String[] args) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");


for (int i = 0; i < 1E+4; i++) {
byte[] messageDigest = md.digest(new Date().toString().getBytes());
BigInteger number = new BigInteger(1, messageDigest);
System.out.println(number.toString(16));
}
}



and while looking at the output, came across these MD5s:-



8150f16d3efeddda79787fb9e8a235
8150f16d3efeddda79787fb9e8a235
8150f16d3efeddda79787fb9e8a235
8150f16d3efeddda79787fb9e8a235
4e9b15f5c1df1905f63faec3bb6a49d2
4e9b15f5c1df1905f63faec3bb6a49d2
4e9b15f5c1df1905f63faec3bb6a49d2
4e9b15f5c1df1905f63faec3bb6a49d2



I'm not an expert and don't really understand how it works, but I thought that all MD5s were the same length...
reply iconedit reply
2009-02-16 01:37:54

leading zeroes don't matter!

You could argue that leading zeroes are insignificant. Depending on how you use the hash bytes, they may or may not matter. Here is an easy way to check a user supplied password against a saved hash value;


MessageDigest m = MessageDigest.getInstance("SHA"); // or MD5
BigInteger supplied = new BigInteger(1, m.digest(password.getBytes()));
BigInteger checkval = new BigInteger(stored, 16);
if (supplied.equals(checkval)) {
// do something
};

Where 'password' is the user supplied String, and 'stored' is the String of the stored hash. You could easily combine it into a one line statement, but this is very clear and easy to read (besides which, you need to wrap in a try/catch anyway).

By viewing the stored hash and the supplied hash as BigIntegers, you can check for equality easily, and not have to worry about leading zeroes in the stored hash value.

My 2 cents.
reply iconedit reply
2009-05-25 19:29:02

I had also attempted to use the code in this thread, though several of you are correct that the MD5 that is generated is not a consistent 32 char hex. In several tests that I had run it wasn't just the leading 0s being chopped off either it was characters in the middle of the hash. I would get variable length hashes 30, 31, 32 chars depending on the input data.

My suggestion if you're just looking for a solution to generate consistent MD5 or other hashes and not worrying about trying to write your own implementation is to use the Apache Commons Codec package to do this for you. Add this library to your project.

Apache Commons Codec Home
http://commons.apache.org/codec/

The specific class you will want to use is DigestUtils. Here is a link to the javadoc
DigestUtils JavaDoc

This is what your code will now look like to achieve the same as above.

String sessionid = "12345";
String md5 = DigestUtils.md5Hex(sessionid);

Result: 827CCB0EEA8A706C4C34A16891F84E7B

Hope this helps.

Cheers,

B
reply icon
2010-02-19 13:49:17

public String getMD5Hash(String value)
throws NoSuchAlgorithmException, UnsupportedEncodingException {

final StringBuilder sbMd5Hash = new StringBuilder();
final MessageDigest m = MessageDigest.getInstance("MD5");
m.update(value.getBytes("UTF-8"));

final byte data[] = m.digest();

for (byte element : data) {
sbMd5Hash.append(Character.forDigit((element >> 4) & 0xf, 16));
sbMd5Hash.append(Character.forDigit(element & 0xf, 16));
}

return sbMd5Hash.toString();
}

BigInteger is not correct for example "Cash"
with BigInteger = 69b30db06d047a398f9eb0940d3279c
Right is = 069b30db06d047a398f9eb0940d3279c
reply iconedit reply
반응형

'IT 세상 > 자바세상' 카테고리의 다른 글

jsp filedown 소스  (0) 2010.05.27
tag 내용(,구분자) 20개 제한 및 /score 뺴기  (0) 2010.04.01
mysql의 최대 성능 향상 방법  (0) 2010.03.19
dom4j 사용하기  (0) 2010.03.19
Java Collection Sort (List, Array)  (0) 2010.03.04

관련글 더보기