Alan Kaminsky Department of Computer Science Rochester Institute of Technology 4486 + 2220 = 6706
Home Page

//******************************************************************************
//
// File:    SHA256Hash.java
// Package: edu.rit.crypto.hash
// Unit:    Class edu.rit.crypto.hash.SHA256Hash
//
// This Java source file is copyright (C) 2008 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Computer Science Course Library ("The
// Library"). The Library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// The Library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************

package edu.rit.crypto.hash;

import edu.rit.crypto.CryptoUtils;

// For unit test main program
// import edu.rit.util.Hex;

/**
 * Class SHA256Hash provides a one-way hash function using the Secure Hash
 * Algorithm with a 256-bit hash value (SHA-256). The SHA-256 specification may
 * be found at
 * <A HREF="http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf">http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf</A>.
 * <P>
 * To compute a hash value, create an instance of class SHA256Hash; call the
 * various <TT>write...()</TT> methods to write a sequence of data items; and
 * call the <TT>hash()</TT> method to get the hash value. After calling
 * <TT>hash()</TT>, the SHA-256 hash function resets itself. You can also call
 * <TT>reset()</TT> to reset the SHA-256 hash function explicitly. If you write
 * further bytes after resetting the SHA-256 hash function, these bytes go into
 * the computation of a new hash value.
 * <P>
 * Since it is an iterated hash function, class SHA256Hash is susceptible to a
 * length extension attack. Consider using class {@link DoubleSHA256Hash
 * </CODE>DoubleSHA256Hash<CODE>} instead.
 * <P>
 * Class SHA256Hash is limited to hashing a maximum of 2<SUP>61</SUP> bytes
 * (2<SUP>64</SUP> bits).
 * <P>
 * <B><I>Note:</I></B> Class SHA256Hash is not multiple thread safe.
 *
 * @author  Alan Kaminsky
 * @version 30-Apr-2008
 */
public class SHA256Hash
    extends OneWayHash
    {

// Hidden constants.

    private static final int BLOCK_LENGTH_WORDS = 16;
    private static final int HASH_LENGTH_WORDS = 8;
    private static final int H_LENGTH_WORDS = 8;
    private static final int W_LENGTH_WORDS = 64;

// Hidden data members.

    // Hash value.
    private int[] H = new int [H_LENGTH_WORDS];

    // Message schedule.
    private int[] W = new int [W_LENGTH_WORDS];

// Exported constructors.

    /**
     * Construct a new SHA-256 hash function.
     */
    public SHA256Hash()
        {
        super (BLOCK_LENGTH_WORDS*4, HASH_LENGTH_WORDS*4);
        resetHashComputation();
        }

// Hidden operations.

    /**
     * Reset the hash computation.
     */
    protected void resetHashComputation()
        {
        H[0] = 0x6a09e667;
        H[1] = 0xbb67ae85;
        H[2] = 0x3c6ef372;
        H[3] = 0xa54ff53a;
        H[4] = 0x510e527f;
        H[5] = 0x9b05688c;
        H[6] = 0x1f83d9ab;
        H[7] = 0x5be0cd19;
        }

    /**
     * Accumulate the given hash block into this one-way hash function's hash
     * computation. Every byte in <TT>theBlock</TT> is valid.
     *
     * @param  theBlock  Hash block.
     */
    protected void accumulateHashBlock
        (byte[] theBlock)
        {
        int i;

        // Prepare the message schedule W.
        for (i = 0; i < BLOCK_LENGTH_WORDS; ++ i)
            {
            W[i] =
                ((theBlock[4*i  ] & 0xFF) << 24) |
                ((theBlock[4*i+1] & 0xFF) << 16) |
                ((theBlock[4*i+2] & 0xFF) <<  8) |
                ((theBlock[4*i+3] & 0xFF)      );
            }
        for (i = BLOCK_LENGTH_WORDS; i < W_LENGTH_WORDS; ++ i)
            {
            W[i] =
                lowerSigmaOne (W[i-2]) +
                W[i-7] +
                lowerSigmaZero (W[i-15]) +
                W[i-16];
            }

        // Initialize working variables.
        int a = H[0];
        int b = H[1];
        int c = H[2];
        int d = H[3];
        int e = H[4];
        int f = H[5];
        int g = H[6];
        int h = H[7];

        // Churn working variables using message schedule.
        for (i = 0; i < W_LENGTH_WORDS; ++ i)
            {
            int T1 = h + upperSigmaOne (e) + Ch (e, f, g) + K[i] + W[i];
            int T2 = upperSigmaZero (a) + Maj (a, b, c);
            h = g;
            g = f;
            f = e;
            e = d + T1;
            d = c;
            c = b;
            b = a;
            a = T1 + T2;
            }

        // Update hash value.
        H[0] += a;
        H[1] += b;
        H[2] += c;
        H[3] += d;
        H[4] += e;
        H[5] += f;
        H[6] += g;
        H[7] += h;
        }

    /**
     * Accumulate the given partial hash block into this one-way hash function's
     * hash computation and compute the final hash value. Only those bytes in
     * <TT>theBlock</TT> from index 0 through index <TT>theByteCount-1</TT> are
     * valid.
     *
     * @param  theBlock           Hash block.
     * @param  theByteCount       Number of valid bytes in the hash block.
     * @param  theDataLengthBits  Total number of data bits accumulated.
     * @param  buf                Byte array in which to store hash value.
     * @param  off                Index at which to start storing hash value.
     */
    protected void computeHashValue
        (byte[] theBlock,
         int theByteCount,
         long theDataLengthBits,
         byte[] buf,
         int off)
        {
        // If the message block is full, accumulate it and clear it out.
        if (theByteCount == 64)
            {
            accumulateHashBlock (theBlock);
            theByteCount = 0;
            }

        // Store first padding byte.
        theBlock[theByteCount++] = (byte) 0x80;

        // If there are fewer than 8 unused bytes in the hash block, we must put
        // the message length into the next hash block.
        if (theByteCount > 56)
            {
            while (theByteCount < 64)
                {
                theBlock[theByteCount++] = (byte) 0;
                }
            accumulateHashBlock (theBlock);
            theByteCount = 0;
            }

        // Store remaining padding bytes, leaving 8 free bytes for the message
        // length.
        while (theByteCount < 56)
            {
            theBlock[theByteCount++] = (byte) 0;
            }

        // Store message length and accumulate hash block.
        theBlock[56] = (byte) ((theDataLengthBits >> 56) & 0xFFL);
        theBlock[57] = (byte) ((theDataLengthBits >> 48) & 0xFFL);
        theBlock[58] = (byte) ((theDataLengthBits >> 40) & 0xFFL);
        theBlock[59] = (byte) ((theDataLengthBits >> 32) & 0xFFL);
        theBlock[60] = (byte) ((theDataLengthBits >> 24) & 0xFFL);
        theBlock[61] = (byte) ((theDataLengthBits >> 16) & 0xFFL);
        theBlock[62] = (byte) ((theDataLengthBits >>  8) & 0xFFL);
        theBlock[63] = (byte) ((theDataLengthBits      ) & 0xFFL);
        accumulateHashBlock (theBlock);

        // Return final hash value.
        int j = off;
        for (int i = 0; i < HASH_LENGTH_WORDS; ++ i)
            {
            buf[j++] = (byte) ((H[i] >> 24) & 0xFF);
            buf[j++] = (byte) ((H[i] >> 16) & 0xFF);
            buf[j++] = (byte) ((H[i] >>  8) & 0xFF);
            buf[j++] = (byte) ((H[i]      ) & 0xFF);
            }
        }

    /**
     * Erase this one-way hash function's internal state.
     */
    protected void eraseInternalState()
        {
        CryptoUtils.erase (H);
        H = null;
        CryptoUtils.erase (W);
        W = null;
        }

// Hidden functions and constants from the SHA-256 spec.

    private static int Ch
        (int x,
         int y,
         int z)
        {
        return (x & y) ^ (~x & z);
        }

    private static int Maj
        (int x,
         int y,
         int z)
        {
        return (x & y) ^ (x & z) ^ (y & z);
        }

    private static int upperSigmaZero
        (int x)
        {
        return ROTR (2, x) ^ ROTR (13, x) ^ ROTR (22, x);
        }

    private static int upperSigmaOne
        (int x)
        {
        return ROTR (6, x) ^ ROTR (11, x) ^ ROTR (25, x);
        }

    private static int lowerSigmaZero
        (int x)
        {
        return ROTR (7, x) ^ ROTR (18, x) ^ SHR (3, x);
        }

    private static int lowerSigmaOne
        (int x)
        {
        return ROTR (17, x) ^ ROTR (19, x) ^ SHR (10, x);
        }

    private static int ROTR
        (int n,
         int x)
        {
        return (x >>> n) | (x << (32 - n));
        }

    private static int SHR
        (int n,
         int x)
        {
        return x >>> n;
        }

    private static int[] K = new int[]
        {/* 0*/ 0x428a2f98,
         /* 1*/ 0x71374491,
         /* 2*/ 0xb5c0fbcf,
         /* 3*/ 0xe9b5dba5,
         /* 4*/ 0x3956c25b,
         /* 5*/ 0x59f111f1,
         /* 6*/ 0x923f82a4,
         /* 7*/ 0xab1c5ed5,
         /* 8*/ 0xd807aa98,
         /* 9*/ 0x12835b01,
         /*10*/ 0x243185be,
         /*11*/ 0x550c7dc3,
         /*12*/ 0x72be5d74,
         /*13*/ 0x80deb1fe,
         /*14*/ 0x9bdc06a7,
         /*15*/ 0xc19bf174,
         /*16*/ 0xe49b69c1,
         /*17*/ 0xefbe4786,
         /*18*/ 0x0fc19dc6,
         /*19*/ 0x240ca1cc,
         /*20*/ 0x2de92c6f,
         /*21*/ 0x4a7484aa,
         /*22*/ 0x5cb0a9dc,
         /*23*/ 0x76f988da,
         /*24*/ 0x983e5152,
         /*25*/ 0xa831c66d,
         /*26*/ 0xb00327c8,
         /*27*/ 0xbf597fc7,
         /*28*/ 0xc6e00bf3,
         /*29*/ 0xd5a79147,
         /*30*/ 0x06ca6351,
         /*31*/ 0x14292967,
         /*32*/ 0x27b70a85,
         /*33*/ 0x2e1b2138,
         /*34*/ 0x4d2c6dfc,
         /*35*/ 0x53380d13,
         /*36*/ 0x650a7354,
         /*37*/ 0x766a0abb,
         /*38*/ 0x81c2c92e,
         /*39*/ 0x92722c85,
         /*40*/ 0xa2bfe8a1,
         /*41*/ 0xa81a664b,
         /*42*/ 0xc24b8b70,
         /*43*/ 0xc76c51a3,
         /*44*/ 0xd192e819,
         /*45*/ 0xd6990624,
         /*46*/ 0xf40e3585,
         /*47*/ 0x106aa070,
         /*48*/ 0x19a4c116,
         /*49*/ 0x1e376c08,
         /*50*/ 0x2748774c,
         /*51*/ 0x34b0bcb5,
         /*52*/ 0x391c0cb3,
         /*53*/ 0x4ed8aa4a,
         /*54*/ 0x5b9cca4f,
         /*55*/ 0x682e6ff3,
         /*56*/ 0x748f82ee,
         /*57*/ 0x78a5636f,
         /*58*/ 0x84c87814,
         /*59*/ 0x8cc70208,
         /*60*/ 0x90befffa,
         /*61*/ 0xa4506ceb,
         /*62*/ 0xbef9a3f7,
         /*63*/ 0xc67178f2};

// Unit test main program.

//    /**
//     * Unit test main program.
//     */
//    public static void main
//        (String[] args)
//        throws Exception
//        {
//        int i, n;
//
//        OneWayHash md = new SHA256Hash();
//
//        if (args.length == 0)
//            {
//            System.out.println ("Hashing one million 'a's");
//            for (i = 0; i < 1000000; ++ i)
//                {
//                md.writeByte ((byte) 'a');
//                }
//            }
//        else
//            {
//            System.out.println ("Hashing \"" + args[0] + "\"");
//            md.writeByteArray (args[0].getBytes());
//            }
//
//        byte[] h = new byte [md.getHashLength()];
//        md.hash (h);
//        System.out.println (Hex.toString (h));
//        }

    }

Alan Kaminsky Department of Computer Science Rochester Institute of Technology 4486 + 2220 = 6706
Home Page
Copyright © 2011 Alan Kaminsky. All rights reserved. Last updated 01-Mar-2013. Please send comments to ark­@­cs.rit.edu.