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.util.Arrays;
  32 import java.security.*;
  33 import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
  34 
  35 /**
  36  * This class represents the GHASH function defined in NIST 800-38D
  37  * under section 6.4. It needs to be constructed w/ a hash subkey, i.e.
  38  * block H. Given input of 128-bit blocks, it will process and output
  39  * a 128-bit block.
  40  *
  41  * <p>This function is used in the implementation of GCM mode.
  42  *
  43  * @since 1.8
  44  */
  45 final class GHASH {
  46 
  47     private static final byte P128 = (byte) 0xe1; //reduction polynomial
  48 
  49     private static boolean getBit(byte[] b, int pos) {
  50         int p = pos / 8;
  51         pos %= 8;
  52         int i = (b[p] >>> (7 - pos)) & 1;
  53         return i != 0;
  54     }
  55 
  56     private static void shift(byte[] b) {
  57         byte temp, temp2;
  58         temp2 = 0;
  59         for (int i = 0; i < b.length; i++) {
  60             temp = (byte) ((b[i] & 0x01) << 7);
  61             b[i] = (byte) ((b[i] & 0xff) >>> 1);
  62             b[i] = (byte) (b[i] | temp2);
  63             temp2 = temp;
  64         }
  65     }
  66 
  67     // Given block X and Y, returns the muliplication of X * Y
  68     private static byte[] blockMult(byte[] x, byte[] y) {
  69         if (x.length != AES_BLOCK_SIZE || y.length != AES_BLOCK_SIZE) {
  70             throw new RuntimeException("illegal input sizes");
  71         }
  72         byte[] z = new byte[AES_BLOCK_SIZE];
  73         byte[] v = y.clone();
  74         // calculate Z1-Z127 and V1-V127
  75         for (int i = 0; i < 127; i++) {
  76             // Zi+1 = Zi if bit i of x is 0
  77             if (getBit(x, i)) {
  78                 for (int n = 0; n < z.length; n++) {
  79                     z[n] ^= v[n];
  80                 }
  81             }
  82             boolean lastBitOfV = getBit(v, 127);
  83             shift(v);
  84             if (lastBitOfV) v[0] ^= P128;
  85         }
  86         // calculate Z128
  87         if (getBit(x, 127)) {
  88             for (int n = 0; n < z.length; n++) {
  89                 z[n] ^= v[n];
  90             }
  91         }
  92         return z;
  93     }
  94 
  95     // hash subkey H; should not change after the object has been constructed
  96     private final byte[] subkeyH;
  97 
  98     // buffer for storing hash
  99     private byte[] state;
 100 
 101     // variables for save/restore calls
 102     private byte[] stateSave = null;
 103 
 104     /**
 105      * Initializes the cipher in the specified mode with the given key
 106      * and iv.
 107      *
 108      * @param subkeyH the hash subkey
 109      *
 110      * @exception ProviderException if the given key is inappropriate for
 111      * initializing this digest
 112      */
 113     GHASH(byte[] subkeyH) throws ProviderException {
 114         if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) {
 115             throw new ProviderException("Internal error");
 116         }
 117         this.subkeyH = subkeyH;
 118         this.state = new byte[AES_BLOCK_SIZE];
 119     }
 120 
 121     /**
 122      * Resets the GHASH object to its original state, i.e. blank w/
 123      * the same subkey H. Used after digest() is called and to re-use
 124      * this object for different data w/ the same H.
 125      */
 126     void reset() {
 127         Arrays.fill(state, (byte) 0);
 128     }
 129 
 130     /**
 131      * Save the current snapshot of this GHASH object.
 132      */
 133     void save() {
 134         stateSave = state.clone();
 135     }
 136 
 137     /**
 138      * Restores this object using the saved snapshot.
 139      */
 140     void restore() {
 141         state = stateSave;
 142     }
 143 
 144     private void processBlock(byte[] data, int ofs) {
 145         if (data.length - ofs < AES_BLOCK_SIZE) {
 146             throw new RuntimeException("need complete block");
 147         }
 148         for (int n = 0; n < state.length; n++) {
 149             state[n] ^= data[ofs + n];
 150         }
 151         state = blockMult(state, subkeyH);
 152     }
 153 
 154     void update(byte[] in) {
 155         update(in, 0, in.length);
 156     }
 157 
 158     void update(byte[] in, int inOfs, int inLen) {
 159         if (inLen - inOfs > in.length) {
 160             throw new RuntimeException("input length out of bound");
 161         }
 162         if (inLen % AES_BLOCK_SIZE != 0) {
 163             throw new RuntimeException("input length unsupported");
 164         }
 165 
 166         for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) {
 167             processBlock(in, i);
 168         }
 169     }
 170 
 171     byte[] digest() {
 172         try {
 173             return state.clone();
 174         } finally {
 175             reset();
 176         }
 177     }
 178 }