src/share/classes/com/sun/crypto/provider/GHASH.java

Print this page
rev 10474 : com.sun.crypto.provider.GHASH performance fix


  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 }


  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 }