sha256.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #include "sha256.h"
  2. #include <Windows.h>
  3. #include <bcrypt.h>
  4. #include <limits>
  5. namespace sunrise::middleware::crypto::sha256 {
  6. namespace {
  7. /** @return True for a BCrypt status that reports success. */
  8. [[nodiscard]] bool succeeded(NTSTATUS status) noexcept {
  9. return status >= 0;
  10. }
  11. /**
  12. * Adds one buffer to an open hash.
  13. * @param handle Open hash object.
  14. * @param part Bytes to add; an empty part is skipped.
  15. * @return True when the bytes fit one call and BCrypt accepted them.
  16. */
  17. [[nodiscard]] bool add(BCRYPT_HASH_HANDLE handle, std::span<const std::byte> part) noexcept {
  18. if (part.empty()) {
  19. return true;
  20. }
  21. if (part.size() > (std::numeric_limits<ULONG>::max)()) {
  22. return false;
  23. }
  24. return succeeded(BCryptHashData(handle,
  25. reinterpret_cast<PUCHAR>(const_cast<std::byte*>(part.data())),
  26. static_cast<ULONG>(part.size()),
  27. 0));
  28. }
  29. /**
  30. * Hashes up to two buffers as one message.
  31. * @param first Leading bytes.
  32. * @param second Trailing bytes, possibly empty.
  33. * @param output Receives the digest only on success.
  34. * @return True when every stage of the Windows hash succeeded.
  35. */
  36. [[nodiscard]] bool digest(std::span<const std::byte> first,
  37. std::span<const std::byte> second,
  38. Digest& output) noexcept {
  39. BCRYPT_ALG_HANDLE algorithm = nullptr;
  40. if (!succeeded(BCryptOpenAlgorithmProvider(&algorithm, BCRYPT_SHA256_ALGORITHM, nullptr, 0))) {
  41. return false;
  42. }
  43. BCRYPT_HASH_HANDLE handle = nullptr;
  44. bool complete = false;
  45. if (succeeded(BCryptCreateHash(algorithm, &handle, nullptr, 0, nullptr, 0, 0))) {
  46. complete = add(handle, first) && add(handle, second)
  47. && succeeded(BCryptFinishHash(handle,
  48. reinterpret_cast<PUCHAR>(output.data()),
  49. static_cast<ULONG>(output.size()),
  50. 0));
  51. BCryptDestroyHash(handle);
  52. }
  53. BCryptCloseAlgorithmProvider(algorithm, 0);
  54. return complete;
  55. }
  56. } // namespace
  57. /** Hashes one buffer. */
  58. bool hash(std::span<const std::byte> input, Digest& output) noexcept {
  59. return digest(input, {}, output);
  60. }
  61. /** Hashes two buffers as one concatenated message. */
  62. bool hash_pair(std::span<const std::byte> first,
  63. std::span<const std::byte> second,
  64. Digest& output) noexcept {
  65. return digest(first, second, output);
  66. }
  67. } // namespace sunrise::middleware::crypto::sha256