DigestMd5.java

 1package eu.siacs.conversations.crypto.sasl;
 2
 3import android.util.Base64;
 4
 5import java.math.BigInteger;
 6import java.nio.charset.Charset;
 7import java.security.MessageDigest;
 8import java.security.NoSuchAlgorithmException;
 9import java.security.SecureRandom;
10
11import eu.siacs.conversations.entities.Account;
12import eu.siacs.conversations.utils.CryptoHelper;
13import eu.siacs.conversations.xml.TagWriter;
14
15public class DigestMd5 extends SaslMechanism {
16    public DigestMd5(final TagWriter tagWriter, final Account account, final SecureRandom rng) {
17        super(tagWriter, account, rng);
18    }
19
20    @Override
21    public String getMechanism() {
22        return "DIGEST-MD5";
23    }
24
25    @Override
26    public String getResponse(final String challenge) {
27        final String encodedResponse;
28        try {
29            final String[] challengeParts = new String(Base64.decode(challenge,
30                    Base64.DEFAULT)).split(",");
31            String nonce = "";
32            for (int i = 0; i < challengeParts.length; ++i) {
33                String[] parts = challengeParts[i].split("=");
34                if (parts[0].equals("nonce")) {
35                    nonce = parts[1].replace("\"", "");
36                } else if (parts[0].equals("rspauth")) {
37                    return "";
38                }
39            }
40            final String digestUri = "xmpp/" + account.getServer();
41            final String nonceCount = "00000001";
42            final String x = account.getUsername() + ":" + account.getServer() + ":"
43                    + account.getPassword();
44            final MessageDigest md = MessageDigest.getInstance("MD5");
45            final byte[] y = md.digest(x.getBytes(Charset.defaultCharset()));
46            final String cNonce = new BigInteger(100, rng).toString(32);
47            final byte[] a1 = CryptoHelper.concatenateByteArrays(y,
48                    (":" + nonce + ":" + cNonce).getBytes(Charset
49                            .defaultCharset()));
50            final String a2 = "AUTHENTICATE:" + digestUri;
51            final String ha1 = CryptoHelper.bytesToHex(md.digest(a1));
52            final String ha2 = CryptoHelper.bytesToHex(md.digest(a2.getBytes(Charset
53                    .defaultCharset())));
54            final String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce
55                    + ":auth:" + ha2;
56            final String response = CryptoHelper.bytesToHex(md.digest(kd.getBytes(Charset
57                    .defaultCharset())));
58            final String saslString = "username=\"" + account.getUsername()
59                    + "\",realm=\"" + account.getServer() + "\",nonce=\""
60                    + nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount
61                    + ",qop=auth,digest-uri=\"" + digestUri + "\",response="
62                    + response + ",charset=utf-8";
63            encodedResponse = Base64.encodeToString(
64                    saslString.getBytes(Charset.defaultCharset()),
65                    Base64.NO_WRAP);
66        } catch (final NoSuchAlgorithmException e) {
67            return "";
68        }
69
70        return encodedResponse;
71    }
72}