CBC.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright (c) 2020, Ali Mohammad Pur <ali.mpfard@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #pragma once
  27. #include <AK/String.h>
  28. #include <AK/StringBuilder.h>
  29. #include <LibCrypto/Cipher/Mode/Mode.h>
  30. namespace Crypto {
  31. namespace Cipher {
  32. template <typename T>
  33. class CBC : public Mode<T> {
  34. public:
  35. constexpr static size_t IVSizeInBits = 128;
  36. virtual ~CBC() {}
  37. template <typename... Args>
  38. explicit constexpr CBC<T>(Args... args)
  39. : Mode<T>(args...)
  40. {
  41. }
  42. virtual String class_name() const override
  43. {
  44. StringBuilder builder;
  45. builder.append(this->cipher().class_name());
  46. builder.append("_CBC");
  47. return builder.build();
  48. }
  49. virtual size_t IV_length() const { return IVSizeInBits / 8; }
  50. virtual Optional<ByteBuffer> encrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) override
  51. {
  52. auto length = in.size();
  53. if (length == 0)
  54. return {};
  55. auto& cipher = this->cipher();
  56. // FIXME: We should have two of these encrypt/decrypt functions that
  57. // we SFINAE out based on whether the Cipher mode needs an ivec
  58. ASSERT(ivec.has_value());
  59. const auto* iv = ivec.value().data();
  60. typename T::BlockType block { cipher.padding_mode() };
  61. size_t offset { 0 };
  62. auto block_size = cipher.block_size();
  63. while (length >= block_size) {
  64. block.overwrite(in.slice_view(offset, block_size));
  65. block.apply_initialization_vector(iv);
  66. cipher.encrypt_block(block, block);
  67. out.overwrite(offset, block.get().data(), block_size);
  68. iv = out.offset_pointer(offset);
  69. length -= block_size;
  70. offset += block_size;
  71. }
  72. if (length > 0) {
  73. block.overwrite(in.slice_view(offset, length));
  74. block.apply_initialization_vector(iv);
  75. cipher.encrypt_block(block, block);
  76. out.overwrite(offset, block.get().data(), block_size);
  77. iv = out.offset_pointer(offset);
  78. }
  79. return ByteBuffer::copy(iv, block_size);
  80. }
  81. virtual void decrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) override
  82. {
  83. auto length = in.size();
  84. if (length == 0)
  85. return;
  86. auto& cipher = this->cipher();
  87. ASSERT(ivec.has_value());
  88. const auto* iv = ivec.value().data();
  89. auto block_size = cipher.block_size();
  90. // if the data is not aligned, it's not correct encrypted data
  91. // FIXME (ponder): Should we simply decrypt as much as we can?
  92. ASSERT(length % block_size == 0);
  93. typename T::BlockType block { cipher.padding_mode() };
  94. size_t offset { 0 };
  95. while (length > 0) {
  96. auto* slice = in.offset_pointer(offset);
  97. block.overwrite(slice, block_size);
  98. cipher.decrypt_block(block, block);
  99. block.apply_initialization_vector(iv);
  100. auto decrypted = block.get();
  101. out.overwrite(offset, decrypted.data(), decrypted.size());
  102. iv = slice;
  103. length -= block_size;
  104. offset += block_size;
  105. }
  106. out.trim(offset);
  107. this->prune_padding(out);
  108. }
  109. };
  110. }
  111. }