public static async Task <string> GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse) { StringBuilder sb = StringBuilderCache.Acquire(); // It is mandatory for servers to implement sha-256 per RFC 7616 // Keep MD5 for backward compatibility. string algorithm; if (digestResponse.Parameters.TryGetValue(Algorithm, out algorithm)) { if (algorithm != Sha256 && algorithm != Md5 && algorithm != Sha256Sess && algorithm != MD5Sess) { return(null); } } else { algorithm = Md5; } // Check if nonce is there in challenge string nonce; if (!digestResponse.Parameters.TryGetValue(Nonce, out nonce)) { return(null); } // opaque token may or may not exist string opaque; digestResponse.Parameters.TryGetValue(Opaque, out opaque); string realm; if (!digestResponse.Parameters.TryGetValue(Realm, out realm)) { return(null); } // Add username string userhash; if (digestResponse.Parameters.TryGetValue(UserHash, out userhash) && userhash == "true") { sb.AppendKeyValue(Username, ComputeHash(credential.UserName + ":" + realm, algorithm)); sb.AppendKeyValue(UserHash, userhash, includeQuotes: false); } else { string usernameStar; if (HeaderUtilities.IsInputEncoded5987(credential.UserName, out usernameStar)) { sb.AppendKeyValue(UsernameStar, usernameStar, includeQuotes: false); } else { sb.AppendKeyValue(Username, credential.UserName); } } // Add realm if (realm != string.Empty) { sb.AppendKeyValue(Realm, realm); } // Add nonce sb.AppendKeyValue(Nonce, nonce); // Add uri sb.AppendKeyValue(Uri, request.RequestUri.PathAndQuery); // Set qop, default is auth string qop = Auth; if (digestResponse.Parameters.ContainsKey(Qop)) { // Check if auth-int present in qop string int index1 = digestResponse.Parameters[Qop].IndexOf(AuthInt); if (index1 != -1) { // Get index of auth if present in qop string int index2 = digestResponse.Parameters[Qop].IndexOf(Auth); // If index2 < index1, auth option is available // If index2 == index1, check if auth option available later in string after auth-int. if (index2 == index1) { index2 = digestResponse.Parameters[Qop].IndexOf(Auth, index1 + AuthInt.Length); if (index2 == -1) { qop = AuthInt; } } } } // Set cnonce string cnonce = GetRandomAlphaNumericString(); // Calculate response string a1 = credential.UserName + ":" + realm + ":" + credential.Password; if (algorithm == Sha256Sess || algorithm == MD5Sess) { algorithm = algorithm == Sha256Sess ? Sha256 : Md5; a1 = ComputeHash(a1, algorithm) + ":" + nonce + ":" + cnonce; } string a2 = request.Method.Method + ":" + request.RequestUri.PathAndQuery; if (qop == AuthInt) { string content = request.Content == null ? string.Empty : await request.Content.ReadAsStringAsync().ConfigureAwait(false); a2 = a2 + ":" + ComputeHash(content, algorithm); } string response = ComputeHash(ComputeHash(a1, algorithm) + ":" + nonce + ":" + DigestResponse.NonceCount + ":" + cnonce + ":" + qop + ":" + ComputeHash(a2, algorithm), algorithm); // Add response sb.AppendKeyValue(Response, response); // Add algorithm sb.AppendKeyValue(Algorithm, algorithm, includeQuotes: false); // Add opaque if (opaque != null) { sb.AppendKeyValue(Opaque, opaque); } // Add qop sb.AppendKeyValue(Qop, qop, includeQuotes: false); // Add nc sb.AppendKeyValue(NC, DigestResponse.NonceCount, includeQuotes: false); // Add cnonce sb.AppendKeyValue(CNonce, cnonce, includeComma: false); return(StringBuilderCache.GetStringAndRelease(sb)); }