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
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 }
|
1 /*
2 * Copyright (c) 2013, 2015, 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
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 state[0], state[1] by subkeyH[0], subkeyH[1].
66 private void blockMult(long[] subH) {
67 long Z0 = 0;
68 long Z1 = 0;
69 long V0 = subH[0];
70 long V1 = subH[1];
71 long X;
72
73 // Separate loops for processing state[0] and state[1].
74 X = state[0];
75 for (int i = 0; i < 64; i++) {
76 // Zi+1 = Zi if bit i of x is 0
77 long mask = X >> 63;
78 Z0 ^= V0 & mask;
79 Z1 ^= V1 & mask;
80
81 // Save mask for conditional reduction below.
82 mask = (V1 << 63) >> 63;
83
84 // V = rightshift(V)
85 long carry = V0 & 1;
86 V0 = V0 >>> 1;
87 V1 = (V1 >>> 1) | (carry << 63);
88
89 // Conditional reduction modulo P128.
90 V0 ^= 0xe100000000000000L & mask;
91 X <<= 1;
92 }
93
94 X = state[1];
95 for (int i = 64; i < 127; i++) {
96 // Zi+1 = Zi if bit i of x is 0
97 long mask = X >> 63;
98 Z0 ^= V0 & mask;
99 Z1 ^= V1 & mask;
100
101 // Save mask for conditional reduction below.
102 mask = (V1 << 63) >> 63;
103
104 // V = rightshift(V)
105 long carry = V0 & 1;
106 V0 = V0 >>> 1;
107 V1 = (V1 >>> 1) | (carry << 63);
108
109 // Conditional reduction.
110 V0 ^= 0xe100000000000000L & mask;
111 X <<= 1;
112 }
113
114 // calculate Z128
115 long mask = X >> 63;
116 Z0 ^= V0 & mask;
117 Z1 ^= V1 & mask;
118
119 // Save result.
120 state[0] = Z0;
121 state[1] = Z1;
122
123 }
124
125 /* subkeyH and state are stored in long[] for GHASH intrinsic use */
126
127 // hash subkey H; should not change after the object has been constructed
128 private final long[] subkeyH;
129
130 // buffer for storing hash
131 private final long[] state;
132
133 // variables for save/restore calls
134 private long stateSave0, stateSave1;
135
136 /**
137 * Initializes the cipher in the specified mode with the given key
138 * and iv.
139 *
140 * @param subkeyH the hash subkey
141 *
142 * @exception ProviderException if the given key is inappropriate for
143 * initializing this digest
144 */
145 GHASH(byte[] subkeyH) throws ProviderException {
146 if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) {
147 throw new ProviderException("Internal error");
148 }
149 state = new long[2];
150 this.subkeyH = new long[2];
151 this.subkeyH[0] = getLong(subkeyH, 0);
152 this.subkeyH[1] = getLong(subkeyH, 8);
153 }
154
155 /**
156 * Resets the GHASH object to its original state, i.e. blank w/
157 * the same subkey H. Used after digest() is called and to re-use
158 * this object for different data w/ the same H.
159 */
160 void reset() {
161 state[0] = 0;
162 state[1] = 0;
163 }
164
165 /**
166 * Save the current snapshot of this GHASH object.
167 */
168 void save() {
169 stateSave0 = state[0];
170 stateSave1 = state[1];
171 }
172
173 /**
174 * Restores this object using the saved snapshot.
175 */
176 void restore() {
177 state[0] = stateSave0;
178 state[1] = stateSave1;
179 }
180
181 private void processBlock(byte[] data, int ofs) {
182 state[0] ^= getLong(data, ofs);
183 state[1] ^= getLong(data, ofs + 8);
184 blockMult(subkeyH);
185 }
186
187 void update(byte[] in) {
188 update(in, 0, in.length);
189 }
190
191 void update(byte[] in, int inOfs, int inLen) {
192 if (inLen == 0) {
193 return;
194 }
195 if (inLen < 0 || inOfs < 0 || inLen > in.length - inOfs) {
196 throw new RuntimeException("input length out of bound");
197 }
198 if (inLen % AES_BLOCK_SIZE != 0) {
199 throw new RuntimeException("input length unsupported");
200 }
201
202 // These two checks are for C2 checking
203 if (state.length != 2) {
204 throw new RuntimeException("internal state has invalid length " +
205 state.length);
206 }
207 if (subkeyH.length != 2) {
208 throw new RuntimeException("internal subkeyH has invalid length" +
209 subkeyH.length);
210 }
211
212 processBlocks(in, inOfs, inLen/AES_BLOCK_SIZE);
213 }
214
215 /*
216 * This is an intrinsified method. The method's argument list must match
217 * the hotspot signature. This method and methods called by it, cannot
218 * throw exceptions or allocate arrays as it will breaking intrinsics
219 */
220 private void processBlocks(byte[] data, int inOfs, int blocks) {
221 int offset = inOfs;
222 while (blocks > 0) {
223 processBlock(data, offset);
224 blocks--;
225 offset += AES_BLOCK_SIZE;
226 }
227 }
228
229 byte[] digest() {
230 byte[] result = new byte[AES_BLOCK_SIZE];
231 putLong(result, 0, state[0]);
232 putLong(result, 8, state[1]);
233 reset();
234 return result;
235 }
236 }
|