Mode.h 3.0 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::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. // rfc5652 Cryptographic Message Syntax (CMS):
  41. // the input shall be padded at the trailing end with k-(lth mod k) octets
  42. // all having value k-(lth mod k), where lth is the length of the input.
  43. auto maybe_padding_length = data[size - 1];
  44. if (maybe_padding_length > T::block_size()) {
  45. // Invalid padding length (too long)
  46. return;
  47. }
  48. for (auto i = size - maybe_padding_length; i < size; ++i) {
  49. if (data[i] != maybe_padding_length) {
  50. // not padding, part of data
  51. return;
  52. }
  53. }
  54. data = data.slice(0, size - maybe_padding_length);
  55. break;
  56. }
  57. case PaddingMode::RFC5246: {
  58. auto maybe_padding_length = data[size - 1];
  59. // FIXME: If we want constant-time operations, this loop should not stop
  60. for (auto i = size - maybe_padding_length - 1; i < size; ++i) {
  61. if (data[i] != maybe_padding_length) {
  62. // note that this is likely invalid padding
  63. return;
  64. }
  65. }
  66. data = data.slice(0, size - maybe_padding_length - 1);
  67. break;
  68. }
  69. case PaddingMode::Null: {
  70. while (data[size - 1] == 0)
  71. --size;
  72. data = data.slice(0, size);
  73. break;
  74. }
  75. default:
  76. // FIXME: support other padding modes
  77. VERIFY_NOT_REACHED();
  78. break;
  79. }
  80. }
  81. // FIXME: Somehow add a reference version of this
  82. template<typename... Args>
  83. Mode(Args... args)
  84. : m_cipher(args...)
  85. {
  86. }
  87. private:
  88. T m_cipher;
  89. };
  90. }