diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java index 3a8f96a4a82f4fcd2ecb296af0c1f218bd56c80f..e80b259cfc7e2ef496e84f137c311f1661084133 100644 --- a/core/java/src/net/i2p/crypto/HMACGenerator.java +++ b/core/java/src/net/i2p/crypto/HMACGenerator.java @@ -109,7 +109,7 @@ public class HMACGenerator { mac.doFinal(rv, 0); release(mac); - boolean eq = DataHelper.eq(rv, 0, origMAC, origMACOffset, origMACLength); + boolean eq = DataHelper.eqCT(rv, 0, origMAC, origMACOffset, origMACLength); releaseTmp(rv); return eq; } diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 12b17832913fe2d6fa21c608936991a62921bd3e..9c9cfc27cbc2094bb333518e4015a346a11e00f6 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -983,6 +983,8 @@ public class DataHelper { * This treats (null == null) as true, (null == (!null)) as false, * and unequal length arrays as false. * + * Variable time. + * * @return Arrays.equals(lhs, rhs) */ public final static boolean eq(byte lhs[], byte rhs[]) { @@ -1018,22 +1020,40 @@ public class DataHelper { /** * Unlike eq(byte[], byte[]), this returns false if either lhs or rhs is null. - * @throws AIOOBE if either array isn't long enough + * Variable time. + * + * @throws ArrayIndexOutOfBoundsException if either array isn't long enough */ public final static boolean eq(byte lhs[], int offsetLeft, byte rhs[], int offsetRight, int length) { if ( (lhs == null) || (rhs == null) ) return false; - if (length <= 0) return true; for (int i = 0; i < length; i++) { if (lhs[offsetLeft + i] != rhs[offsetRight + i]) return false; } return true; } + + /** + * Unlike eq(), this throws NPE if either lhs or rhs is null. + * Constant time. + * + * @throws NullPointerException if lhs or rhs is null + * @throws ArrayIndexOutOfBoundsException if either array isn't long enough + * @since 0.9.13 + */ + public final static boolean eqCT(byte lhs[], int offsetLeft, byte rhs[], int offsetRight, int length) { + int r = 0; + for (int i = 0; i < length; i++) { + r |= lhs[offsetLeft + i] ^ rhs[offsetRight + i]; + } + return r == 0; + } /** * Big endian compare, treats bytes as unsigned. * Shorter arg is lesser. * Args may be null, null is less than non-null. + * Variable time. */ public final static int compareTo(byte lhs[], byte rhs[]) { if ((rhs == null) && (lhs == null)) return 0;