Mode.h 2.8 KB

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