CBC.h 3.7 KB

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