Mode.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/ByteBuffer.h>
  8. #include <AK/Span.h>
  9. #include <LibCrypto/Cipher/Cipher.h>
  10. namespace Crypto {
  11. namespace Cipher {
  12. template<typename T>
  13. class Mode {
  14. public:
  15. virtual ~Mode() = default;
  16. virtual void encrypt(ReadonlyBytes in, Bytes& out, ReadonlyBytes ivec = {}, Bytes* ivec_out = nullptr) = 0;
  17. virtual void decrypt(ReadonlyBytes in, Bytes& out, ReadonlyBytes ivec = {}) = 0;
  18. virtual size_t IV_length() const = 0;
  19. T const& cipher() const { return m_cipher; }
  20. ErrorOr<ByteBuffer> create_aligned_buffer(size_t input_size) const
  21. {
  22. size_t remainder = (input_size + T::block_size()) % T::block_size();
  23. if (remainder == 0)
  24. return ByteBuffer::create_uninitialized(input_size);
  25. else
  26. return ByteBuffer::create_uninitialized(input_size + T::block_size() - remainder);
  27. }
  28. #ifndef KERNEL
  29. virtual DeprecatedString class_name() const = 0;
  30. #endif
  31. T& cipher()
  32. {
  33. return m_cipher;
  34. }
  35. protected:
  36. virtual void prune_padding(Bytes& data)
  37. {
  38. auto size = data.size();
  39. switch (m_cipher.padding_mode()) {
  40. case PaddingMode::CMS: {
  41. auto maybe_padding_length = data[size - 1];
  42. if (maybe_padding_length >= T::block_size()) {
  43. // cannot be padding (the entire block cannot be padding)
  44. return;
  45. }
  46. for (auto i = size - maybe_padding_length; i < size; ++i) {
  47. if (data[i] != maybe_padding_length) {
  48. // not padding, part of data
  49. return;
  50. }
  51. }
  52. data = data.slice(0, size - maybe_padding_length);
  53. break;
  54. }
  55. case PaddingMode::RFC5246: {
  56. auto maybe_padding_length = data[size - 1];
  57. // FIXME: If we want constant-time operations, this loop should not stop
  58. for (auto i = size - maybe_padding_length - 1; i < size; ++i) {
  59. if (data[i] != maybe_padding_length) {
  60. // note that this is likely invalid padding
  61. return;
  62. }
  63. }
  64. data = data.slice(0, size - maybe_padding_length - 1);
  65. break;
  66. }
  67. case PaddingMode::Null: {
  68. while (data[size - 1] == 0)
  69. --size;
  70. data = data.slice(0, size);
  71. break;
  72. }
  73. default:
  74. // FIXME: support other padding modes
  75. VERIFY_NOT_REACHED();
  76. break;
  77. }
  78. }
  79. // FIXME: Somehow add a reference version of this
  80. template<typename... Args>
  81. Mode(Args... args)
  82. : m_cipher(args...)
  83. {
  84. }
  85. private:
  86. T m_cipher;
  87. };
  88. }
  89. }