Mode.h 2.8 KB

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