From 14cfb60952402a25cad6681552daed657cde8237 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Wed, 12 Nov 2014 10:15:38 -0500 Subject: Refactor authentication code --- .../siacs/conversations/crypto/sasl/DigestMd5.java | 72 ++++++++++++++++++++++ .../eu/siacs/conversations/crypto/sasl/Plain.java | 25 ++++++++ .../conversations/crypto/sasl/SaslMechanism.java | 27 ++++++++ 3 files changed, 124 insertions(+) create mode 100644 src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java create mode 100644 src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java create mode 100644 src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java (limited to 'src/main/java/eu/siacs/conversations/crypto') diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java new file mode 100644 index 00000000..f81bd0c5 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/DigestMd5.java @@ -0,0 +1,72 @@ +package eu.siacs.conversations.crypto.sasl; + +import android.util.Base64; + +import java.math.BigInteger; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.xml.TagWriter; + +public class DigestMd5 extends SaslMechanism { + public DigestMd5(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + super(tagWriter, account, rng); + } + + @Override + public String getMechanism() { + return "DIGEST-MD5"; + } + + @Override + public String getResponse(final String challenge) { + final String encodedResponse; + try { + final String[] challengeParts = new String(Base64.decode(challenge, + Base64.DEFAULT)).split(","); + String nonce = ""; + for (int i = 0; i < challengeParts.length; ++i) { + String[] parts = challengeParts[i].split("="); + if (parts[0].equals("nonce")) { + nonce = parts[1].replace("\"", ""); + } else if (parts[0].equals("rspauth")) { + return ""; + } + } + final String digestUri = "xmpp/" + account.getServer(); + final String nonceCount = "00000001"; + final String x = account.getUsername() + ":" + account.getServer() + ":" + + account.getPassword(); + final MessageDigest md = MessageDigest.getInstance("MD5"); + final byte[] y = md.digest(x.getBytes(Charset.defaultCharset())); + final String cNonce = new BigInteger(100, rng).toString(32); + final byte[] a1 = CryptoHelper.concatenateByteArrays(y, + (":" + nonce + ":" + cNonce).getBytes(Charset + .defaultCharset())); + final String a2 = "AUTHENTICATE:" + digestUri; + final String ha1 = CryptoHelper.bytesToHex(md.digest(a1)); + final String ha2 = CryptoHelper.bytesToHex(md.digest(a2.getBytes(Charset + .defaultCharset()))); + final String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce + + ":auth:" + ha2; + final String response = CryptoHelper.bytesToHex(md.digest(kd.getBytes(Charset + .defaultCharset()))); + final String saslString = "username=\"" + account.getUsername() + + "\",realm=\"" + account.getServer() + "\",nonce=\"" + + nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount + + ",qop=auth,digest-uri=\"" + digestUri + "\",response=" + + response + ",charset=utf-8"; + encodedResponse = Base64.encodeToString( + saslString.getBytes(Charset.defaultCharset()), + Base64.NO_WRAP); + } catch (final NoSuchAlgorithmException e) { + return ""; + } + + return encodedResponse; + } +} diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java b/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java new file mode 100644 index 00000000..e7760bbc --- /dev/null +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/Plain.java @@ -0,0 +1,25 @@ +package eu.siacs.conversations.crypto.sasl; + +import android.util.Base64; + +import java.nio.charset.Charset; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.xml.TagWriter; + +public class Plain extends SaslMechanism { + public Plain(final TagWriter tagWriter, final Account account) { + super(tagWriter, account, null); + } + + @Override + public String getMechanism() { + return "PLAIN"; + } + + @Override + public String getStartAuth() { + final String sasl = '\u0000' + account.getUsername() + '\u0000' + account.getPassword(); + return Base64.encodeToString(sasl.getBytes(Charset.defaultCharset()), Base64.NO_WRAP); + } +} diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java new file mode 100644 index 00000000..5eddd5c2 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/SaslMechanism.java @@ -0,0 +1,27 @@ +package eu.siacs.conversations.crypto.sasl; + +import java.security.SecureRandom; + +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.xml.TagWriter; + +public abstract class SaslMechanism { + + final protected TagWriter tagWriter; + final protected Account account; + final protected SecureRandom rng; + + public SaslMechanism(final TagWriter tagWriter, final Account account, final SecureRandom rng) { + this.tagWriter = tagWriter; + this.account = account; + this.rng = rng; + } + + public abstract String getMechanism(); + public String getStartAuth() { + return ""; + } + public String getResponse(final String challenge) { + return ""; + } +} -- cgit v1.2.3