// $Id: SHA2Core.java 54 2007-01-24 16:22:09Z tp $ package fr.cryptohash; /** * This class implements SHA-224 and SHA-256, which differ only by the IV * and the output length. * * <pre> * ==========================(LICENSE BEGIN)============================ * * Copyright (c) 2007 Projet RNRT SAPHIR * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * ===========================(LICENSE END)============================= * </pre> * * @version $Revision: 54 $ * @author Thomas Pornin <thomas.pornin@cryptolog.com> */ abstract class SHA2Core extends MDHelper { /** * Create the object. */ SHA2Core() { super(false, 8); } /** private special values. */ private static final int[] K = { 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 }; private int[] currentVal, W; /** @see DigestEngine */ protected Digest copyState(SHA2Core dst) { System.arraycopy(currentVal, 0, dst.currentVal, 0, currentVal.length); return super.copyState(dst); } /** @see Digest */ public int getBlockLength() { return 64; } /** @see DigestEngine */ protected void engineReset() { System.arraycopy(getInitVal(), 0, currentVal, 0, 8); } /** * Get the initial value for this algorithm. * * @return the initial value (eight 32-bit words) */ abstract int[] getInitVal(); /** @see DigestEngine */ protected void doPadding(byte[] output, int outputOffset) { makeMDPadding(); int olen = getDigestLength(); for (int i = 0, j = 0; j < olen; i ++, j += 4) encodeBEInt(currentVal[i], output, outputOffset + j); } /** @see DigestEngine */ protected void doInit() { currentVal = new int[8]; W = new int[64]; engineReset(); } /** * Encode the 32-bit word <code>val</code> into the array * <code>buf</code> at offset <code>off</code>, in big-endian * convention (most significant byte first). * * @param val the value to encode * @param buf the destination buffer * @param off the destination offset */ private static final void encodeBEInt(int val, byte[] buf, int off) { buf[off + 0] = (byte)(val >>> 24); buf[off + 1] = (byte)(val >>> 16); buf[off + 2] = (byte)(val >>> 8); buf[off + 3] = (byte)val; } /** * Decode a 32-bit big-endian word from the array <code>buf</code> * at offset <code>off</code>. * * @param buf the source buffer * @param off the source offset * @return the decoded value */ private static final int decodeBEInt(byte[] buf, int off) { return ((buf[off] & 0xFF) << 24) | ((buf[off + 1] & 0xFF) << 16) | ((buf[off + 2] & 0xFF) << 8) | (buf[off + 3] & 0xFF); } /** * Perform a circular rotation by <code>n</code> to the left * of the 32-bit word <code>x</code>. The <code>n</code> parameter * must lie between 1 and 31 (inclusive). * * @param x the value to rotate * @param n the rotation count (between 1 and 31) * @return the rotated value */ static private int circularLeft(int x, int n) { return (x << n) | (x >>> (32 - n)); } /** @see DigestEngine */ protected void processBlock(byte[] data) { int A = currentVal[0]; int B = currentVal[1]; int C = currentVal[2]; int D = currentVal[3]; int E = currentVal[4]; int F = currentVal[5]; int G = currentVal[6]; int H = currentVal[7]; for (int i = 0; i < 16; i ++) W[i] = decodeBEInt(data, 4 * i); for (int i = 16; i < 64; i ++) { W[i] = (circularLeft(W[i - 2], 15) ^ circularLeft(W[i - 2], 13) ^ (W[i - 2] >>> 10)) + W[i - 7] + (circularLeft(W[i - 15], 25) ^ circularLeft(W[i - 15], 14) ^ (W[i - 15] >>> 3)) + W[i - 16]; } for (int i = 0; i < 64; i ++) { int T1 = H + (circularLeft(E, 26) ^ circularLeft(E, 21) ^ circularLeft(E, 7)) + ((F & E) ^ (G & ~E)) + K[i] + W[i]; int T2 = (circularLeft(A, 30) ^ circularLeft(A, 19) ^ circularLeft(A, 10)) + ((A & B) ^ (A & C) ^ (B & C)); H = G; G = F; F = E; E = D + T1; D = C; C = B; B = A; A = T1 + T2; } currentVal[0] += A; currentVal[1] += B; currentVal[2] += C; currentVal[3] += D; currentVal[4] += E; currentVal[5] += F; currentVal[6] += G; currentVal[7] += H; } }