--- old/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java 2015-02-19 15:51:39.259044944 -0800 +++ new/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java 2015-02-19 15:51:39.147045659 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -42,7 +42,7 @@ * @since 1.8 */ final class GHASH { - + private static long getLong(byte[] buffer, int offset) { long result = 0; int end = offset + 8; @@ -51,7 +51,7 @@ } return result; } - + private static void putLong(byte[] buffer, int offset, long value) { int end = offset + 8; for (int i = end - 1; i >= offset; --i) { @@ -59,46 +59,48 @@ value >>= 8; } } - + private static final int AES_BLOCK_SIZE = 16; - - // Multiplies state0, state1 by V0, V1. - private void blockMult(long V0, long V1) { + + // Multiplies state[0], state[1] by subkeyH[0], subkeyH[1]. + private void blockMult(long[] subH) { long Z0 = 0; long Z1 = 0; - long X; - - // Separate loops for processing state0 and state1. - X = state0; + long V0 = subH[0]; + long V1 = subH[1]; + long X; + + // Separate loops for processing state[0] and state[1]. + X = state[0]; for (int i = 0; i < 64; i++) { // Zi+1 = Zi if bit i of x is 0 long mask = X >> 63; Z0 ^= V0 & mask; Z1 ^= V1 & mask; - + // Save mask for conditional reduction below. mask = (V1 << 63) >> 63; - + // V = rightshift(V) long carry = V0 & 1; V0 = V0 >>> 1; V1 = (V1 >>> 1) | (carry << 63); - // Conditional reduction modulo P128. + // Conditional reduction modulo P128. V0 ^= 0xe100000000000000L & mask; X <<= 1; } - - X = state1; + + X = state[1]; for (int i = 64; i < 127; i++) { // Zi+1 = Zi if bit i of x is 0 long mask = X >> 63; Z0 ^= V0 & mask; Z1 ^= V1 & mask; - + // Save mask for conditional reduction below. mask = (V1 << 63) >> 63; - + // V = rightshift(V) long carry = V0 & 1; V0 = V0 >>> 1; @@ -108,22 +110,25 @@ V0 ^= 0xe100000000000000L & mask; X <<= 1; } - + // calculate Z128 long mask = X >> 63; Z0 ^= V0 & mask; Z1 ^= V1 & mask; - + // Save result. - state0 = Z0; - state1 = Z1; + state[0] = Z0; + state[1] = Z1; + } + /* subkeyH and state are stored in long[] for GHASH intrinsic use */ + // hash subkey H; should not change after the object has been constructed - private final long subkeyH0, subkeyH1; + private final long[] subkeyH; // buffer for storing hash - private long state0, state1; + private final long[] state; // variables for save/restore calls private long stateSave0, stateSave1; @@ -141,8 +146,10 @@ if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) { throw new ProviderException("Internal error"); } - this.subkeyH0 = getLong(subkeyH, 0); - this.subkeyH1 = getLong(subkeyH, 8); + state = new long[2]; + this.subkeyH = new long[2]; + this.subkeyH[0] = getLong(subkeyH, 0); + this.subkeyH[1] = getLong(subkeyH, 8); } /** @@ -151,33 +158,30 @@ * this object for different data w/ the same H. */ void reset() { - state0 = 0; - state1 = 0; + state[0] = 0; + state[1] = 0; } /** * Save the current snapshot of this GHASH object. */ void save() { - stateSave0 = state0; - stateSave1 = state1; + stateSave0 = state[0]; + stateSave1 = state[1]; } /** * Restores this object using the saved snapshot. */ void restore() { - state0 = stateSave0; - state1 = stateSave1; + state[0] = stateSave0; + state[1] = stateSave1; } private void processBlock(byte[] data, int ofs) { - if (data.length - ofs < AES_BLOCK_SIZE) { - throw new RuntimeException("need complete block"); - } - state0 ^= getLong(data, ofs); - state1 ^= getLong(data, ofs + 8); - blockMult(subkeyH0, subkeyH1); + state[0] ^= getLong(data, ofs); + state[1] ^= getLong(data, ofs + 8); + blockMult(subkeyH); } void update(byte[] in) { @@ -185,22 +189,47 @@ } void update(byte[] in, int inOfs, int inLen) { - if (inLen - inOfs > in.length) { + if (inLen == 0) { + return; + } + if (inLen < 0 || inOfs < 0 || inLen > in.length - inOfs) { throw new RuntimeException("input length out of bound"); } if (inLen % AES_BLOCK_SIZE != 0) { throw new RuntimeException("input length unsupported"); } - for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) { - processBlock(in, i); + // These two checks are for C2 checking + if (state.length != 2) { + throw new RuntimeException("internal state has invalid length " + + state.length); + } + if (subkeyH.length != 2) { + throw new RuntimeException("internal subkeyH has invalid length" + + subkeyH.length); + } + + processBlocks(in, inOfs, inLen/AES_BLOCK_SIZE); + } + + /* + * This is an intrinsified method. The method's argument list must match + * the hotspot signature. This method and methods called by it, cannot + * throw exceptions or allocate arrays as it will breaking intrinsics + */ + private void processBlocks(byte[] data, int inOfs, int blocks) { + int offset = inOfs; + while (blocks > 0) { + processBlock(data, offset); + blocks--; + offset += AES_BLOCK_SIZE; } } byte[] digest() { byte[] result = new byte[AES_BLOCK_SIZE]; - putLong(result, 0, state0); - putLong(result, 8, state1); + putLong(result, 0, state[0]); + putLong(result, 8, state[1]); reset(); return result; }