1 /* 2 * Copyright (c) 2006, 2016, 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 package sun.security.provider; 27 28 import static java.lang.Integer.reverseBytes; 29 import static java.lang.Long.reverseBytes; 30 31 import java.nio.ByteOrder; 32 33 import 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 ArrayIndexOutOfBoundsException will be thrown if the bounds checks 47 * failed. 48 * 49 * This class may also be helpful in improving the performance of the 50 * crypto code in the SunJCE provider. However, for now it is only accessible by 51 * the message digest implementation in the SUN provider. 52 * 53 * @since 1.6 54 * @author Andreas Sterbenz 55 */ 56 final class ByteArrayAccess { 57 58 private ByteArrayAccess() { 59 // empty 60 } 61 62 private static final Unsafe unsafe = Unsafe.getUnsafe(); 63 64 // whether to use the optimized path for little endian platforms that 65 // support full speed unaligned memory access. 66 private static final boolean littleEndianUnaligned; 67 68 // whether to use the optimzied path for big endian platforms that 69 // support only correctly aligned full speed memory access. 70 // (Note that on SPARC unaligned memory access is possible, but it is 71 // implemented using a software trap and therefore very slow) 72 private static final boolean bigEndian; 73 74 private final static int byteArrayOfs = unsafe.arrayBaseOffset(byte[].class); 75 76 static { 77 boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1) 78 && (unsafe.arrayIndexScale(int[].class) == 4) 79 && (unsafe.arrayIndexScale(long[].class) == 8) 80 && ((byteArrayOfs & 3) == 0)); 81 82 ByteOrder byteOrder = ByteOrder.nativeOrder(); 83 littleEndianUnaligned = 84 scaleOK && unaligned() && (byteOrder == ByteOrder.LITTLE_ENDIAN); 85 bigEndian = 86 scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN); 87 } 88 89 // Return whether this platform supports full speed int/long memory access 90 // at unaligned addresses. 91 // This code was copied from java.nio.Bits because there is no equivalent 92 // public API. 93 private static boolean unaligned() { 94 String arch = java.security.AccessController.doPrivileged 95 (new sun.security.action.GetPropertyAction("os.arch", "")); 96 return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64") 97 || arch.equals("x86_64") || arch.equals("ppc64") || arch.equals("ppc64le") 98 || arch.equals("aarch64"); 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 ((inOfs < 0) || ((in.length - inOfs) < len) || 106 (outOfs < 0) || ((out.length - outOfs) < len/4)) { 107 throw new ArrayIndexOutOfBoundsException(); 108 } 109 if (littleEndianUnaligned) { 110 inOfs += byteArrayOfs; 111 len += inOfs; 112 while (inOfs < len) { 113 out[outOfs++] = unsafe.getInt(in, (long)inOfs); 114 inOfs += 4; 115 } 116 } else if (bigEndian && ((inOfs & 3) == 0)) { 117 inOfs += byteArrayOfs; 118 len += inOfs; 119 while (inOfs < len) { 120 out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs)); 121 inOfs += 4; 122 } 123 } else { 124 len += inOfs; 125 while (inOfs < len) { 126 out[outOfs++] = ((in[inOfs ] & 0xff) ) 127 | ((in[inOfs + 1] & 0xff) << 8) 128 | ((in[inOfs + 2] & 0xff) << 16) 129 | ((in[inOfs + 3] ) << 24); 130 inOfs += 4; 131 } 132 } 133 } 134 135 // Special optimization of b2iLittle(in, inOfs, out, 0, 64) 136 static void b2iLittle64(byte[] in, int inOfs, int[] out) { 137 if ((inOfs < 0) || ((in.length - inOfs) < 64) || 138 (out.length < 16)) { 139 throw new ArrayIndexOutOfBoundsException(); 140 } 141 if (littleEndianUnaligned) { 142 inOfs += byteArrayOfs; 143 out[ 0] = unsafe.getInt(in, (long)(inOfs )); 144 out[ 1] = unsafe.getInt(in, (long)(inOfs + 4)); 145 out[ 2] = unsafe.getInt(in, (long)(inOfs + 8)); 146 out[ 3] = unsafe.getInt(in, (long)(inOfs + 12)); 147 out[ 4] = unsafe.getInt(in, (long)(inOfs + 16)); 148 out[ 5] = unsafe.getInt(in, (long)(inOfs + 20)); 149 out[ 6] = unsafe.getInt(in, (long)(inOfs + 24)); 150 out[ 7] = unsafe.getInt(in, (long)(inOfs + 28)); 151 out[ 8] = unsafe.getInt(in, (long)(inOfs + 32)); 152 out[ 9] = unsafe.getInt(in, (long)(inOfs + 36)); 153 out[10] = unsafe.getInt(in, (long)(inOfs + 40)); 154 out[11] = unsafe.getInt(in, (long)(inOfs + 44)); 155 out[12] = unsafe.getInt(in, (long)(inOfs + 48)); 156 out[13] = unsafe.getInt(in, (long)(inOfs + 52)); 157 out[14] = unsafe.getInt(in, (long)(inOfs + 56)); 158 out[15] = unsafe.getInt(in, (long)(inOfs + 60)); 159 } else if (bigEndian && ((inOfs & 3) == 0)) { 160 inOfs += byteArrayOfs; 161 out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs ))); 162 out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4))); 163 out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8))); 164 out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12))); 165 out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16))); 166 out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20))); 167 out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24))); 168 out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28))); 169 out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32))); 170 out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36))); 171 out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40))); 172 out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44))); 173 out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48))); 174 out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52))); 175 out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56))); 176 out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60))); 177 } else { 178 b2iLittle(in, inOfs, out, 0, 64); 179 } 180 } 181 182 /** 183 * int[] to byte[] conversion, little endian byte order. 184 */ 185 static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs, int len) { 186 if ((inOfs < 0) || ((in.length - inOfs) < len/4) || 187 (outOfs < 0) || ((out.length - outOfs) < len)) { 188 throw new ArrayIndexOutOfBoundsException(); 189 } 190 if (littleEndianUnaligned) { 191 outOfs += byteArrayOfs; 192 len += outOfs; 193 while (outOfs < len) { 194 unsafe.putInt(out, (long)outOfs, in[inOfs++]); 195 outOfs += 4; 196 } 197 } else if (bigEndian && ((outOfs & 3) == 0)) { 198 outOfs += byteArrayOfs; 199 len += outOfs; 200 while (outOfs < len) { 201 unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++])); 202 outOfs += 4; 203 } 204 } else { 205 len += outOfs; 206 while (outOfs < len) { 207 int i = in[inOfs++]; 208 out[outOfs++] = (byte)(i ); 209 out[outOfs++] = (byte)(i >> 8); 210 out[outOfs++] = (byte)(i >> 16); 211 out[outOfs++] = (byte)(i >> 24); 212 } 213 } 214 } 215 216 // Store one 32-bit value into out[outOfs..outOfs+3] in little endian order. 217 static void i2bLittle4(int val, byte[] out, int outOfs) { 218 if ((outOfs < 0) || ((out.length - outOfs) < 4)) { 219 throw new ArrayIndexOutOfBoundsException(); 220 } 221 if (littleEndianUnaligned) { 222 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val); 223 } else if (bigEndian && ((outOfs & 3) == 0)) { 224 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val)); 225 } else { 226 out[outOfs ] = (byte)(val ); 227 out[outOfs + 1] = (byte)(val >> 8); 228 out[outOfs + 2] = (byte)(val >> 16); 229 out[outOfs + 3] = (byte)(val >> 24); 230 } 231 } 232 233 /** 234 * byte[] to int[] conversion, big endian byte order. 235 */ 236 static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs, int len) { 237 if ((inOfs < 0) || ((in.length - inOfs) < len) || 238 (outOfs < 0) || ((out.length - outOfs) < len/4)) { 239 throw new ArrayIndexOutOfBoundsException(); 240 } 241 if (littleEndianUnaligned) { 242 inOfs += byteArrayOfs; 243 len += inOfs; 244 while (inOfs < len) { 245 out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs)); 246 inOfs += 4; 247 } 248 } else if (bigEndian && ((inOfs & 3) == 0)) { 249 inOfs += byteArrayOfs; 250 len += inOfs; 251 while (inOfs < len) { 252 out[outOfs++] = unsafe.getInt(in, (long)inOfs); 253 inOfs += 4; 254 } 255 } else { 256 len += inOfs; 257 while (inOfs < len) { 258 out[outOfs++] = ((in[inOfs + 3] & 0xff) ) 259 | ((in[inOfs + 2] & 0xff) << 8) 260 | ((in[inOfs + 1] & 0xff) << 16) 261 | ((in[inOfs ] ) << 24); 262 inOfs += 4; 263 } 264 } 265 } 266 267 // Special optimization of b2iBig(in, inOfs, out, 0, 64) 268 static void b2iBig64(byte[] in, int inOfs, int[] out) { 269 if ((inOfs < 0) || ((in.length - inOfs) < 64) || 270 (out.length < 16)) { 271 throw new ArrayIndexOutOfBoundsException(); 272 } 273 if (littleEndianUnaligned) { 274 inOfs += byteArrayOfs; 275 out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs ))); 276 out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4))); 277 out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8))); 278 out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12))); 279 out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16))); 280 out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20))); 281 out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24))); 282 out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28))); 283 out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32))); 284 out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36))); 285 out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40))); 286 out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44))); 287 out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48))); 288 out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52))); 289 out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56))); 290 out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60))); 291 } else if (bigEndian && ((inOfs & 3) == 0)) { 292 inOfs += byteArrayOfs; 293 out[ 0] = unsafe.getInt(in, (long)(inOfs )); 294 out[ 1] = unsafe.getInt(in, (long)(inOfs + 4)); 295 out[ 2] = unsafe.getInt(in, (long)(inOfs + 8)); 296 out[ 3] = unsafe.getInt(in, (long)(inOfs + 12)); 297 out[ 4] = unsafe.getInt(in, (long)(inOfs + 16)); 298 out[ 5] = unsafe.getInt(in, (long)(inOfs + 20)); 299 out[ 6] = unsafe.getInt(in, (long)(inOfs + 24)); 300 out[ 7] = unsafe.getInt(in, (long)(inOfs + 28)); 301 out[ 8] = unsafe.getInt(in, (long)(inOfs + 32)); 302 out[ 9] = unsafe.getInt(in, (long)(inOfs + 36)); 303 out[10] = unsafe.getInt(in, (long)(inOfs + 40)); 304 out[11] = unsafe.getInt(in, (long)(inOfs + 44)); 305 out[12] = unsafe.getInt(in, (long)(inOfs + 48)); 306 out[13] = unsafe.getInt(in, (long)(inOfs + 52)); 307 out[14] = unsafe.getInt(in, (long)(inOfs + 56)); 308 out[15] = unsafe.getInt(in, (long)(inOfs + 60)); 309 } else { 310 b2iBig(in, inOfs, out, 0, 64); 311 } 312 } 313 314 /** 315 * int[] to byte[] conversion, big endian byte order. 316 */ 317 static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs, int len) { 318 if ((inOfs < 0) || ((in.length - inOfs) < len/4) || 319 (outOfs < 0) || ((out.length - outOfs) < len)) { 320 throw new ArrayIndexOutOfBoundsException(); 321 } 322 if (littleEndianUnaligned) { 323 outOfs += byteArrayOfs; 324 len += outOfs; 325 while (outOfs < len) { 326 unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++])); 327 outOfs += 4; 328 } 329 } else if (bigEndian && ((outOfs & 3) == 0)) { 330 outOfs += byteArrayOfs; 331 len += outOfs; 332 while (outOfs < len) { 333 unsafe.putInt(out, (long)outOfs, in[inOfs++]); 334 outOfs += 4; 335 } 336 } else { 337 len += outOfs; 338 while (outOfs < len) { 339 int i = in[inOfs++]; 340 out[outOfs++] = (byte)(i >> 24); 341 out[outOfs++] = (byte)(i >> 16); 342 out[outOfs++] = (byte)(i >> 8); 343 out[outOfs++] = (byte)(i ); 344 } 345 } 346 } 347 348 // Store one 32-bit value into out[outOfs..outOfs+3] in big endian order. 349 static void i2bBig4(int val, byte[] out, int outOfs) { 350 if ((outOfs < 0) || ((out.length - outOfs) < 4)) { 351 throw new ArrayIndexOutOfBoundsException(); 352 } 353 if (littleEndianUnaligned) { 354 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val)); 355 } else if (bigEndian && ((outOfs & 3) == 0)) { 356 unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val); 357 } else { 358 out[outOfs ] = (byte)(val >> 24); 359 out[outOfs + 1] = (byte)(val >> 16); 360 out[outOfs + 2] = (byte)(val >> 8); 361 out[outOfs + 3] = (byte)(val ); 362 } 363 } 364 365 /** 366 * byte[] to long[] conversion, big endian byte order. 367 */ 368 static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs, int len) { 369 if ((inOfs < 0) || ((in.length - inOfs) < len) || 370 (outOfs < 0) || ((out.length - outOfs) < len/8)) { 371 throw new ArrayIndexOutOfBoundsException(); 372 } 373 if (littleEndianUnaligned) { 374 inOfs += byteArrayOfs; 375 len += inOfs; 376 while (inOfs < len) { 377 out[outOfs++] = reverseBytes(unsafe.getLong(in, (long)inOfs)); 378 inOfs += 8; 379 } 380 } else if (bigEndian && ((inOfs & 3) == 0)) { 381 // In the current HotSpot memory layout, the first element of a 382 // byte[] is only 32-bit aligned, not 64-bit. 383 // That means we could use getLong() only for offset 4, 12, etc., 384 // which would rarely occur in practice. Instead, we use an 385 // optimization that uses getInt() so that it works for offset 0. 386 inOfs += byteArrayOfs; 387 len += inOfs; 388 while (inOfs < len) { 389 out[outOfs++] = 390 ((long)unsafe.getInt(in, (long)inOfs) << 32) 391 | (unsafe.getInt(in, (long)(inOfs + 4)) & 0xffffffffL); 392 inOfs += 8; 393 } 394 } else { 395 len += inOfs; 396 while (inOfs < len) { 397 int i1 = ((in[inOfs + 3] & 0xff) ) 398 | ((in[inOfs + 2] & 0xff) << 8) 399 | ((in[inOfs + 1] & 0xff) << 16) 400 | ((in[inOfs ] ) << 24); 401 inOfs += 4; 402 int i2 = ((in[inOfs + 3] & 0xff) ) 403 | ((in[inOfs + 2] & 0xff) << 8) 404 | ((in[inOfs + 1] & 0xff) << 16) 405 | ((in[inOfs ] ) << 24); 406 out[outOfs++] = ((long)i1 << 32) | (i2 & 0xffffffffL); 407 inOfs += 4; 408 } 409 } 410 } 411 412 // Special optimization of b2lBig(in, inOfs, out, 0, 128) 413 static void b2lBig128(byte[] in, int inOfs, long[] out) { 414 if ((inOfs < 0) || ((in.length - inOfs) < 128) || 415 (out.length < 16)) { 416 throw new ArrayIndexOutOfBoundsException(); 417 } 418 if (littleEndianUnaligned) { 419 inOfs += byteArrayOfs; 420 out[ 0] = reverseBytes(unsafe.getLong(in, (long)(inOfs ))); 421 out[ 1] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 8))); 422 out[ 2] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 16))); 423 out[ 3] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 24))); 424 out[ 4] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 32))); 425 out[ 5] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 40))); 426 out[ 6] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 48))); 427 out[ 7] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 56))); 428 out[ 8] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 64))); 429 out[ 9] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 72))); 430 out[10] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 80))); 431 out[11] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 88))); 432 out[12] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 96))); 433 out[13] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 104))); 434 out[14] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 112))); 435 out[15] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 120))); 436 } else { 437 // no optimization for big endian, see comments in b2lBig 438 b2lBig(in, inOfs, out, 0, 128); 439 } 440 } 441 442 /** 443 * long[] to byte[] conversion, big endian byte order. 444 */ 445 static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs, int len) { 446 if ((inOfs < 0) || ((in.length - inOfs) < len/8) || 447 (outOfs < 0) || ((out.length - outOfs) < len)) { 448 throw new ArrayIndexOutOfBoundsException(); 449 } 450 len += outOfs; 451 while (outOfs < len) { 452 long i = in[inOfs++]; 453 out[outOfs++] = (byte)(i >> 56); 454 out[outOfs++] = (byte)(i >> 48); 455 out[outOfs++] = (byte)(i >> 40); 456 out[outOfs++] = (byte)(i >> 32); 457 out[outOfs++] = (byte)(i >> 24); 458 out[outOfs++] = (byte)(i >> 16); 459 out[outOfs++] = (byte)(i >> 8); 460 out[outOfs++] = (byte)(i ); 461 } 462 } 463 }