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.netty.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 }