EMSA_PKCS1_V1_5.h 4.6 KB

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