xlsx_crypto_producer.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright (c) 2014-2021 Thomas Fussell
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE
  20. //
  21. // @license: http://www.opensource.org/licenses/mit-license.php
  22. // @author: see AUTHORS file
  23. #include <xlnt/utils/exceptions.hpp>
  24. #include <detail/constants.hpp>
  25. #include <detail/cryptography/aes.hpp>
  26. #include <detail/cryptography/base64.hpp>
  27. #include <detail/cryptography/compound_document.hpp>
  28. #include <detail/cryptography/encryption_info.hpp>
  29. #include <detail/cryptography/value_traits.hpp>
  30. #include <detail/cryptography/xlsx_crypto_producer.hpp>
  31. #include <detail/external/include_libstudxml.hpp>
  32. #include <detail/serialization/vector_streambuf.hpp>
  33. #include <detail/serialization/xlsx_producer.hpp>
  34. #include <detail/serialization/zstream.hpp>
  35. #include <detail/unicode.hpp>
  36. namespace {
  37. using xlnt::detail::encryption_info;
  38. encryption_info generate_encryption_info(const std::u16string & /*password*/)
  39. {
  40. encryption_info result;
  41. result.is_agile = true;
  42. result.agile = encryption_info::agile_encryption_info();
  43. result.agile.key_data.block_size = 16;
  44. result.agile.key_data.cipher_algorithm = "AES";
  45. result.agile.key_data.cipher_chaining = "ChainingModeCBC";
  46. result.agile.key_data.hash_algorithm = "SHA512";
  47. result.agile.key_data.hash_size = 64;
  48. result.agile.key_data.key_bits = 256;
  49. result.agile.key_data.salt_size = 16;
  50. result.agile.key_data.salt_value =
  51. {
  52. {40, 183, 193, 64, 115, 97, 10, 177, 122, 50, 243, 123, 229, 145, 162, 247}};
  53. result.agile.data_integrity.hmac_key =
  54. {
  55. {90, 206, 203, 147, 102, 81, 82, 14, 118, 94, 168, 38, 200, 79, 13, 147, 60,
  56. 123, 167, 220, 17, 165, 124, 188, 206, 74, 98, 33, 156, 63, 220, 152, 180, 201,
  57. 167, 183, 141, 252, 182, 55, 90, 189, 187, 167, 230, 186, 61, 239, 80, 49, 54,
  58. 208, 52, 133, 232, 187, 117, 136, 213, 48, 133, 15, 7, 126}};
  59. result.agile.data_integrity.hmac_value =
  60. {
  61. {49, 128, 174, 178, 161, 48, 1, 82, 241, 103, 72, 223, 103, 111, 204, 73,
  62. 210, 70, 254, 43, 12, 134, 180, 201, 124, 153, 214, 115, 82, 184, 78, 2,
  63. 166, 106, 69, 18, 173, 177, 40, 238, 243, 240, 3, 86, 145, 218, 223, 177,
  64. 36, 34, 44, 159, 104, 163, 217, 42, 203, 135, 173, 14, 218, 172, 72, 224}};
  65. result.agile.key_encryptor.spin_count = 100000;
  66. result.agile.key_encryptor.block_size = 16;
  67. result.agile.key_encryptor.cipher_algorithm = "AES";
  68. result.agile.key_encryptor.cipher_chaining = "ChainingModeCBC";
  69. result.agile.key_encryptor.hash = xlnt::detail::hash_algorithm::sha512;
  70. result.agile.key_encryptor.hash_size = 64;
  71. result.agile.key_encryptor.key_bits = 256;
  72. result.agile.key_encryptor.salt_size = 16;
  73. result.agile.key_encryptor.salt_value =
  74. {
  75. {98, 169, 85, 224, 173, 253, 2, 52, 199, 108, 195, 73, 116, 112, 72, 165}};
  76. result.agile.key_encryptor.verifier_hash_input =
  77. {
  78. {179, 105, 118, 193, 217, 180, 248, 7, 174, 45, 186, 17, 202, 101, 178, 12}};
  79. result.agile.key_encryptor.verifier_hash_value =
  80. {
  81. {82, 190, 235, 102, 30, 33, 103, 191, 3, 160, 153, 30, 127, 117, 8, 195, 65,
  82. 245, 77, 219, 85, 28, 206, 236, 55, 86, 243, 49, 104, 128, 243, 138, 227, 113,
  83. 82, 88, 88, 73, 243, 108, 193, 11, 84, 162, 235, 189, 9, 137, 151, 97, 43,
  84. 137, 197, 72, 164, 192, 65, 252, 253, 227, 236, 242, 252, 179}};
  85. result.agile.key_encryptor.encrypted_key_value =
  86. {
  87. {220, 6, 106, 218, 31, 210, 9, 75, 28, 154, 173, 232, 190, 109, 112, 203, 25,
  88. 5, 45, 152, 75, 131, 122, 17, 166, 95, 117, 124, 121, 123, 32, 133}};
  89. return result;
  90. }
  91. void write_agile_encryption_info(
  92. const encryption_info &info,
  93. std::ostream &info_stream)
  94. {
  95. const auto version_major = std::uint16_t(4);
  96. const auto version_minor = std::uint16_t(4);
  97. const auto encryption_flags = std::uint32_t(0x40);
  98. info_stream.write(reinterpret_cast<const char *>(&version_major), sizeof(std::uint16_t));
  99. info_stream.write(reinterpret_cast<const char *>(&version_minor), sizeof(std::uint16_t));
  100. info_stream.write(reinterpret_cast<const char *>(&encryption_flags), sizeof(std::uint32_t));
  101. static const auto &xmlns = xlnt::constants::ns("encryption");
  102. static const auto &xmlns_p = xlnt::constants::ns("encryption-password");
  103. xml::serializer serializer(info_stream, "EncryptionInfo");
  104. serializer.start_element(xmlns, "encryption");
  105. const auto key_data = info.agile.key_data;
  106. serializer.start_element(xmlns, "keyData");
  107. serializer.attribute("saltSize", key_data.salt_size);
  108. serializer.attribute("blockSize", key_data.block_size);
  109. serializer.attribute("keyBits", key_data.key_bits);
  110. serializer.attribute("hashSize", key_data.hash_size);
  111. serializer.attribute("cipherAlgorithm", key_data.cipher_algorithm);
  112. serializer.attribute("cipherChaining", key_data.cipher_chaining);
  113. serializer.attribute("hashAlgorithm", key_data.hash_algorithm);
  114. serializer.attribute("saltValue",
  115. xlnt::detail::encode_base64(key_data.salt_value));
  116. serializer.end_element();
  117. const auto data_integrity = info.agile.data_integrity;
  118. serializer.start_element(xmlns, "dataIntegrity");
  119. serializer.attribute("encryptedHmacKey",
  120. xlnt::detail::encode_base64(data_integrity.hmac_key));
  121. serializer.attribute("encryptedHmacValue",
  122. xlnt::detail::encode_base64(data_integrity.hmac_value));
  123. serializer.end_element();
  124. const auto key_encryptor = info.agile.key_encryptor;
  125. serializer.start_element(xmlns, "keyEncryptors");
  126. serializer.start_element(xmlns, "keyEncryptor");
  127. serializer.attribute("uri", "");
  128. serializer.start_element(xmlns_p, "encryptedKey");
  129. serializer.attribute("spinCount", key_encryptor.spin_count);
  130. serializer.attribute("saltSize", key_encryptor.salt_size);
  131. serializer.attribute("blockSize", key_encryptor.block_size);
  132. serializer.attribute("keyBits", key_encryptor.key_bits);
  133. serializer.attribute("hashSize", key_encryptor.hash_size);
  134. serializer.attribute("cipherAlgorithm", key_encryptor.cipher_algorithm);
  135. serializer.attribute("cipherChaining", key_encryptor.cipher_chaining);
  136. serializer.attribute("hashAlgorithm", key_encryptor.hash);
  137. serializer.attribute("saltValue",
  138. xlnt::detail::encode_base64(key_encryptor.salt_value));
  139. serializer.attribute("encryptedVerifierHashInput",
  140. xlnt::detail::encode_base64(key_encryptor.verifier_hash_input));
  141. serializer.attribute("encryptedVerifierHashValue",
  142. xlnt::detail::encode_base64(key_encryptor.verifier_hash_value));
  143. serializer.attribute("encryptedKeyValue",
  144. xlnt::detail::encode_base64(key_encryptor.encrypted_key_value));
  145. serializer.end_element();
  146. serializer.end_element();
  147. serializer.end_element();
  148. serializer.end_element();
  149. }
  150. void write_standard_encryption_info(const encryption_info &info, std::ostream &info_stream)
  151. {
  152. auto result = std::vector<std::uint8_t>();
  153. auto writer = xlnt::detail::binary_writer<std::uint8_t>(result);
  154. const auto version_major = std::uint16_t(4);
  155. const auto version_minor = std::uint16_t(2);
  156. const auto encryption_flags = std::uint32_t(0x10 & 0x20);
  157. writer.write(version_major);
  158. writer.write(version_minor);
  159. writer.write(encryption_flags);
  160. const auto header_length = std::uint32_t(32); // calculate this!
  161. writer.write(header_length);
  162. writer.write(std::uint32_t(0)); // skip_flags
  163. writer.write(std::uint32_t(0)); // size_extra
  164. writer.write(std::uint32_t(0x0000660E));
  165. writer.write(std::uint32_t(0x00008004));
  166. writer.write(std::uint32_t(info.standard.key_bits));
  167. writer.write(std::uint32_t(0x00000018));
  168. writer.write(std::uint32_t(0));
  169. writer.write(std::uint32_t(0));
  170. const auto provider = std::u16string(u"Microsoft Enhanced RSA and AES Cryptographic Provider");
  171. writer.append(xlnt::detail::string_to_bytes(provider));
  172. writer.write(std::uint32_t(info.standard.salt.size()));
  173. writer.append(info.standard.salt);
  174. writer.append(info.standard.encrypted_verifier);
  175. writer.write(std::uint32_t(20));
  176. writer.append(info.standard.encrypted_verifier_hash);
  177. info_stream.write(reinterpret_cast<char *>(result.data()),
  178. static_cast<std::streamsize>(result.size()));
  179. }
  180. void encrypt_xlsx_agile(
  181. const encryption_info &info,
  182. const std::vector<std::uint8_t> &plaintext,
  183. std::ostream &ciphertext_stream)
  184. {
  185. const auto length = static_cast<std::uint64_t>(plaintext.size());
  186. ciphertext_stream.write(reinterpret_cast<const char *>(&length), sizeof(std::uint64_t));
  187. auto key = info.calculate_key();
  188. auto salt_size = info.agile.key_data.salt_size;
  189. auto salt_with_block_key = info.agile.key_data.salt_value;
  190. salt_with_block_key.resize(salt_size + sizeof(std::uint32_t), 0);
  191. auto &segment_index = *reinterpret_cast<std::uint32_t *>(salt_with_block_key.data() + salt_size);
  192. auto segment = std::vector<std::uint8_t>(4096, 0);
  193. for (auto i = std::size_t(0); i < length; i += 4096)
  194. {
  195. auto iv = hash(info.agile.key_encryptor.hash, salt_with_block_key);
  196. iv.resize(16);
  197. auto start = plaintext.begin() + static_cast<std::ptrdiff_t>(i);
  198. auto bytes = std::min(std::size_t(length - i), std::size_t(4096));
  199. std::copy(start, start + static_cast<std::ptrdiff_t>(bytes), segment.begin());
  200. auto encrypted_segment = xlnt::detail::aes_cbc_encrypt(segment, key, iv);
  201. ciphertext_stream.write(reinterpret_cast<char *>(encrypted_segment.data()),
  202. static_cast<std::streamsize>(bytes));
  203. ++segment_index;
  204. }
  205. }
  206. void encrypt_xlsx_standard(
  207. const encryption_info &info,
  208. const std::vector<std::uint8_t> &plaintext,
  209. std::ostream &ciphertext_stream)
  210. {
  211. const auto length = static_cast<std::uint64_t>(plaintext.size());
  212. ciphertext_stream.write(reinterpret_cast<const char *>(&length), sizeof(std::uint64_t));
  213. auto key = info.calculate_key();
  214. auto segment = std::vector<std::uint8_t>(4096, 0);
  215. for (auto i = std::size_t(0); i < length; ++i)
  216. {
  217. auto start = plaintext.begin() + static_cast<std::ptrdiff_t>(i);
  218. auto bytes = std::min(std::size_t(length - i), std::size_t(4096));
  219. std::copy(start, start + static_cast<std::ptrdiff_t>(bytes), segment.begin());
  220. auto encrypted_segment = xlnt::detail::aes_ecb_encrypt(segment, key);
  221. ciphertext_stream.write(reinterpret_cast<char *>(encrypted_segment.data()),
  222. static_cast<std::streamsize>(bytes));
  223. }
  224. }
  225. std::vector<std::uint8_t> encrypt_xlsx(
  226. const std::vector<std::uint8_t> &plaintext,
  227. const std::u16string &password)
  228. {
  229. auto encryption_info = generate_encryption_info(password);
  230. encryption_info.password = u"secret";
  231. auto ciphertext = std::vector<std::uint8_t>();
  232. xlnt::detail::vector_ostreambuf buffer(ciphertext);
  233. std::ostream stream(&buffer);
  234. xlnt::detail::compound_document document(stream);
  235. if (encryption_info.is_agile)
  236. {
  237. write_agile_encryption_info(encryption_info,
  238. document.open_write_stream("/EncryptionInfo"));
  239. encrypt_xlsx_agile(encryption_info, plaintext,
  240. document.open_write_stream("/EncryptedPackage"));
  241. }
  242. else
  243. {
  244. write_standard_encryption_info(encryption_info,
  245. document.open_write_stream("/EncryptionInfo"));
  246. encrypt_xlsx_standard(encryption_info, plaintext,
  247. document.open_write_stream("/EncryptedPackage"));
  248. }
  249. return ciphertext;
  250. }
  251. } // namespace
  252. namespace xlnt {
  253. namespace detail {
  254. std::vector<std::uint8_t> XLNT_API encrypt_xlsx(
  255. const std::vector<std::uint8_t> &plaintext,
  256. const std::string &password)
  257. {
  258. return ::encrypt_xlsx(plaintext, utf8_to_utf16(password));
  259. }
  260. void xlsx_producer::write(std::ostream &destination, const std::string &password)
  261. {
  262. std::vector<std::uint8_t> plaintext;
  263. vector_ostreambuf plaintext_buffer(plaintext);
  264. std::ostream decrypted_stream(&plaintext_buffer);
  265. write(decrypted_stream);
  266. archive_.reset();
  267. const auto ciphertext = ::encrypt_xlsx(plaintext, utf8_to_utf16(password));
  268. vector_istreambuf encrypted_buffer(ciphertext);
  269. destination << &encrypted_buffer;
  270. }
  271. } // namespace detail
  272. } // namespace xlnt