On 09.12.2005 10:40 (+0100), Vinod Panicker wrote:
> What are you using as your SASL implementation?

SASL, mechanism DIGEST-MD5, code: my own.

I was pointed to the example at the end of the SASL RFC, so I tried to
get to the same results, and I didn't. I have attached my code with some
comments on how to use it and what results I had.

-- 
Yves Goergen "LonelyPixel" <[EMAIL PROTECTED]>
"Does the movement of the trees make the wind blow?"
http://newsboard.unclassified.de - Unclassified NewsBoard Forum
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

// SASL specification: ftp://ietf.org//rfc/rfc2831.txt
//
// Demo usage of this class:
//
// XMPP.Sasl sasl = new XMPP.Sasl();
// sasl.Hostname = "elwood.innosoft.com";
// sasl.Mechanism = "DIGEST-MD5";
// sasl.Password = "secret";
// sasl.Username = "chris";
// string challenge = 
@"realm=""elwood.innosoft.com"",nonce=""OA6MG9tEQGm2hh"",qop=""auth""" +
//    ",algorithm=md5-sess,charset=utf-8";
// string response = sasl.GetResponse(challenge);

namespace XMPP
{
        public class Sasl
        {
                public string Hostname = "";
                public string Username = "";
                public string Password = "";
                public string Mechanism = "";
                
                public string GetResponse(string challenge)
                {
                        Regex r;
                        Match m;
                        string realm = "";
                        string nonce = "";
                        string qop = "auth";
                        string algorithm = "";

                        r = new Regex(@"realm=""(.*?)(?<!\\)""");
                        m = r.Match(challenge);
                        if (m.Success)
                                realm = m.Groups[1].Value;

                        r = new Regex(@"nonce=""(.*?)(?<!\\)""");
                        m = r.Match(challenge);
                        if (!m.Success)
                                throw new 
System.Security.Authentication.AuthenticationException("Invalid SASL protocol");
                        nonce  = m.Groups[1].Value;

                        r = new Regex(@"qop=""(.*?)(?<!\\)""");
                        m = r.Match(challenge);
                        if (m.Success)
                                qop = m.Groups[1].Value;
                        if (qop != "auth")
                                throw new 
System.Security.Authentication.AuthenticationException("Unsupported SASL 
protocol use");

                        r = new Regex(@"algorithm=(.*?)(?=,|$)");
                        m = r.Match(challenge);
                        if (!m.Success)
                                throw new 
System.Security.Authentication.AuthenticationException("Invalid SASL protocol");
                        algorithm = m.Groups[1].Value;

                        RandomNumberGenerator rng = 
RandomNumberGenerator.Create();
                        byte[] bytes = new byte[32];
                        rng.GetBytes(bytes);
                        string cnonce = HEX(bytes);
                        cnonce = "OA6MHXh6VqTrRk";   // for testing

                        string nonce_count = "00000001";
                        
                        string A1 = BytesToString(H(ToUTF8(Username) + ":" + 
realm + ":" + ToUTF8(Password))) +
                                ":" + nonce + ":" + cnonce;
                        string A2 = "AUTHENTICATE:xmpp/" + Hostname;

                        //A1 = "a2549853149b0536f01f0b850c643c57"; // for 
testing -> this produces still no correct response
                        A2 = "AUTHENTICATE:imap/" + Hostname;   // for testing

                        string response = HEX(KD(
                                HEX(H(A1)),
                                nonce + ":" + nonce_count + ":" + cnonce + ":" 
+ qop + ":" + HEX(H(A2))));

                        // for testing:
                        string HA1 = HEX(H(A1));
                        string HA2 = HEX(H(A2));
                        // my HA1:           b797a8d5eeae5f17625ca975f6a8dc2f
                        // my response:      db4446e7eedfff854d71882b0266eb80
                        
                        // correct HA1:      a2549853149b0536f01f0b850c643c57
                        // correct response: d388dad90d4bbd760a152321f2143af7

                        if (realm != "") realm = @"realm=""" + realm + @""",";
                        string ret = realm + "username=\"" + ToUTF8(Username) + 
"\",nonce=\"" + nonce + "\",cnonce=\"" +
                                cnonce + "\",nc=00000001,qop=" + qop + 
",digest-uri=\"xmpp/" + Hostname + "\",response=" +
                                response + ",charset=utf-8";

                        return ret;
                }

                private byte[] H(string s)
                {
                        MD5 md5 = new MD5CryptoServiceProvider();
                        byte[] bytes = Encoding.UTF8.GetBytes(s);
                        bytes = md5.ComputeHash(bytes);
                        return bytes;
                        // TODO: optimise after debugging
                }

                private string BytesToString(byte[] bytes)
                {
                        return Encoding.GetEncoding(28591).GetString(bytes);
                }

                private byte[] KD(string k, string s)
                {
                        return H(k + ":" + s);
                }

                private string HEX(byte[] n)
                {
                        string hex = "";
                        foreach (byte b in n)
                                hex += b.ToString("x2");
                        return hex;
                }

                private string ToUTF8(string data)
                {
                        // Codepage 28591 is ISO-8859-1
                        return 
Encoding.GetEncoding(28591).GetString(Encoding.UTF8.GetBytes(data));
                }
        }
}

Reply via email to