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 }
--- EOF ---