-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #129 from SalusaSecondus/trimZeros
Decrease the timing differences when trimming zeros from DH TLS PMS
- Loading branch information
Showing
6 changed files
with
215 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.corretto.crypto.provider; | ||
|
||
/** | ||
* Contains several constant time utilities | ||
*/ | ||
final class ConstantTime { | ||
private ConstantTime() { | ||
// Prevent instantiation | ||
} | ||
|
||
/** | ||
* Equivalent to {@code val != 0 ? 1 : 0} | ||
*/ | ||
static final int isNonZero(int val) { | ||
return ((val | -val) >>> 31) & 0x01; // Unsigned bitshift | ||
} | ||
|
||
/** | ||
* Equivalent to {@code val == 0 ? 1 : 0} | ||
*/ | ||
static final int isZero(int val) { | ||
return 1 - isNonZero(val); | ||
} | ||
|
||
/** | ||
* Equivalent to {@code val < 0 ? 1 : 0} | ||
*/ | ||
static final int isNegative(int val) { | ||
return (val >>> 31) & 0x01; | ||
} | ||
|
||
/** | ||
* Equivalent to {@code x == y ? 1 : 0} | ||
*/ | ||
static final int equal(int x, int y) { | ||
final int difference = x - y; | ||
// Difference is 0 iff x == y | ||
return isZero(difference); | ||
} | ||
|
||
/** | ||
* Equivalent to {@code x > y ? 1 : 0} | ||
*/ | ||
static final int gt(int x, int y) { | ||
// Convert to long to avoid underflow | ||
final long xl = x; | ||
final long yl = y; | ||
final long difference = yl - xl; | ||
// If xl > yl, then difference is negative. | ||
// Thus, we can just return the sign-bit | ||
return (int) ((difference >>> 63) & 0x01); // Unsigned bitshift | ||
} | ||
|
||
/** | ||
* Equivalent to {@code selector != 0 ? a : b} | ||
*/ | ||
static final int select(int selector, int a, int b) { | ||
final int mask = isZero(selector) - 1; | ||
// Mask == -1 (all bits 1) iff selector != 0 | ||
// Mask == 0 (all bits 0) iff selector == 0 | ||
|
||
final int combined = a ^ b; | ||
|
||
return b ^ (combined & mask); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
tst/com/amazon/corretto/crypto/provider/test/ConstantTimeTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.corretto.crypto.provider.test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.params.provider.Arguments.arguments; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.junit.jupiter.api.parallel.Execution; | ||
import org.junit.jupiter.api.parallel.ExecutionMode; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
|
||
|
||
// Note: We don't actually test that these methods are constant time, just that they give the correct answers. | ||
@ExtendWith(TestResultLogger.class) | ||
@Execution(ExecutionMode.CONCURRENT) | ||
public class ConstantTimeTests { | ||
// A few common values which when combined can trigger edge cases | ||
private static final int[] TEST_VALUES = {Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -2, -1, 0, 1, 2, Integer.MAX_VALUE - 1, Integer.MAX_VALUE}; | ||
private static final Class<?> CONSTANT_TIME_CLASS; | ||
static { | ||
try { | ||
CONSTANT_TIME_CLASS = Class.forName("com.amazon.corretto.crypto.provider.ConstantTime"); | ||
} catch (Exception ex) { | ||
throw new RuntimeException(ex); | ||
} | ||
} | ||
|
||
|
||
public static List<Arguments> testPairs() { | ||
final List<Arguments> result = new ArrayList<>(); | ||
for (int a : TEST_VALUES) { | ||
for (int b : TEST_VALUES) { | ||
result.add(arguments(a, b)); | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
public static int[] testSingles() { | ||
return TEST_VALUES; | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("testSingles") | ||
public void testIsNonZero(int val) { | ||
final int expected = val != 0 ? 1 : 0; | ||
assertEquals(expected, sneaky("isNonZero", val)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("testSingles") | ||
public void testIsZero(int val) { | ||
final int expected = val == 0 ? 1 : 0; | ||
assertEquals(expected, sneaky("isZero", val)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("testSingles") | ||
public void testIsNegative(int val) { | ||
final int expected = val < 0 ? 1 : 0; | ||
assertEquals(expected, sneaky("isNegative", val)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("testPairs") | ||
public void testEqual(int x, int y) { | ||
final int expected = x == y ? 1 : 0; | ||
assertEquals(expected, sneaky("equal", x, y)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("testPairs") | ||
public void testGt(int x, int y) { | ||
final int expected = x > y ? 1 : 0; | ||
assertEquals(expected, sneaky("gt", x, y)); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource("testSingles") | ||
public void testSelect(int selector) { | ||
final int a = 10; | ||
final int b = 11; | ||
final int expected = selector != 0 ? a : b; | ||
assertEquals(expected, sneaky("select", selector, a, b)); | ||
} | ||
|
||
private static int sneaky(String name, int a) { | ||
try { | ||
return TestUtil.sneakyInvoke_int(CONSTANT_TIME_CLASS, name, a); | ||
} catch (final Throwable t) { | ||
throw new AssertionError(t); | ||
} | ||
} | ||
|
||
private static int sneaky(String name, int a, int b) { | ||
try { | ||
return TestUtil.sneakyInvoke_int(CONSTANT_TIME_CLASS, name, a, b); | ||
} catch (final Throwable t) { | ||
throw new AssertionError(t); | ||
} | ||
} | ||
|
||
private static int sneaky(String name, int a, int b, int c) { | ||
try { | ||
return TestUtil.sneakyInvoke_int(CONSTANT_TIME_CLASS, name, a, b, c); | ||
} catch (final Throwable t) { | ||
throw new AssertionError(t); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters