From a014918c0d5fde9d03b30fa190b64cb9d748bce8 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Wed, 7 May 2014 14:47:15 +0000 Subject: [PATCH] Transports: Use constant time method for HMAC verification --- .../src/net/i2p/crypto/HMACGenerator.java | 2 +- core/java/src/net/i2p/data/DataHelper.java | 24 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java index 3a8f96a4a8..e80b259cfc 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 12b1783291..9c9cfc27cb 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; -- GitLab