blob: 74d2dd7d57f2d1da3fc054c5ec18a49376bdde17 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.provider;
27
28import static java.lang.Integer.reverseBytes;
29import static java.lang.Long.reverseBytes;
30
31import java.nio.ByteOrder;
32
33import sun.misc.Unsafe;
34
35/**
36 * Optimized methods for converting between byte[] and int[]/long[], both for
37 * big endian and little endian byte orders.
38 *
39 * Currently, it includes a default code path plus two optimized code paths.
40 * One is for little endian architectures that support full speed int/long
41 * access at unaligned addresses (i.e. x86/amd64). The second is for big endian
42 * architectures (that only support correctly aligned access), such as SPARC.
43 * These are the only platforms we currently support, but other optimized
44 * variants could be added as needed.
45 *
46 * NOTE that because this code performs unchecked direct memory access, it
47 * MUST be restricted to trusted code. It is imperative that the caller protects
48 * against out of bounds memory access by performing the necessary bounds
49 * checks before calling methods in this class.
50 *
51 * This class may also be helpful in improving the performance of the
52 * crypto code in the SunJCE provider. However, for now it is only accessible by
53 * the message digest implementation in the SUN provider.
54 *
55 * @since 1.6
56 * @author Andreas Sterbenz
57 */
58final class ByteArrayAccess {
59
60 private ByteArrayAccess() {
61 // empty
62 }
63
64 private static final Unsafe unsafe = Unsafe.getUnsafe();
65
66 // whether to use the optimized path for little endian platforms that
67 // support full speed unaligned memory access.
68 private static final boolean littleEndianUnaligned;
69
70 // whether to use the optimzied path for big endian platforms that
71 // support only correctly aligned full speed memory access.
72 // (Note that on SPARC unaligned memory access is possible, but it is
73 // implemented using a software trap and therefore very slow)
74 private static final boolean bigEndian;
75
76 private final static int byteArrayOfs = unsafe.arrayBaseOffset(byte[].class);
77
78 static {
79 boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1)
80 && (unsafe.arrayIndexScale(int[].class) == 4)
81 && (unsafe.arrayIndexScale(long[].class) == 8)
82 && ((byteArrayOfs & 3) == 0));
83
84 ByteOrder byteOrder = ByteOrder.nativeOrder();
85 littleEndianUnaligned =
86 scaleOK && unaligned() && (byteOrder == ByteOrder.LITTLE_ENDIAN);
87 bigEndian =
88 scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN);
89 }
90
91 // Return whether this platform supports full speed int/long memory access
92 // at unaligned addresses.
93 // This code was copied from java.nio.Bits because there is no equivalent
94 // public API.
95 private static boolean unaligned() {
96 String arch = java.security.AccessController.doPrivileged
97 (new sun.security.action.GetPropertyAction("os.arch", ""));
98 return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64");
99 }
100
101 /**
102 * byte[] to int[] conversion, little endian byte order.
103 */
104 static void b2iLittle(byte[] in, int inOfs, int[] out, int outOfs, int len) {
105 if (littleEndianUnaligned) {
106 inOfs += byteArrayOfs;
107 len += inOfs;
108 while (inOfs < len) {
109 out[outOfs++] = unsafe.getInt(in, (long)inOfs);
110 inOfs += 4;
111 }
112 } else if (bigEndian && ((inOfs & 3) == 0)) {
113 inOfs += byteArrayOfs;
114 len += inOfs;
115 while (inOfs < len) {
116 out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
117 inOfs += 4;
118 }
119 } else {
120 len += inOfs;
121 while (inOfs < len) {
122 out[outOfs++] = ((in[inOfs ] & 0xff) )
123 | ((in[inOfs + 1] & 0xff) << 8)
124 | ((in[inOfs + 2] & 0xff) << 16)
125 | ((in[inOfs + 3] ) << 24);
126 inOfs += 4;
127 }
128 }
129 }
130
131 // Special optimization of b2iLittle(in, inOfs, out, 0, 64)
132 static void b2iLittle64(byte[] in, int inOfs, int[] out) {
133 if (littleEndianUnaligned) {
134 inOfs += byteArrayOfs;
135 out[ 0] = unsafe.getInt(in, (long)(inOfs ));
136 out[ 1] = unsafe.getInt(in, (long)(inOfs + 4));
137 out[ 2] = unsafe.getInt(in, (long)(inOfs + 8));
138 out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
139 out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
140 out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
141 out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
142 out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
143 out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
144 out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
145 out[10] = unsafe.getInt(in, (long)(inOfs + 40));
146 out[11] = unsafe.getInt(in, (long)(inOfs + 44));
147 out[12] = unsafe.getInt(in, (long)(inOfs + 48));
148 out[13] = unsafe.getInt(in, (long)(inOfs + 52));
149 out[14] = unsafe.getInt(in, (long)(inOfs + 56));
150 out[15] = unsafe.getInt(in, (long)(inOfs + 60));
151 } else if (bigEndian && ((inOfs & 3) == 0)) {
152 inOfs += byteArrayOfs;
153 out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs )));
154 out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4)));
155 out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8)));
156 out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
157 out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
158 out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
159 out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
160 out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
161 out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
162 out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
163 out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
164 out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
165 out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
166 out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
167 out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
168 out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
169 } else {
170 b2iLittle(in, inOfs, out, 0, 64);
171 }
172 }
173
174 /**
175 * int[] to byte[] conversion, little endian byte order.
176 */
177 static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs, int len) {
178 if (littleEndianUnaligned) {
179 outOfs += byteArrayOfs;
180 len += outOfs;
181 while (outOfs < len) {
182 unsafe.putInt(out, (long)outOfs, in[inOfs++]);
183 outOfs += 4;
184 }
185 } else if (bigEndian && ((outOfs & 3) == 0)) {
186 outOfs += byteArrayOfs;
187 len += outOfs;
188 while (outOfs < len) {
189 unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
190 outOfs += 4;
191 }
192 } else {
193 len += outOfs;
194 while (outOfs < len) {
195 int i = in[inOfs++];
196 out[outOfs++] = (byte)(i );
197 out[outOfs++] = (byte)(i >> 8);
198 out[outOfs++] = (byte)(i >> 16);
199 out[outOfs++] = (byte)(i >> 24);
200 }
201 }
202 }
203
204 // Store one 32-bit value into out[outOfs..outOfs+3] in little endian order.
205 static void i2bLittle4(int val, byte[] out, int outOfs) {
206 if (littleEndianUnaligned) {
207 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
208 } else if (bigEndian && ((outOfs & 3) == 0)) {
209 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
210 } else {
211 out[outOfs ] = (byte)(val );
212 out[outOfs + 1] = (byte)(val >> 8);
213 out[outOfs + 2] = (byte)(val >> 16);
214 out[outOfs + 3] = (byte)(val >> 24);
215 }
216 }
217
218 /**
219 * byte[] to int[] conversion, big endian byte order.
220 */
221 static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs, int len) {
222 if (littleEndianUnaligned) {
223 inOfs += byteArrayOfs;
224 len += inOfs;
225 while (inOfs < len) {
226 out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
227 inOfs += 4;
228 }
229 } else if (bigEndian && ((inOfs & 3) == 0)) {
230 inOfs += byteArrayOfs;
231 len += inOfs;
232 while (inOfs < len) {
233 out[outOfs++] = unsafe.getInt(in, (long)inOfs);
234 inOfs += 4;
235 }
236 } else {
237 len += inOfs;
238 while (inOfs < len) {
239 out[outOfs++] = ((in[inOfs + 3] & 0xff) )
240 | ((in[inOfs + 2] & 0xff) << 8)
241 | ((in[inOfs + 1] & 0xff) << 16)
242 | ((in[inOfs ] ) << 24);
243 inOfs += 4;
244 }
245 }
246 }
247
248 // Special optimization of b2iBig(in, inOfs, out, 0, 64)
249 static void b2iBig64(byte[] in, int inOfs, int[] out) {
250 if (littleEndianUnaligned) {
251 inOfs += byteArrayOfs;
252 out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs )));
253 out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4)));
254 out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8)));
255 out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
256 out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
257 out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
258 out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
259 out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
260 out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
261 out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
262 out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
263 out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
264 out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
265 out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
266 out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
267 out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
268 } else if (bigEndian && ((inOfs & 3) == 0)) {
269 inOfs += byteArrayOfs;
270 out[ 0] = unsafe.getInt(in, (long)(inOfs ));
271 out[ 1] = unsafe.getInt(in, (long)(inOfs + 4));
272 out[ 2] = unsafe.getInt(in, (long)(inOfs + 8));
273 out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
274 out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
275 out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
276 out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
277 out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
278 out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
279 out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
280 out[10] = unsafe.getInt(in, (long)(inOfs + 40));
281 out[11] = unsafe.getInt(in, (long)(inOfs + 44));
282 out[12] = unsafe.getInt(in, (long)(inOfs + 48));
283 out[13] = unsafe.getInt(in, (long)(inOfs + 52));
284 out[14] = unsafe.getInt(in, (long)(inOfs + 56));
285 out[15] = unsafe.getInt(in, (long)(inOfs + 60));
286 } else {
287 b2iBig(in, inOfs, out, 0, 64);
288 }
289 }
290
291 /**
292 * int[] to byte[] conversion, big endian byte order.
293 */
294 static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs, int len) {
295 if (littleEndianUnaligned) {
296 outOfs += byteArrayOfs;
297 len += outOfs;
298 while (outOfs < len) {
299 unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
300 outOfs += 4;
301 }
302 } else if (bigEndian && ((outOfs & 3) == 0)) {
303 outOfs += byteArrayOfs;
304 len += outOfs;
305 while (outOfs < len) {
306 unsafe.putInt(out, (long)outOfs, in[inOfs++]);
307 outOfs += 4;
308 }
309 } else {
310 len += outOfs;
311 while (outOfs < len) {
312 int i = in[inOfs++];
313 out[outOfs++] = (byte)(i >> 24);
314 out[outOfs++] = (byte)(i >> 16);
315 out[outOfs++] = (byte)(i >> 8);
316 out[outOfs++] = (byte)(i );
317 }
318 }
319 }
320
321 // Store one 32-bit value into out[outOfs..outOfs+3] in big endian order.
322 static void i2bBig4(int val, byte[] out, int outOfs) {
323 if (littleEndianUnaligned) {
324 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
325 } else if (bigEndian && ((outOfs & 3) == 0)) {
326 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
327 } else {
328 out[outOfs ] = (byte)(val >> 24);
329 out[outOfs + 1] = (byte)(val >> 16);
330 out[outOfs + 2] = (byte)(val >> 8);
331 out[outOfs + 3] = (byte)(val );
332 }
333 }
334
335 /**
336 * byte[] to long[] conversion, big endian byte order.
337 */
338 static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs, int len) {
339 if (littleEndianUnaligned) {
340 inOfs += byteArrayOfs;
341 len += inOfs;
342 while (inOfs < len) {
343 out[outOfs++] = reverseBytes(unsafe.getLong(in, (long)inOfs));
344 inOfs += 8;
345 }
346 } else if (bigEndian && ((inOfs & 3) == 0)) {
347 // In the current HotSpot memory layout, the first element of a
348 // byte[] is only 32-bit aligned, not 64-bit.
349 // That means we could use getLong() only for offset 4, 12, etc.,
350 // which would rarely occur in practice. Instead, we use an
351 // optimization that uses getInt() so that it works for offset 0.
352 inOfs += byteArrayOfs;
353 len += inOfs;
354 while (inOfs < len) {
355 out[outOfs++] =
356 ((long)unsafe.getInt(in, (long)inOfs) << 32)
357 | (unsafe.getInt(in, (long)(inOfs + 4)) & 0xffffffffL);
358 inOfs += 8;
359 }
360 } else {
361 len += inOfs;
362 while (inOfs < len) {
363 int i1 = ((in[inOfs + 3] & 0xff) )
364 | ((in[inOfs + 2] & 0xff) << 8)
365 | ((in[inOfs + 1] & 0xff) << 16)
366 | ((in[inOfs ] ) << 24);
367 inOfs += 4;
368 int i2 = ((in[inOfs + 3] & 0xff) )
369 | ((in[inOfs + 2] & 0xff) << 8)
370 | ((in[inOfs + 1] & 0xff) << 16)
371 | ((in[inOfs ] ) << 24);
372 out[outOfs++] = ((long)i1 << 32) | (i2 & 0xffffffffL);
373 inOfs += 4;
374 }
375 }
376 }
377
378 // Special optimization of b2lBig(in, inOfs, out, 0, 128)
379 static void b2lBig128(byte[] in, int inOfs, long[] out) {
380 if (littleEndianUnaligned) {
381 inOfs += byteArrayOfs;
382 out[ 0] = reverseBytes(unsafe.getLong(in, (long)(inOfs )));
383 out[ 1] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 8)));
384 out[ 2] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 16)));
385 out[ 3] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 24)));
386 out[ 4] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 32)));
387 out[ 5] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 40)));
388 out[ 6] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 48)));
389 out[ 7] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 56)));
390 out[ 8] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 64)));
391 out[ 9] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 72)));
392 out[10] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 80)));
393 out[11] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 88)));
394 out[12] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 96)));
395 out[13] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 104)));
396 out[14] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 112)));
397 out[15] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 120)));
398 } else {
399 // no optimization for big endian, see comments in b2lBig
400 b2lBig(in, inOfs, out, 0, 128);
401 }
402 }
403
404 /**
405 * long[] to byte[] conversion, big endian byte order.
406 */
407 static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs, int len) {
408 len += outOfs;
409 while (outOfs < len) {
410 long i = in[inOfs++];
411 out[outOfs++] = (byte)(i >> 56);
412 out[outOfs++] = (byte)(i >> 48);
413 out[outOfs++] = (byte)(i >> 40);
414 out[outOfs++] = (byte)(i >> 32);
415 out[outOfs++] = (byte)(i >> 24);
416 out[outOfs++] = (byte)(i >> 16);
417 out[outOfs++] = (byte)(i >> 8);
418 out[outOfs++] = (byte)(i );
419 }
420 }
421
422}