SCRAM remove cache. made digest and hmac non static
DIGEST and HMAC were static variables. Those are initialized by what ever concrete implementation gets executed first. (Perform SCRAM-SHA1 first and those variables got initialized with SHA1 variants) For subsequent SHA256 executions those variables contained wrong values.
This commit is contained in:
		
							parent
							
								
									f23016c967
								
							
						
					
					
						commit
						692ee6c9fb
					
				@ -3,13 +3,11 @@ package eu.siacs.conversations.crypto.sasl;
 | 
				
			|||||||
import android.annotation.TargetApi;
 | 
					import android.annotation.TargetApi;
 | 
				
			||||||
import android.os.Build;
 | 
					import android.os.Build;
 | 
				
			||||||
import android.util.Base64;
 | 
					import android.util.Base64;
 | 
				
			||||||
import android.util.LruCache;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.bouncycastle.crypto.Digest;
 | 
					import org.bouncycastle.crypto.Digest;
 | 
				
			||||||
import org.bouncycastle.crypto.macs.HMac;
 | 
					import org.bouncycastle.crypto.macs.HMac;
 | 
				
			||||||
import org.bouncycastle.crypto.params.KeyParameter;
 | 
					import org.bouncycastle.crypto.params.KeyParameter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.math.BigInteger;
 | 
					 | 
				
			||||||
import java.nio.charset.Charset;
 | 
					import java.nio.charset.Charset;
 | 
				
			||||||
import java.security.InvalidKeyException;
 | 
					import java.security.InvalidKeyException;
 | 
				
			||||||
import java.security.SecureRandom;
 | 
					import java.security.SecureRandom;
 | 
				
			||||||
@ -24,30 +22,22 @@ abstract class ScramMechanism extends SaslMechanism {
 | 
				
			|||||||
    private final static String GS2_HEADER = "n,,";
 | 
					    private final static String GS2_HEADER = "n,,";
 | 
				
			||||||
    private static final byte[] CLIENT_KEY_BYTES = "Client Key".getBytes();
 | 
					    private static final byte[] CLIENT_KEY_BYTES = "Client Key".getBytes();
 | 
				
			||||||
    private static final byte[] SERVER_KEY_BYTES = "Server Key".getBytes();
 | 
					    private static final byte[] SERVER_KEY_BYTES = "Server Key".getBytes();
 | 
				
			||||||
    private static final LruCache<String, KeyPair> CACHE;
 | 
					 | 
				
			||||||
    static HMac HMAC;
 | 
					 | 
				
			||||||
    static Digest DIGEST;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static {
 | 
					    protected abstract HMac getHMAC();
 | 
				
			||||||
        CACHE = new LruCache<String, KeyPair>(10) {
 | 
					 | 
				
			||||||
            protected KeyPair create(final String k) {
 | 
					 | 
				
			||||||
                // 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(",", 5);
 | 
					 | 
				
			||||||
                try {
 | 
					 | 
				
			||||||
                    final byte[] saltedPassword, serverKey, clientKey;
 | 
					 | 
				
			||||||
                    saltedPassword = hi(CryptoHelper.hexToString(kParts[1]).getBytes(),
 | 
					 | 
				
			||||||
                            Base64.decode(CryptoHelper.hexToString(kParts[2]), Base64.DEFAULT), Integer.parseInt(kParts[3]));
 | 
					 | 
				
			||||||
                    serverKey = hmac(saltedPassword, SERVER_KEY_BYTES);
 | 
					 | 
				
			||||||
                    clientKey = hmac(saltedPassword, CLIENT_KEY_BYTES);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    return new KeyPair(clientKey, serverKey);
 | 
					    protected abstract Digest getDigest();
 | 
				
			||||||
                } catch (final InvalidKeyException | NumberFormatException e) {
 | 
					
 | 
				
			||||||
                    return null;
 | 
					    private KeyPair getKeyPair(final String password, final String salt, final int iterations) {
 | 
				
			||||||
                }
 | 
					        try {
 | 
				
			||||||
            }
 | 
					            final byte[] saltedPassword, serverKey, clientKey;
 | 
				
			||||||
        };
 | 
					            saltedPassword = hi(password.getBytes(), Base64.decode(salt, Base64.DEFAULT), iterations);
 | 
				
			||||||
 | 
					            serverKey = hmac(saltedPassword, SERVER_KEY_BYTES);
 | 
				
			||||||
 | 
					            clientKey = hmac(saltedPassword, CLIENT_KEY_BYTES);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return new KeyPair(clientKey, serverKey);
 | 
				
			||||||
 | 
					        } catch (final InvalidKeyException | NumberFormatException e) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final String clientNonce;
 | 
					    private final String clientNonce;
 | 
				
			||||||
@ -63,20 +53,21 @@ abstract class ScramMechanism extends SaslMechanism {
 | 
				
			|||||||
        clientFirstMessageBare = "";
 | 
					        clientFirstMessageBare = "";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static synchronized byte[] hmac(final byte[] key, final byte[] input)
 | 
					    private byte[] hmac(final byte[] key, final byte[] input) throws InvalidKeyException {
 | 
				
			||||||
            throws InvalidKeyException {
 | 
					        final HMac hMac = getHMAC();
 | 
				
			||||||
        HMAC.init(new KeyParameter(key));
 | 
					        hMac.init(new KeyParameter(key));
 | 
				
			||||||
        HMAC.update(input, 0, input.length);
 | 
					        hMac.update(input, 0, input.length);
 | 
				
			||||||
        final byte[] out = new byte[HMAC.getMacSize()];
 | 
					        final byte[] out = new byte[hMac.getMacSize()];
 | 
				
			||||||
        HMAC.doFinal(out, 0);
 | 
					        hMac.doFinal(out, 0);
 | 
				
			||||||
        return out;
 | 
					        return out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static synchronized byte[] digest(byte[] bytes) {
 | 
					    public byte[] digest(byte[] bytes) {
 | 
				
			||||||
        DIGEST.reset();
 | 
					        final Digest digest = getDigest();
 | 
				
			||||||
        DIGEST.update(bytes, 0, bytes.length);
 | 
					        digest.reset();
 | 
				
			||||||
        final byte[] out = new byte[DIGEST.getDigestSize()];
 | 
					        digest.update(bytes, 0, bytes.length);
 | 
				
			||||||
        DIGEST.doFinal(out, 0);
 | 
					        final byte[] out = new byte[digest.getDigestSize()];
 | 
				
			||||||
 | 
					        digest.doFinal(out, 0);
 | 
				
			||||||
        return out;
 | 
					        return out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -85,7 +76,7 @@ abstract class ScramMechanism extends SaslMechanism {
 | 
				
			|||||||
     * pseudorandom function (PRF) and with dkLen == output length of
 | 
					     * pseudorandom function (PRF) and with dkLen == output length of
 | 
				
			||||||
     * HMAC() == output length of H().
 | 
					     * HMAC() == output length of H().
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private static synchronized byte[] hi(final byte[] key, final byte[] salt, final int iterations)
 | 
					    private byte[] hi(final byte[] key, final byte[] salt, final int iterations)
 | 
				
			||||||
            throws InvalidKeyException {
 | 
					            throws InvalidKeyException {
 | 
				
			||||||
        byte[] u = hmac(key, CryptoHelper.concatenateByteArrays(salt, CryptoHelper.ONE));
 | 
					        byte[] u = hmac(key, CryptoHelper.concatenateByteArrays(salt, CryptoHelper.ONE));
 | 
				
			||||||
        byte[] out = u.clone();
 | 
					        byte[] out = u.clone();
 | 
				
			||||||
@ -171,14 +162,7 @@ abstract class ScramMechanism extends SaslMechanism {
 | 
				
			|||||||
                final byte[] authMessage = (clientFirstMessageBare + ',' + new String(serverFirstMessage) + ','
 | 
					                final byte[] authMessage = (clientFirstMessageBare + ',' + new String(serverFirstMessage) + ','
 | 
				
			||||||
                        + clientFinalMessageWithoutProof).getBytes();
 | 
					                        + clientFinalMessageWithoutProof).getBytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Map keys are "bytesToHex(JID),bytesToHex(password),bytesToHex(salt),iterations,SASL-Mechanism".
 | 
					                final KeyPair keys = getKeyPair(CryptoHelper.saslPrep(account.getPassword()), salt, iterationCount);
 | 
				
			||||||
                final KeyPair keys = CACHE.get(
 | 
					 | 
				
			||||||
                        CryptoHelper.bytesToHex(CryptoHelper.saslPrep(account.getJid().asBareJid().toEscapedString()).getBytes()) + ","
 | 
					 | 
				
			||||||
                                + CryptoHelper.bytesToHex(CryptoHelper.saslPrep(account.getPassword()).getBytes()) + ","
 | 
					 | 
				
			||||||
                                + CryptoHelper.bytesToHex(salt.getBytes()) + ","
 | 
					 | 
				
			||||||
                                + iterationCount + ","
 | 
					 | 
				
			||||||
                                + getMechanism()
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                if (keys == null) {
 | 
					                if (keys == null) {
 | 
				
			||||||
                    throw new AuthenticationException("Invalid keys generated");
 | 
					                    throw new AuthenticationException("Invalid keys generated");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package eu.siacs.conversations.crypto.sasl;
 | 
					package eu.siacs.conversations.crypto.sasl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bouncycastle.crypto.Digest;
 | 
				
			||||||
import org.bouncycastle.crypto.digests.SHA1Digest;
 | 
					import org.bouncycastle.crypto.digests.SHA1Digest;
 | 
				
			||||||
import org.bouncycastle.crypto.macs.HMac;
 | 
					import org.bouncycastle.crypto.macs.HMac;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,9 +10,15 @@ import eu.siacs.conversations.entities.Account;
 | 
				
			|||||||
import eu.siacs.conversations.xml.TagWriter;
 | 
					import eu.siacs.conversations.xml.TagWriter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ScramSha1 extends ScramMechanism {
 | 
					public class ScramSha1 extends ScramMechanism {
 | 
				
			||||||
	static {
 | 
					
 | 
				
			||||||
		DIGEST = new SHA1Digest();
 | 
						@Override
 | 
				
			||||||
		HMAC = new HMac(new SHA1Digest());
 | 
						protected HMac getHMAC() {
 | 
				
			||||||
 | 
							return  new HMac(new SHA1Digest());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						protected Digest getDigest() {
 | 
				
			||||||
 | 
							return new SHA1Digest();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ScramSha1(final TagWriter tagWriter, final Account account, final SecureRandom rng) {
 | 
						public ScramSha1(final TagWriter tagWriter, final Account account, final SecureRandom rng) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package eu.siacs.conversations.crypto.sasl;
 | 
					package eu.siacs.conversations.crypto.sasl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bouncycastle.crypto.Digest;
 | 
				
			||||||
import org.bouncycastle.crypto.digests.SHA256Digest;
 | 
					import org.bouncycastle.crypto.digests.SHA256Digest;
 | 
				
			||||||
import org.bouncycastle.crypto.macs.HMac;
 | 
					import org.bouncycastle.crypto.macs.HMac;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,9 +10,15 @@ import eu.siacs.conversations.entities.Account;
 | 
				
			|||||||
import eu.siacs.conversations.xml.TagWriter;
 | 
					import eu.siacs.conversations.xml.TagWriter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ScramSha256 extends ScramMechanism {
 | 
					public class ScramSha256 extends ScramMechanism {
 | 
				
			||||||
	static {
 | 
					
 | 
				
			||||||
		DIGEST = new SHA256Digest();
 | 
						@Override
 | 
				
			||||||
		HMAC = new HMac(new SHA256Digest());
 | 
						protected HMac getHMAC() {
 | 
				
			||||||
 | 
							return new HMac(new SHA256Digest());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						protected Digest getDigest() {
 | 
				
			||||||
 | 
							return new SHA256Digest();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ScramSha256(final TagWriter tagWriter, final Account account, final SecureRandom rng) {
 | 
						public ScramSha256(final TagWriter tagWriter, final Account account, final SecureRandom rng) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user