55

I'm looking for a way of getting an SHA-1 checksum with a Java byte array as the message.

Should I use a third party tool or is there something built in to the JVM that can help?

Andy Hayden
  • 359,921
  • 101
  • 625
  • 535
Mike
  • 58,961
  • 76
  • 175
  • 221
  • 12
    I was looking for the same stuff. A way to compute SHA1 in Java. What I get? Two answers. With a lot of "this is wrong", "this is horrible". Yet, the people who wrote these comments, didn't write a "good" answer. – Apache Mar 05 '12 at 22:45

8 Answers8

59

What about:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;

public static String SHAsum(byte[] convertme) throws NoSuchAlgorithmException{
    MessageDigest md = MessageDigest.getInstance("SHA-1"); 
    return byteArray2Hex(md.digest(convertme));
}

private static String byteArray2Hex(final byte[] hash) {
    Formatter formatter = new Formatter();
    for (byte b : hash) {
        formatter.format("%02x", b);
    }
    return formatter.toString();
}
LabOctoCat
  • 611
  • 7
  • 17
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 1
    I was only looking for way of computing the sha1 - the format doesn't matter – Mike Oct 04 '09 at 15:06
  • 7
    @PascalThivent But another programmer might stop by and use this answer, including the error (that's after all partly what SO is about). There's enough vagueness about hashing as it is (docs like "calculate this signature by sha-1 hashing these string concatenated", without mentioning how to encode the input characters and stringify the hash output, are common enough). – Bart van Heukelom Nov 02 '11 at 11:27
  • 2
    This didn't even compile correctly. I don't get how a user with 152k rep writes such an answer two years ago, and nobody edits it until now. – ripper234 Nov 29 '11 at 08:55
  • 7
    @jarnbjo Thanks for pointing out the potential issues. But why don't I see a post from you 'with' the correct answer then? It may not get accepted as the correct answer, but it may get voted up significantly more than the current 9 votes. – Jeach Jan 20 '12 at 16:12
  • 4
    I believe the comment mentioning the answer is wrong is not relevant anymore. The answer was edited and the conversion to Hex String looks fine. – Damien May 16 '12 at 15:59
10

You can do it yourself but I would recommend to use a library that has been proven to work, like Commons Codec. The class DigestUtils has several methods to calculate hashes.

Jasha
  • 781
  • 9
  • 15
9

This a snippet of code we use to convert to SHA-1 but takes a String instead of a Byte[] see this javadoc for further info

        import java.io.UnsupportedEncodingException;
        import java.security.MessageDigest;
        import java.security.NoSuchAlgorithmException;

        public class DoSHA1 {

            private static String convToHex(byte[] data) {
                StringBuilder buf = new StringBuilder();
                for (int i = 0; i < data.length; i++) {
                    int halfbyte = (data[i] >>> 4) & 0x0F;
                    int two_halfs = 0;
                    do {
                        if ((0 <= halfbyte) && (halfbyte <= 9))
                            buf.append((char) ('0' + halfbyte));
                        else
                            buf.append((char) ('a' + (halfbyte - 10)));
                        halfbyte = data[i] & 0x0F;
                    } while(two_halfs++ < 1);
                }
                return buf.toString();
            }

            public static String SHA1(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException  {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] sha1hash = new byte[40];
            md.update(text.getBytes("iso-8859-1"), 0, text.length());
            sha1hash = md.digest();
            return convToHex(sha1hash);
            }
        }
non sequitor
  • 18,296
  • 9
  • 45
  • 64
  • 2
    If it's fast enough for you, you can also just use String.format("%02x", b) to convert the bytes into a hex string. – John Cromartie Oct 01 '11 at 17:44
  • The line where you allocate a new 40-byte array is useless; the array object comes from the md.digest() call. When you assign the return of that method to sha1hash, you erase the empty 40-byte array you've created. – MikeB Dec 15 '16 at 15:30
  • Further, a SHA-1 digest is 20 bytes, not 40 bytes. – MikeB Dec 15 '16 at 15:44
2

From CommonCodec DigestUtils Implementation the Hex coversion after the Digest calculation as shown before :

MessageDigest md = MessageDigest.getInstance("SHA-1"); 
return byteArray2Hex(md.digest(convertme));

should be http://commons.apache.org/codec/apidocs/src-html/org/apache/commons/codec/binary/Hex.html#line.129 :

private static final char[] DIGITS_LOWER = 
   {'0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

private static final char[] DIGITS_UPPER = 
   {'0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

protected static char[] encodeHex(byte[] data, char[] toDigits) {
    int l = data.length;
    char[] out = new char[l << 1];
    // two characters form the hex value.
    for (int i = 0, j = 0; i < l; i++) {
        out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
        out[j++] = toDigits[0x0F & data[i]];
    }
    return out;
}

protected static int toDigit(char ch, int index) throws DecoderException {
    int digit = Character.digit(ch, 16);
    if (digit == -1) {
        throw new DecoderException(
                    "Illegal hexadecimal character " 
            + ch + " at index " + index);
    }
    return digit;
}

public static String exampleSha1(String convertme){
    MessageDigest md = MessageDigest.getInstance("SHA-1"); 
    byte[] encodeHex = md.digest(convertme));
    return new String(encodeHex);
}
loreii
  • 380
  • 4
  • 13
1

...another option is to use Spring:

<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
     <constructor-arg value="256"/>
 </bean>

read more here

HTH

OhadR
  • 8,276
  • 3
  • 47
  • 53
0

I Just used this to compute the hash sum inside of a dex file and compare it with the value which is saved in the dex file.

i know this code hasnt very good style but its more PoC and only needed for some research which isnt time critical. may someone can use it!

class CheckDex{
public boolean checkSHA1(File f) throws IOException, NoSuchAlgorithmException{
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    byte[] sig = new byte[20];
    raf.seek(0xC);
    for(int i = 0; i < 20; i++){
        sig[i] = (byte) raf.readUnsignedByte();
    }

    MessageDigest md = MessageDigest.getInstance("SHA-1"); 

    byte[] code = new byte[(int) (raf.length()-32)];
    for(int i = 0; i < code.length; i++){
        code[i] = (byte) raf.readUnsignedByte();
    }
    byte[] comsig = md.digest(code);

    raf.close();
    return Arrays.equals(sig,comsig);
}
}
reox
  • 5,036
  • 11
  • 53
  • 98
0

How about Using This:

public class sha1Calculate {

    public static void main(String[] args)throws Exception
    {
         File file = new File("D:\\Android Links.txt");
        String outputTxt= "";
        String hashcode = null;

        try {

            FileInputStream input = new FileInputStream(file);

            ByteArrayOutputStream output = new ByteArrayOutputStream ();
            byte [] buffer = new byte [65536];
            int l;

            while ((l = input.read (buffer)) > 0)
                output.write (buffer, 0, l);

            input.close ();
            output.close ();

            byte [] data = output.toByteArray ();


                MessageDigest digest = MessageDigest.getInstance( "SHA-1" ); 

            byte[] bytes = data;

            digest.update(bytes, 0, bytes.length);
            bytes = digest.digest();

            StringBuilder sb = new StringBuilder();

            for( byte b : bytes )
            {
                sb.append( String.format("%02X", b) );
            }

                System.out.println("Digest(in hex format):: " + sb.toString());


        }catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    }

}
Nayan Rath
  • 293
  • 5
  • 18
0

The following code converts the given byte[] into a String of the SHA-1 hash.

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public static String hash(byte data[]) throws NoSuchAlgorithmException
{
   MessageDigest digest;
   BigInteger big;
   String result;
   byte hash[];

   digest = MessageDigest.getInstance("SHA-1"); 
   hash   = digest.digest(data);
   big    = new BigInteger(1, hash);
   result = big.toString(16);

   return result;
}

Note: The leading zeros will be trimmed. So, this may or may not work depending on your use case.

Nathan
  • 8,093
  • 8
  • 50
  • 76