mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-26 22:32:07 +01:00
Make Passphrase comparison constant time
This commit is contained in:
parent
729b33a116
commit
176ad09d19
3 changed files with 57 additions and 1 deletions
|
@ -47,4 +47,41 @@ public final class BCUtil {
|
|||
return bitStrength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A constant time equals comparison - does not terminate early if
|
||||
* test will fail. For best results always pass the expected value
|
||||
* as the first parameter.
|
||||
*
|
||||
* @param expected first array
|
||||
* @param supplied second array
|
||||
* @return true if arrays equal, false otherwise.
|
||||
*/
|
||||
public static boolean constantTimeAreEqual(
|
||||
char[] expected,
|
||||
char[] supplied) {
|
||||
if (expected == null || supplied == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected == supplied) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int len = (expected.length < supplied.length) ? expected.length : supplied.length;
|
||||
|
||||
int nonEqual = expected.length ^ supplied.length;
|
||||
|
||||
// do the char-wise comparison
|
||||
for (int i = 0; i != len; i++) {
|
||||
nonEqual |= (expected[i] ^ supplied[i]);
|
||||
}
|
||||
// If supplied is longer than expected, iterate over rest of supplied with NOPs
|
||||
for (int i = len; i < supplied.length; i++) {
|
||||
nonEqual |= ((byte) supplied[i] ^ (byte) ~supplied[i]);
|
||||
}
|
||||
|
||||
return nonEqual == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import javax.annotation.Nonnull;
|
|||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.pgpainless.util.BCUtil.constantTimeAreEqual;
|
||||
|
||||
public class Passphrase {
|
||||
|
||||
public final Object lock = new Object();
|
||||
|
@ -162,6 +164,7 @@ public class Passphrase {
|
|||
return false;
|
||||
}
|
||||
Passphrase other = (Passphrase) obj;
|
||||
return Arrays.equals(getChars(), other.getChars());
|
||||
return (getChars() == null && other.getChars() == null) ||
|
||||
constantTimeAreEqual(getChars(), other.getChars());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
package org.pgpainless.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
|
@ -88,4 +90,18 @@ public class BCUtilTest {
|
|||
|
||||
assertEquals(pubColSize, secColSize);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constantTimeAreEqualsTest() {
|
||||
char[] b = "Hello".toCharArray();
|
||||
assertTrue(BCUtil.constantTimeAreEqual(b, b));
|
||||
assertTrue(BCUtil.constantTimeAreEqual("Hello".toCharArray(), "Hello".toCharArray()));
|
||||
assertTrue(BCUtil.constantTimeAreEqual(new char[0], new char[0]));
|
||||
assertTrue(BCUtil.constantTimeAreEqual(new char[] {'H', 'e', 'l', 'l', 'o'}, "Hello".toCharArray()));
|
||||
|
||||
assertFalse(BCUtil.constantTimeAreEqual("Hello".toCharArray(), "Hello World".toCharArray()));
|
||||
assertFalse(BCUtil.constantTimeAreEqual(null, "Hello".toCharArray()));
|
||||
assertFalse(BCUtil.constantTimeAreEqual("Hello".toCharArray(), null));
|
||||
assertFalse(BCUtil.constantTimeAreEqual(null, null));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue