public string ComputeHash(string password, bool client) { string text, a1, a2; byte[] buf, digest; // compute A1 text = string.Format("{0}:{1}:{2}", UserName, Realm, password); buf = Encoding.UTF8.GetBytes(text); using (var md5 = new MD5()) digest = md5.ComputeHash(buf); using (var md5 = new MD5()) { md5.TransformBlock(digest, 0, digest.Length, null, 0); text = string.Format(":{0}:{1}", Nonce, CNonce); if (!string.IsNullOrEmpty(AuthZid)) { text += ":" + AuthZid; } buf = Encoding.ASCII.GetBytes(text); md5.TransformFinalBlock(buf, 0, buf.Length); a1 = HexEncode(md5.Hash); } // compute A2 text = client ? "AUTHENTICATE:" : ":"; text += DigestUri; if (Qop == "auth-int" || Qop == "auth-conf") { text += ":00000000000000000000000000000000"; } buf = Encoding.ASCII.GetBytes(text); using (var md5 = new MD5()) digest = md5.ComputeHash(buf); a2 = HexEncode(digest); // compute KD text = string.Format("{0}:{1}:{2:x8}:{3}:{4}:{5}", a1, Nonce, Nc, CNonce, Qop, a2); buf = Encoding.ASCII.GetBytes(text); using (var md5 = new MD5()) digest = md5.ComputeHash(buf); return(HexEncode(digest)); }
public string ComputeHash (string password, bool client) { string text, a1, a2; byte[] buf, digest; // compute A1 text = string.Format ("{0}:{1}:{2}", UserName, Realm, password); buf = Encoding.UTF8.GetBytes (text); using (var md5 = new MD5 ()) digest = md5.ComputeHash (buf); using (var md5 = new MD5 ()) { md5.TransformBlock (digest, 0, digest.Length, null, 0); text = string.Format (":{0}:{1}", Nonce, CNonce); if (!string.IsNullOrEmpty (AuthZid)) text += ":" + AuthZid; buf = Encoding.ASCII.GetBytes (text); md5.TransformFinalBlock (buf, 0, buf.Length); a1 = HexEncode (md5.Hash); } // compute A2 text = client ? "AUTHENTICATE:" : ":"; text += DigestUri; if (Qop == "auth-int" || Qop == "auth-conf") text += ":00000000000000000000000000000000"; buf = Encoding.ASCII.GetBytes (text); using (var md5 = new MD5 ()) digest = md5.ComputeHash (buf); a2 = HexEncode (digest); // compute KD text = string.Format ("{0}:{1}:{2:x8}:{3}:{4}:{5}", a1, Nonce, Nc, CNonce, Qop, a2); buf = Encoding.ASCII.GetBytes (text); using (var md5 = new MD5 ()) digest = md5.ComputeHash (buf); return HexEncode (digest); }
/// <summary> /// Parses the server's challenge token and returns the next challenge response. /// </summary> /// <remarks> /// Parses the server's challenge token and returns the next challenge response. /// </remarks> /// <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="System.InvalidOperationException"> /// The SASL mechanism is already authenticated. /// </exception> /// <exception cref="System.NotSupportedException"> /// The SASL mechanism does not support SASL-IR. /// </exception> /// <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) throw new NotSupportedException ("CRAM-MD5 does not support SASL-IR."); var cred = Credentials.GetCredential (Uri, MechanismName); var userName = Encoding.UTF8.GetBytes (cred.UserName); var password = Encoding.UTF8.GetBytes (cred.Password); var ipad = new byte[64]; var opad = new byte[64]; byte[] digest; if (password.Length > 64) { byte[] checksum; using (var md5 = new MD5 ()) 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; } using (var md5 = new MD5 ()) { md5.TransformBlock (ipad, 0, ipad.Length, null, 0); md5.TransformFinalBlock (token, startIndex, length); digest = md5.Hash; } using (var md5 = new MD5 ()) { md5.TransformBlock (opad, 0, opad.Length, null, 0); md5.TransformFinalBlock (digest, 0, digest.Length); digest = md5.Hash; } var buffer = new byte[userName.Length + 1 + (digest.Length * 2)]; int 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; }
/// <summary> /// Parses the server's challenge token and returns the next challenge response. /// </summary> /// <remarks> /// Parses the server's challenge token and returns the next challenge response. /// </remarks> /// <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="System.InvalidOperationException"> /// The SASL mechanism is already authenticated. /// </exception> /// <exception cref="System.NotSupportedException"> /// THe SASL mechanism does not support SASL-IR. /// </exception> /// <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) { throw new NotSupportedException("CRAM-MD5 does not support SASL-IR."); } var cred = Credentials.GetCredential(Uri, MechanismName); var userName = Encoding.UTF8.GetBytes(cred.UserName); var password = Encoding.UTF8.GetBytes(cred.Password); var ipad = new byte[64]; var opad = new byte[64]; byte[] digest; if (password.Length > 64) { byte[] checksum; using (var md5 = new MD5()) 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; } using (var md5 = new MD5()) { md5.TransformBlock(ipad, 0, ipad.Length, null, 0); md5.TransformFinalBlock(token, startIndex, length); digest = md5.Hash; } using (var md5 = new MD5()) { md5.TransformBlock(opad, 0, opad.Length, null, 0); md5.TransformFinalBlock(digest, 0, digest.Length); digest = md5.Hash; } var buffer = new byte[userName.Length + 1 + (digest.Length * 2)]; int 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); }