CBC.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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/StringBuilder.h>
  8. #include <AK/StringView.h>
  9. #include <LibCrypto/Cipher/Mode/Mode.h>
  10. #ifndef KERNEL
  11. # include <AK/DeprecatedString.h>
  12. #endif
  13. namespace Crypto {
  14. namespace Cipher {
  15. template<typename T>
  16. class CBC : public Mode<T> {
  17. public:
  18. constexpr static size_t IVSizeInBits = 128;
  19. virtual ~CBC() = default;
  20. template<typename... Args>
  21. explicit constexpr CBC<T>(Args... args)
  22. : Mode<T>(args...)
  23. {
  24. }
  25. #ifndef KERNEL
  26. virtual DeprecatedString class_name() const override
  27. {
  28. StringBuilder builder;
  29. builder.append(this->cipher().class_name());
  30. builder.append("_CBC"sv);
  31. return builder.to_deprecated_string();
  32. }
  33. #endif
  34. virtual size_t IV_length() const override
  35. {
  36. return IVSizeInBits / 8;
  37. }
  38. virtual void encrypt(ReadonlyBytes in, Bytes& out, ReadonlyBytes ivec = {}, Bytes* ivec_out = nullptr) override
  39. {
  40. auto length = in.size();
  41. if (length == 0)
  42. return;
  43. auto& cipher = this->cipher();
  44. // FIXME: We should have two of these encrypt/decrypt functions that
  45. // we SFINAE out based on whether the Cipher mode needs an ivec
  46. VERIFY(!ivec.is_empty());
  47. ReadonlyBytes iv = ivec;
  48. m_cipher_block.set_padding_mode(cipher.padding_mode());
  49. size_t offset { 0 };
  50. auto block_size = cipher.block_size();
  51. while (length >= block_size) {
  52. m_cipher_block.overwrite(in.slice(offset, block_size));
  53. m_cipher_block.apply_initialization_vector(iv);
  54. cipher.encrypt_block(m_cipher_block, m_cipher_block);
  55. VERIFY(offset + block_size <= out.size());
  56. __builtin_memcpy(out.offset(offset), m_cipher_block.bytes().data(), block_size);
  57. iv = out.slice(offset);
  58. length -= block_size;
  59. offset += block_size;
  60. }
  61. if (length > 0) {
  62. m_cipher_block.overwrite(in.slice(offset, length));
  63. m_cipher_block.apply_initialization_vector(iv);
  64. cipher.encrypt_block(m_cipher_block, m_cipher_block);
  65. VERIFY(offset + block_size <= out.size());
  66. __builtin_memcpy(out.offset(offset), m_cipher_block.bytes().data(), block_size);
  67. iv = out.slice(offset);
  68. }
  69. if (ivec_out)
  70. __builtin_memcpy(ivec_out->data(), iv.data(), min(IV_length(), ivec_out->size()));
  71. }
  72. virtual void decrypt(ReadonlyBytes in, Bytes& out, ReadonlyBytes ivec = {}) override
  73. {
  74. auto length = in.size();
  75. if (length == 0)
  76. return;
  77. auto& cipher = this->cipher();
  78. VERIFY(!ivec.is_empty());
  79. ReadonlyBytes iv = ivec;
  80. auto block_size = cipher.block_size();
  81. // if the data is not aligned, it's not correct encrypted data
  82. // FIXME (ponder): Should we simply decrypt as much as we can?
  83. VERIFY(length % block_size == 0);
  84. m_cipher_block.set_padding_mode(cipher.padding_mode());
  85. size_t offset { 0 };
  86. while (length > 0) {
  87. auto slice = in.slice(offset);
  88. m_cipher_block.overwrite(slice.data(), block_size);
  89. cipher.decrypt_block(m_cipher_block, m_cipher_block);
  90. m_cipher_block.apply_initialization_vector(iv);
  91. auto decrypted = m_cipher_block.bytes();
  92. VERIFY(offset + decrypted.size() <= out.size());
  93. __builtin_memcpy(out.offset(offset), decrypted.data(), decrypted.size());
  94. iv = slice;
  95. length -= block_size;
  96. offset += block_size;
  97. }
  98. out = out.slice(0, offset);
  99. this->prune_padding(out);
  100. }
  101. private:
  102. typename T::BlockType m_cipher_block {};
  103. };
  104. }
  105. }