EMSA_PKCS1_V1_5.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * Copyright (c) 2022, Michiel Visser <opensource@webmichiel.nl>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <LibCrypto/Hash/HashManager.h>
  8. #include <LibCrypto/Hash/MD5.h>
  9. #include <LibCrypto/Hash/SHA1.h>
  10. #include <LibCrypto/Hash/SHA2.h>
  11. #include <LibCrypto/PK/Code/Code.h>
  12. namespace Crypto {
  13. namespace PK {
  14. template<typename HashFunction>
  15. class EMSA_PKCS1_V1_5 : public Code<HashFunction> {
  16. public:
  17. template<typename... Args>
  18. EMSA_PKCS1_V1_5(Args... args)
  19. : Code<HashFunction>(args...)
  20. {
  21. }
  22. virtual void encode(ReadonlyBytes in, ByteBuffer& out, size_t em_bits) override
  23. {
  24. auto& hash_fn = this->hasher();
  25. hash_fn.update(in);
  26. auto message_digest = hash_fn.digest();
  27. auto message_digest_size = message_digest.bytes().size();
  28. auto digest_info = hash_function_digest_info();
  29. auto encoded_message_length = digest_info.size() + message_digest_size;
  30. auto em_bytes = (em_bits + 7) / 8;
  31. // RFC8017 section 9.2: 3. If emLen < tLen + 11, output "intended encoded message length too short" and stop.
  32. if (em_bytes < encoded_message_length + 11) {
  33. dbgln("EMSA-PKCS1-V1_5-ENCODE: intended encoded message length too short");
  34. return;
  35. }
  36. auto offset = 0;
  37. // Build the padding 0x0001ffff..ff00
  38. out[offset++] = 0x00;
  39. out[offset++] = 0x01;
  40. for (size_t i = 0; i < em_bytes - encoded_message_length - 3; i++)
  41. out[offset++] = 0xff;
  42. out[offset++] = 0x00;
  43. // Add the digest info and message digest
  44. out.overwrite(offset, digest_info.data(), digest_info.size());
  45. offset += digest_info.size();
  46. out.overwrite(offset, message_digest.immutable_data(), message_digest.data_length());
  47. }
  48. virtual VerificationConsistency verify(ReadonlyBytes msg, ReadonlyBytes emsg, size_t em_bits) override
  49. {
  50. auto em_bytes = (em_bits + 7) / 8;
  51. auto buffer_result = ByteBuffer::create_uninitialized(em_bytes);
  52. if (buffer_result.is_error()) {
  53. dbgln("EMSA-PKCS1-V1_5-VERIFY: out of memory");
  54. return VerificationConsistency::Inconsistent;
  55. }
  56. auto buffer = buffer_result.release_value();
  57. // Encode the supplied message into the buffer
  58. encode(msg, buffer, em_bits);
  59. // Check that the expected message matches the encoded original message
  60. if (emsg != buffer) {
  61. return VerificationConsistency::Inconsistent;
  62. }
  63. return VerificationConsistency::Consistent;
  64. }
  65. private:
  66. inline ReadonlyBytes hash_function_digest_info();
  67. };
  68. template<>
  69. inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::MD5>::hash_function_digest_info()
  70. {
  71. // RFC8017 section 9.2 notes 1
  72. return { "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10", 18 };
  73. }
  74. template<>
  75. inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA1>::hash_function_digest_info()
  76. {
  77. // RFC8017 section 9.2 notes 1
  78. return { "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", 15 };
  79. }
  80. template<>
  81. inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA256>::hash_function_digest_info()
  82. {
  83. // RFC8017 section 9.2 notes 1
  84. return { "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19 };
  85. }
  86. template<>
  87. inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA384>::hash_function_digest_info()
  88. {
  89. // RFC8017 section 9.2 notes 1
  90. return { "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19 };
  91. }
  92. template<>
  93. inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::SHA512>::hash_function_digest_info()
  94. {
  95. // RFC8017 section 9.2 notes 1
  96. return { "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19 };
  97. }
  98. template<>
  99. inline ReadonlyBytes EMSA_PKCS1_V1_5<Crypto::Hash::Manager>::hash_function_digest_info()
  100. {
  101. // RFC8017 section 9.2 notes 1
  102. switch (hasher().kind()) {
  103. case Hash::HashKind::MD5:
  104. return { "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10", 18 };
  105. case Hash::HashKind::SHA1:
  106. return { "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", 15 };
  107. case Hash::HashKind::SHA256:
  108. return { "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19 };
  109. case Hash::HashKind::SHA384:
  110. return { "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19 };
  111. case Hash::HashKind::SHA512:
  112. return { "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19 };
  113. case Hash::HashKind::None:
  114. default:
  115. VERIFY_NOT_REACHED();
  116. }
  117. }
  118. }
  119. }