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