From 4a8df17311f2e937840f71b3c1590bbe06fe2393 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Mon, 1 Oct 2018 11:04:59 +0200 Subject: Fix auth when upgrading from SCRAM-SHA-1 to -256 --- .../messenger/crypto/sasl/ScramMechanism.java | 104 ++++++++++----------- 1 file changed, 52 insertions(+), 52 deletions(-) (limited to 'src/main/java/de/pixart') diff --git a/src/main/java/de/pixart/messenger/crypto/sasl/ScramMechanism.java b/src/main/java/de/pixart/messenger/crypto/sasl/ScramMechanism.java index 046b68fda..a7a063409 100644 --- a/src/main/java/de/pixart/messenger/crypto/sasl/ScramMechanism.java +++ b/src/main/java/de/pixart/messenger/crypto/sasl/ScramMechanism.java @@ -22,28 +22,16 @@ import de.pixart.messenger.xml.TagWriter; abstract class ScramMechanism extends SaslMechanism { // TODO: When channel binding (SCRAM-SHA1-PLUS) is supported in future, generalize this to indicate support and/or usage. private final static String GS2_HEADER = "n,,"; - private String clientFirstMessageBare; - private final String clientNonce; - private byte[] serverSignature = null; - static HMac HMAC; - static Digest DIGEST; private static final byte[] CLIENT_KEY_BYTES = "Client Key".getBytes(); private static final byte[] SERVER_KEY_BYTES = "Server Key".getBytes(); - - private static class KeyPair { - final byte[] clientKey; - final byte[] serverKey; - - KeyPair(final byte[] clientKey, final byte[] serverKey) { - this.clientKey = clientKey; - this.serverKey = serverKey; - } - } + private static final LruCache CACHE; + static HMac HMAC; + static Digest DIGEST; static { CACHE = new LruCache(10) { protected KeyPair create(final String k) { - // Map keys are "bytesToHex(JID),bytesToHex(password),bytesToHex(salt),iterations". + // Map keys are "bytesToHex(JID),bytesToHex(password),bytesToHex(salt),iterations,SASL-Mechanism". // Changing any of these values forces a cache miss. `CryptoHelper.bytesToHex()' // is applied to prevent commas in the strings breaking things. final String[] kparts = k.split(",", 4); @@ -62,9 +50,10 @@ abstract class ScramMechanism extends SaslMechanism { }; } - private static final LruCache CACHE; - + private final String clientNonce; protected State state = State.INITIAL; + private String clientFirstMessageBare; + private byte[] serverSignature = null; ScramMechanism(final TagWriter tagWriter, final Account account, final SecureRandom rng) { super(tagWriter, account, rng); @@ -74,6 +63,41 @@ abstract class ScramMechanism extends SaslMechanism { clientFirstMessageBare = ""; } + private static synchronized byte[] hmac(final byte[] key, final byte[] input) + throws InvalidKeyException { + HMAC.init(new KeyParameter(key)); + HMAC.update(input, 0, input.length); + final byte[] out = new byte[HMAC.getMacSize()]; + HMAC.doFinal(out, 0); + return out; + } + + public static synchronized byte[] digest(byte[] bytes) { + DIGEST.reset(); + DIGEST.update(bytes, 0, bytes.length); + final byte[] out = new byte[DIGEST.getDigestSize()]; + DIGEST.doFinal(out, 0); + return out; + } + + /* + * Hi() is, essentially, PBKDF2 [RFC2898] with HMAC() as the + * pseudorandom function (PRF) and with dkLen == output length of + * HMAC() == output length of H(). + */ + private static synchronized byte[] hi(final byte[] key, final byte[] salt, final int iterations) + throws InvalidKeyException { + byte[] u = hmac(key, CryptoHelper.concatenateByteArrays(salt, CryptoHelper.ONE)); + byte[] out = u.clone(); + for (int i = 1; i < iterations; i++) { + u = hmac(key, u); + for (int j = 0; j < u.length; j++) { + out[j] ^= u[j]; + } + } + return out; + } + @Override public String getClientFirstMessage() { if (clientFirstMessageBare.isEmpty() && state == State.INITIAL) { @@ -120,7 +144,7 @@ abstract class ScramMechanism extends SaslMechanism { nonce = token.substring(2); break; case 'm': - /* + /* * RFC 5802: * m: This attribute is reserved for future extensibility. In this * version of SCRAM, its presence in a client or a server message @@ -147,12 +171,13 @@ abstract class ScramMechanism extends SaslMechanism { final byte[] authMessage = (clientFirstMessageBare + ',' + new String(serverFirstMessage) + ',' + clientFinalMessageWithoutProof).getBytes(); - // Map keys are "bytesToHex(JID),bytesToHex(password),bytesToHex(salt),iterations". + // Map keys are "bytesToHex(JID),bytesToHex(password),bytesToHex(salt),iterations,SASL-Mechanism". final KeyPair keys = CACHE.get( CryptoHelper.bytesToHex(account.getJid().asBareJid().toString().getBytes()) + "," + CryptoHelper.bytesToHex(account.getPassword().getBytes()) + "," + CryptoHelper.bytesToHex(salt.getBytes()) + "," + String.valueOf(iterationCount) + + getMechanism() ); if (keys == null) { throw new AuthenticationException("Invalid keys generated"); @@ -188,7 +213,7 @@ abstract class ScramMechanism extends SaslMechanism { } state = State.VALID_SERVER_RESPONSE; return ""; - } catch(Exception e) { + } catch (Exception e) { throw new AuthenticationException("Server final message does not match calculated final message"); } default: @@ -196,38 +221,13 @@ abstract class ScramMechanism extends SaslMechanism { } } - private static synchronized byte[] hmac(final byte[] key, final byte[] input) - throws InvalidKeyException { - HMAC.init(new KeyParameter(key)); - HMAC.update(input, 0, input.length); - final byte[] out = new byte[HMAC.getMacSize()]; - HMAC.doFinal(out, 0); - return out; - } - - public static synchronized byte[] digest(byte[] bytes) { - DIGEST.reset(); - DIGEST.update(bytes, 0, bytes.length); - final byte[] out = new byte[DIGEST.getDigestSize()]; - DIGEST.doFinal(out, 0); - return out; - } + private static class KeyPair { + final byte[] clientKey; + final byte[] serverKey; - /* - * Hi() is, essentially, PBKDF2 [RFC2898] with HMAC() as the - * pseudorandom function (PRF) and with dkLen == output length of - * HMAC() == output length of H(). - */ - private static synchronized byte[] hi(final byte[] key, final byte[] salt, final int iterations) - throws InvalidKeyException { - byte[] u = hmac(key, CryptoHelper.concatenateByteArrays(salt, CryptoHelper.ONE)); - byte[] out = u.clone(); - for (int i = 1; i < iterations; i++) { - u = hmac(key, u); - for (int j = 0; j < u.length; j++) { - out[j] ^= u[j]; - } + KeyPair(final byte[] clientKey, final byte[] serverKey) { + this.clientKey = clientKey; + this.serverKey = serverKey; } - return out; } } \ No newline at end of file -- cgit v1.2.3