1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2015 Red Hat, Inc. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 /* 27 * (C) Copyright IBM Corp. 2013 28 */ 29 30 package com.sun.crypto.provider; 31 32 import java.security.ProviderException; 33 34 /** 35 * This class represents the GHASH function defined in NIST 800-38D 36 * under section 6.4. It needs to be constructed w/ a hash subkey, i.e. 37 * block H. Given input of 128-bit blocks, it will process and output 38 * a 128-bit block. 39 * 40 * <p>This function is used in the implementation of GCM mode. 41 * 42 * @since 1.8 43 */ 44 final class GHASH { 45 46 private static long getLong(byte[] buffer, int offset) { 47 long result = 0; 48 int end = offset + 8; 49 for (int i = offset; i < end; ++i) { 50 result = (result << 8) + (buffer[i] & 0xFF); 51 } 52 return result; 53 } 54 55 private static void putLong(byte[] buffer, int offset, long value) { 56 int end = offset + 8; 57 for (int i = end - 1; i >= offset; --i) { 58 buffer[i] = (byte) value; 59 value >>= 8; 60 } 61 } 62 63 private static final int AES_BLOCK_SIZE = 16; 64 65 // Multiplies state0, state1 by V0, V1. 66 private void blockMult(long V0, long V1) { 67 long Z0 = 0; 68 long Z1 = 0; 69 long X; 70 71 // Separate loops for processing state0 and state1. 72 X = state0; 73 for (int i = 0; i < 64; i++) { 74 // Zi+1 = Zi if bit i of x is 0 75 long mask = X >> 63; 76 Z0 ^= V0 & mask; 77 Z1 ^= V1 & mask; 78 79 // Save mask for conditional reduction below. 80 mask = (V1 << 63) >> 63; 81 82 // V = rightshift(V) 83 long carry = V0 & 1; 84 V0 = V0 >>> 1; 85 V1 = (V1 >>> 1) | (carry << 63); 86 87 // Conditional reduction modulo P128. 88 V0 ^= 0xe100000000000000L & mask; 89 X <<= 1; 90 } 91 92 X = state1; 93 for (int i = 64; i < 127; i++) { 94 // Zi+1 = Zi if bit i of x is 0 95 long mask = X >> 63; 96 Z0 ^= V0 & mask; 97 Z1 ^= V1 & mask; 98 99 // Save mask for conditional reduction below. 100 mask = (V1 << 63) >> 63; 101 102 // V = rightshift(V) 103 long carry = V0 & 1; 104 V0 = V0 >>> 1; 105 V1 = (V1 >>> 1) | (carry << 63); 106 107 // Conditional reduction. 108 V0 ^= 0xe100000000000000L & mask; 109 X <<= 1; 110 } 111 112 // calculate Z128 113 long mask = X >> 63; 114 Z0 ^= V0 & mask; 115 Z1 ^= V1 & mask; 116 117 // Save result. 118 state0 = Z0; 119 state1 = Z1; 120 } 121 122 // hash subkey H; should not change after the object has been constructed 123 private final long subkeyH0, subkeyH1; 124 125 // buffer for storing hash 126 private long state0, state1; 127 128 // variables for save/restore calls 129 private long stateSave0, stateSave1; 130 131 /** 132 * Initializes the cipher in the specified mode with the given key 133 * and iv. 134 * 135 * @param subkeyH the hash subkey 136 * 137 * @exception ProviderException if the given key is inappropriate for 138 * initializing this digest 139 */ 140 GHASH(byte[] subkeyH) throws ProviderException { 141 if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) { 142 throw new ProviderException("Internal error"); 143 } 144 this.subkeyH0 = getLong(subkeyH, 0); 145 this.subkeyH1 = getLong(subkeyH, 8); 146 } 147 148 /** 149 * Resets the GHASH object to its original state, i.e. blank w/ 150 * the same subkey H. Used after digest() is called and to re-use 151 * this object for different data w/ the same H. 152 */ 153 void reset() { 154 state0 = 0; 155 state1 = 0; 156 } 157 158 /** 159 * Save the current snapshot of this GHASH object. 160 */ 161 void save() { 162 stateSave0 = state0; 163 stateSave1 = state1; 164 } 165 166 /** 167 * Restores this object using the saved snapshot. 168 */ 169 void restore() { 170 state0 = stateSave0; 171 state1 = stateSave1; 172 } 173 174 private void processBlock(byte[] data, int ofs) { 175 if (data.length - ofs < AES_BLOCK_SIZE) { 176 throw new RuntimeException("need complete block"); 177 } 178 state0 ^= getLong(data, ofs); 179 state1 ^= getLong(data, ofs + 8); 180 blockMult(subkeyH0, subkeyH1); 181 } 182 183 void update(byte[] in) { 184 update(in, 0, in.length); 185 } 186 187 void update(byte[] in, int inOfs, int inLen) { 188 if (inLen - inOfs > in.length) { 189 throw new RuntimeException("input length out of bound"); 190 } 191 if (inLen % AES_BLOCK_SIZE != 0) { 192 throw new RuntimeException("input length unsupported"); 193 } 194 195 for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) { 196 processBlock(in, i); 197 } 198 } 199 200 byte[] digest() { 201 byte[] result = new byte[AES_BLOCK_SIZE]; 202 putLong(result, 0, state0); 203 putLong(result, 8, state1); 204 reset(); 205 return result; 206 } 207 }