View Javadoc
1   /*
2    * Copyright 2016 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.util.internal;
17  
18  public final class ConstantTimeUtils {
19      private ConstantTimeUtils() { }
20  
21      /**
22       * Compare two {@code int}s without leaking timing information.
23       * <p>
24       * The {@code int} return type is intentional and is designed to allow cascading of constant time operations:
25       * <pre>
26       *     int l1 = 1;
27       *     int l2 = 1;
28       *     int l3 = 1;
29       *     int l4 = 500;
30       *     boolean equals = (equalsConstantTime(l1, l2) & equalsConstantTime(l3, l4)) != 0;
31       * </pre>
32       * @param x the first value.
33       * @param y the second value.
34       * @return {@code 0} if not equal. {@code 1} if equal.
35       */
36      public static int equalsConstantTime(int x, int y) {
37          int z = ~(x ^ y);
38          z &= z >> 16;
39          z &= z >> 8;
40          z &= z >> 4;
41          z &= z >> 2;
42          z &= z >> 1;
43          return z & 1;
44      }
45  
46      /**
47       * Compare two {@code longs}s without leaking timing information.
48       * <p>
49       * The {@code int} return type is intentional and is designed to allow cascading of constant time operations:
50       * <pre>
51       *     long l1 = 1;
52       *     long l2 = 1;
53       *     long l3 = 1;
54       *     long l4 = 500;
55       *     boolean equals = (equalsConstantTime(l1, l2) & equalsConstantTime(l3, l4)) != 0;
56       * </pre>
57       * @param x the first value.
58       * @param y the second value.
59       * @return {@code 0} if not equal. {@code 1} if equal.
60       */
61      public static int equalsConstantTime(long x, long y) {
62          long z = ~(x ^ y);
63          z &= z >> 32;
64          z &= z >> 16;
65          z &= z >> 8;
66          z &= z >> 4;
67          z &= z >> 2;
68          z &= z >> 1;
69          return (int) (z & 1);
70      }
71  
72      /**
73       * Compare two {@code byte} arrays for equality without leaking timing information.
74       * For performance reasons no bounds checking on the parameters is performed.
75       * <p>
76       * The {@code int} return type is intentional and is designed to allow cascading of constant time operations:
77       * <pre>
78       *     byte[] s1 = new {1, 2, 3};
79       *     byte[] s2 = new {1, 2, 3};
80       *     byte[] s3 = new {1, 2, 3};
81       *     byte[] s4 = new {4, 5, 6};
82       *     boolean equals = (equalsConstantTime(s1, 0, s2, 0, s1.length) &
83       *                       equalsConstantTime(s3, 0, s4, 0, s3.length)) != 0;
84       * </pre>
85       * @param bytes1 the first byte array.
86       * @param startPos1 the position (inclusive) to start comparing in {@code bytes1}.
87       * @param bytes2 the second byte array.
88       * @param startPos2 the position (inclusive) to start comparing in {@code bytes2}.
89       * @param length the amount of bytes to compare. This is assumed to be validated as not going out of bounds
90       * by the caller.
91       * @return {@code 0} if not equal. {@code 1} if equal.
92       */
93      public static int equalsConstantTime(byte[] bytes1, int startPos1,
94                                           byte[] bytes2, int startPos2, int length) {
95          // Benchmarking demonstrates that using an int to accumulate is faster than other data types.
96          int b = 0;
97          final int end = startPos1 + length;
98          for (; startPos1 < end; ++startPos1, ++startPos2) {
99              b |= bytes1[startPos1] ^ bytes2[startPos2];
100         }
101         return equalsConstantTime(b, 0);
102     }
103 
104     /**
105      * Compare two {@link CharSequence} objects without leaking timing information.
106      * <p>
107      * The {@code int} return type is intentional and is designed to allow cascading of constant time operations:
108      * <pre>
109      *     String s1 = "foo";
110      *     String s2 = "foo";
111      *     String s3 = "foo";
112      *     String s4 = "goo";
113      *     boolean equals = (equalsConstantTime(s1, s2) & equalsConstantTime(s3, s4)) != 0;
114      * </pre>
115      * @param s1 the first value.
116      * @param s2 the second value.
117      * @return {@code 0} if not equal. {@code 1} if equal.
118      */
119     public static int equalsConstantTime(CharSequence s1, CharSequence s2) {
120         if (s1.length() != s2.length()) {
121             return 0;
122         }
123 
124         // Benchmarking demonstrates that using an int to accumulate is faster than other data types.
125         int c = 0;
126         for (int i = 0; i < s1.length(); ++i) {
127             c |= s1.charAt(i) ^ s2.charAt(i);
128         }
129         return equalsConstantTime(c, 0);
130     }
131 }