public string ComputeHash(string password, bool client)
        {
            using (var checksum = new MD5 ()) {
                byte[] buf, digest;
                string text, a1, a2;

                // compute A1
                text = string.Format ("{0}:{1}:{2}", UserName, Realm, password);
                buf = Encoding.UTF8.GetBytes (text);
                checksum.Initialize ();
                digest = checksum.ComputeHash (buf);

                text = string.Format ("{0}:{1}:{2}", HexEncode (digest), Nonce, CNonce);
                buf = Encoding.UTF8.GetBytes (text);
                checksum.Initialize ();
                digest = checksum.ComputeHash (buf);
                a1 = HexEncode (digest);

                // compute A2
                text = client ? "AUTHENTICATE:" : ":";
                text += DigestUri;

                if (Qop == "auth-int" || Qop == "auth-conf")
                    text += ":00000000000000000000000000000000";

                buf = Encoding.ASCII.GetBytes (text);
                checksum.Initialize ();
                digest = checksum.ComputeHash (buf);
                a2 = HexEncode (digest);

                // compute KD
                text = string.Format ("{0}:{1}:{2:8X}:{3}:{4}:{5}", a1, Nonce, Nc, CNonce, Qop, a2);
                buf = Encoding.ASCII.GetBytes (text);
                checksum.Initialize ();
                digest = checksum.ComputeHash (buf);

                return HexEncode (digest);
            }
        }
예제 #2
0
        /// <summary>
        /// Parses the server's challenge token and returns the next challenge response.
        /// </summary>
        /// <returns>The next challenge response.</returns>
        /// <param name="token">The server's challenge token.</param>
        /// <param name="startIndex">The index into the token specifying where the server's challenge begins.</param>
        /// <param name="length">The length of the server's challenge.</param>
        /// <exception cref="SaslException">
        /// An error has occurred while parsing the server's challenge token.
        /// </exception>
        protected override byte[] Challenge(byte[] token, int startIndex, int length)
        {
            if (IsAuthenticated)
                throw new InvalidOperationException ();

            if (token == null)
                return null;

            var cred = Credentials.GetCredential (Uri, MechanismName);
            var userName = Encoding.UTF8.GetBytes (cred.UserName);
            var password = Encoding.UTF8.GetBytes (cred.Password);

            using (var md5 = new MD5 ()) {
                var ipad = new byte[64];
                var opad = new byte[64];
                byte[] buffer;
                byte[] digest;
                int offset;

                if (password.Length > 64) {
                    var checksum = md5.ComputeHash (password);
                    Array.Copy (checksum, ipad, checksum.Length);
                    Array.Copy (checksum, opad, checksum.Length);
                } else {
                    Array.Copy (password, ipad, password.Length);
                    Array.Copy (password, opad, password.Length);
                }

                for (int i = 0; i < 64; i++) {
                    ipad[i] ^= 0x36;
                    opad[i] ^= 0x5c;
                }

                buffer = new byte[ipad.Length + length];
                offset = 0;

                for (int i = 0; i < ipad.Length; i++)
                    buffer[offset++] = ipad[i];
                for (int i = 0; i < length; i++)
                    buffer[offset++] = token[startIndex + i];

                md5.Initialize ();
                digest = md5.ComputeHash (buffer);

                buffer = new byte[opad.Length + digest.Length];
                offset = 0;

                for (int i = 0; i < opad.Length; i++)
                    buffer[offset++] = opad[i];
                for (int i = 0; i < digest.Length; i++)
                    buffer[offset++] = digest[i];

                md5.Initialize ();
                digest = md5.ComputeHash (buffer);

                buffer = new byte[userName.Length + 1 + (digest.Length * 2)];
                offset = 0;

                for (int i = 0; i < userName.Length; i++)
                    buffer[offset++] = userName[i];
                buffer[offset++] = 0x20;
                for (int i = 0; i < digest.Length; i++) {
                    byte c = digest[i];

                    buffer[offset++] = HexAlphabet[(c >> 4) & 0x0f];
                    buffer[offset++] = HexAlphabet[c & 0x0f];
                }

                IsAuthenticated = true;

                return buffer;
            }
        }