/// <summary> /// Returns the SHA256 HMAC of the given <paramref name="prefix"/> (if non-<see langword="null"/>) followed by /// the given <paramref name="request"/>'s body. /// </summary> /// <param name="request">The current <see cref="HttpRequest"/>.</param> /// <param name="secret">The key data used to initialize the <see cref="HMACSHA256"/>.</param> /// <param name="prefix">If non-<see langword="null"/>, additional <c>byte</c>s to include in the hash.</param> /// <returns> /// A <see cref="Task"/> that on completion provides a <see cref="byte"/> array containing the SHA256 HMAC of /// the <paramref name="prefix"/> followed by the <paramref name="request"/>'s body. /// </returns> protected virtual async Task <byte[]> GetRequestBodyHash_SHA256( HttpRequest request, byte[] secret, byte[] prefix) { await WebHookHttpRequestUtilities.PrepareRequestBody(request); using (var hasher = new HMACSHA256(secret)) { try { if (prefix != null && prefix.Length > 0) { hasher.TransformBlock( inputBuffer: prefix, inputOffset: 0, inputCount: prefix.Length, outputBuffer: null, outputOffset: 0); } var hash = hasher.ComputeHash(request.Body); return(hash); } finally { // Reset Position because JsonInputFormatter et cetera always start from current position. request.Body.Seek(0L, SeekOrigin.Begin); } } }
/// <inheritdoc /> public async Task <IFormCollection> ReadAsFormDataAsync(ActionContext actionContext) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } var request = actionContext.HttpContext.Request; if (!IsValidPost(request) || !request.HasFormContentType) { // Filters e.g. WebHookVerifyBodyTypeFilter will log and return errors about these conditions. return(null); } // ReadFormAsync does not always ensure the body can be read multiple times. await WebHookHttpRequestUtilities.PrepareRequestBody(request); // Read request body. IFormCollection formCollection; try { formCollection = await request.ReadFormAsync(); } finally { request.Body.Seek(0L, SeekOrigin.Begin); } return(formCollection); }
/// <summary> /// Returns the SHA1 HMAC of the given <paramref name="request"/>'s body. /// </summary> /// <param name="request">The current <see cref="HttpRequest"/>.</param> /// <param name="secret">The key data used to initialize the <see cref="HMACSHA1"/>.</param> /// <returns> /// A <see cref="Task"/> that on completion provides a <see cref="byte"/> array containing the SHA1 HMAC of the /// <paramref name="request"/>'s body. /// </returns> protected virtual async Task <byte[]> GetRequestBodyHash_SHA1(HttpRequest request, byte[] secret) { await WebHookHttpRequestUtilities.PrepareRequestBody(request); using (var hasher = new HMACSHA1(secret)) { try { var hash = hasher.ComputeHash(request.Body); return(hash); } finally { // Reset Position because JsonInputFormatter et cetera always start from current position. request.Body.Seek(0L, SeekOrigin.Begin); } } }
/// <summary> /// Returns the SHA256 HMAC of the given <paramref name="prefix"/>, the given <paramref name="request"/>'s /// body, and the given <paramref name="suffix"/> (in that order). /// </summary> /// <param name="request">The current <see cref="HttpRequest"/>.</param> /// <param name="secret">The key data used to initialize the <see cref="HMACSHA256"/>.</param> /// <param name="prefix"> /// If non-<see langword="null"/> and non-empty, additional <c>byte</c>s to include in the hashed content /// before the <paramref name="request"/>'s body. /// </param> /// <param name="suffix"> /// If non-<see langword="null"/> and non-empty, additional <c>byte</c>s to include in the hashed content /// after the <paramref name="request"/>'s body. /// </param> /// <returns> /// A <see cref="Task"/> that on completion provides a <see cref="byte"/> array containing the SHA256 HMAC of /// the <paramref name="prefix"/>, the <paramref name="request"/>'s body, and the <paramref name="suffix"/> /// (in that order). /// </returns> protected virtual async Task <byte[]> ComputeRequestBodySha256HashAsync( HttpRequest request, byte[] secret, byte[] prefix, byte[] suffix) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (secret == null) { throw new ArgumentNullException(nameof(secret)); } if (secret.Length == 0) { throw new ArgumentException(Resources.General_ArgumentCannotBeNullOrEmpty); } await WebHookHttpRequestUtilities.PrepareRequestBody(request); using (var hasher = new HMACSHA256(secret)) { try { if (prefix != null && prefix.Length > 0) { hasher.TransformBlock( inputBuffer: prefix, inputOffset: 0, inputCount: prefix.Length, outputBuffer: null, outputOffset: 0); } // Split body into 4K chunks. var buffer = new byte[4096]; var inputStream = request.Body; int bytesRead; while ((bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { hasher.TransformBlock( buffer, inputOffset: 0, inputCount: bytesRead, outputBuffer: null, outputOffset: 0); } if (suffix != null && suffix.Length > 0) { hasher.TransformBlock( suffix, inputOffset: 0, inputCount: suffix.Length, outputBuffer: null, outputOffset: 0); } hasher.TransformFinalBlock(Array.Empty <byte>(), inputOffset: 0, inputCount: 0); return(hasher.Hash); } finally { // Reset Position because JsonInputFormatter et cetera always start from current position. request.Body.Seek(0L, SeekOrigin.Begin); } } }