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 }