CBC.h 3.8 KB

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