xlsx_crypto_consumer.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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 <array>
  24. #include <cstdint>
  25. #include <vector>
  26. #include <xlnt/utils/exceptions.hpp>
  27. #include <detail/binary.hpp>
  28. #include <detail/constants.hpp>
  29. #include <detail/cryptography/aes.hpp>
  30. #include <detail/cryptography/base64.hpp>
  31. #include <detail/cryptography/compound_document.hpp>
  32. #include <detail/cryptography/encryption_info.hpp>
  33. #include <detail/cryptography/value_traits.hpp>
  34. #include <detail/cryptography/xlsx_crypto_consumer.hpp>
  35. #include <detail/external/include_libstudxml.hpp>
  36. #include <detail/serialization/vector_streambuf.hpp>
  37. #include <detail/serialization/xlsx_consumer.hpp>
  38. #include <detail/unicode.hpp>
  39. namespace {
  40. using xlnt::detail::byte;
  41. using xlnt::detail::encryption_info;
  42. using xlnt::detail::read;
  43. std::vector<std::uint8_t> decrypt_xlsx_standard(
  44. encryption_info info,
  45. std::istream &encrypted_package_stream)
  46. {
  47. const auto key = info.calculate_key();
  48. auto decrypted_size = read<std::uint64_t>(encrypted_package_stream);
  49. std::vector<std::uint8_t> encrypted_segment(4096, 0);
  50. std::vector<std::uint8_t> decrypted_package;
  51. while (encrypted_package_stream)
  52. {
  53. encrypted_package_stream.read(
  54. reinterpret_cast<char *>(encrypted_segment.data()),
  55. static_cast<std::streamsize>(encrypted_segment.size()));
  56. auto decrypted_segment = xlnt::detail::aes_ecb_decrypt(encrypted_segment, key);
  57. decrypted_package.insert(
  58. decrypted_package.end(),
  59. decrypted_segment.begin(),
  60. decrypted_segment.end());
  61. }
  62. decrypted_package.resize(static_cast<std::size_t>(decrypted_size));
  63. return decrypted_package;
  64. }
  65. std::vector<std::uint8_t> decrypt_xlsx_agile(
  66. const encryption_info &info,
  67. std::istream &encrypted_package_stream)
  68. {
  69. const auto key = info.calculate_key();
  70. auto salt_size = info.agile.key_data.salt_size;
  71. auto salt_with_block_key = info.agile.key_data.salt_value;
  72. salt_with_block_key.resize(salt_size + sizeof(std::uint32_t), 0);
  73. auto &segment = *reinterpret_cast<std::uint32_t *>(salt_with_block_key.data() + salt_size);
  74. auto total_size = read<std::uint64_t>(encrypted_package_stream);
  75. std::vector<std::uint8_t> encrypted_segment(4096, 0);
  76. std::vector<std::uint8_t> decrypted_package;
  77. while (encrypted_package_stream)
  78. {
  79. auto iv = hash(info.agile.key_encryptor.hash, salt_with_block_key);
  80. iv.resize(16);
  81. encrypted_package_stream.read(
  82. reinterpret_cast<char *>(encrypted_segment.data()),
  83. static_cast<std::streamsize>(encrypted_segment.size()));
  84. auto decrypted_segment = xlnt::detail::aes_cbc_decrypt(encrypted_segment, key, iv);
  85. decrypted_package.insert(
  86. decrypted_package.end(),
  87. decrypted_segment.begin(),
  88. decrypted_segment.end());
  89. ++segment;
  90. }
  91. decrypted_package.resize(static_cast<std::size_t>(total_size));
  92. return decrypted_package;
  93. }
  94. encryption_info::standard_encryption_info read_standard_encryption_info(std::istream &info_stream)
  95. {
  96. encryption_info::standard_encryption_info result;
  97. auto header_length = read<std::uint32_t>(info_stream);
  98. auto index_at_start = info_stream.tellg();
  99. /*auto skip_flags = */ read<std::uint32_t>(info_stream);
  100. /*auto size_extra = */ read<std::uint32_t>(info_stream);
  101. auto alg_id = read<std::uint32_t>(info_stream);
  102. if (alg_id == 0 || alg_id == 0x0000660E || alg_id == 0x0000660F || alg_id == 0x00006610)
  103. {
  104. result.cipher = xlnt::detail::cipher_algorithm::aes;
  105. }
  106. else
  107. {
  108. throw xlnt::exception("invalid cipher algorithm");
  109. }
  110. auto alg_id_hash = read<std::uint32_t>(info_stream);
  111. if (alg_id_hash != 0x00008004 && alg_id_hash == 0)
  112. {
  113. throw xlnt::exception("invalid hash algorithm");
  114. }
  115. result.key_bits = read<std::uint32_t>(info_stream);
  116. result.key_bytes = result.key_bits / 8;
  117. auto provider_type = read<std::uint32_t>(info_stream);
  118. if (provider_type != 0 && provider_type != 0x00000018)
  119. {
  120. throw xlnt::exception("invalid provider type");
  121. }
  122. read<std::uint32_t>(info_stream); // reserved 1
  123. if (read<std::uint32_t>(info_stream) != 0) // reserved 2
  124. {
  125. throw xlnt::exception("invalid header");
  126. }
  127. const auto csp_name_length = static_cast<std::size_t>((header_length
  128. - (info_stream.tellg() - index_at_start))
  129. / 2);
  130. auto csp_name = xlnt::detail::read_string<char16_t>(info_stream, csp_name_length);
  131. csp_name.pop_back(); // remove extraneous trailing null
  132. if (csp_name != u"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
  133. && csp_name != u"Microsoft Enhanced RSA and AES Cryptographic Provider")
  134. {
  135. throw xlnt::exception("invalid cryptographic provider");
  136. }
  137. const auto salt_size = read<std::uint32_t>(info_stream);
  138. result.salt = xlnt::detail::read_vector<byte>(info_stream, salt_size);
  139. static const auto verifier_size = std::size_t(16);
  140. result.encrypted_verifier = xlnt::detail::read_vector<byte>(info_stream, verifier_size);
  141. /*const auto verifier_hash_size = */ read<std::uint32_t>(info_stream);
  142. const auto encrypted_verifier_hash_size = std::size_t(32);
  143. result.encrypted_verifier_hash = xlnt::detail::read_vector<byte>(info_stream, encrypted_verifier_hash_size);
  144. return result;
  145. }
  146. encryption_info::agile_encryption_info read_agile_encryption_info(std::istream &info_stream)
  147. {
  148. using xlnt::detail::decode_base64;
  149. static const auto &xmlns = xlnt::constants::ns("encryption");
  150. static const auto &xmlns_p = xlnt::constants::ns("encryption-password");
  151. // static const auto &xmlns_c = xlnt::constants::namespace_("encryption-certificate");
  152. encryption_info::agile_encryption_info result;
  153. xml::parser parser(info_stream, "EncryptionInfo");
  154. parser.next_expect(xml::parser::event_type::start_element, xmlns, "encryption");
  155. auto &key_data = result.key_data;
  156. parser.next_expect(xml::parser::event_type::start_element, xmlns, "keyData");
  157. key_data.salt_size = parser.attribute<std::size_t>("saltSize");
  158. key_data.block_size = parser.attribute<std::size_t>("blockSize");
  159. key_data.key_bits = parser.attribute<std::size_t>("keyBits");
  160. key_data.hash_size = parser.attribute<std::size_t>("hashSize");
  161. key_data.cipher_algorithm = parser.attribute("cipherAlgorithm");
  162. key_data.cipher_chaining = parser.attribute("cipherChaining");
  163. key_data.hash_algorithm = parser.attribute("hashAlgorithm");
  164. key_data.salt_value = decode_base64(parser.attribute("saltValue"));
  165. parser.next_expect(xml::parser::event_type::end_element, xmlns, "keyData");
  166. auto &data_integrity = result.data_integrity;
  167. parser.next_expect(xml::parser::event_type::start_element, xmlns, "dataIntegrity");
  168. data_integrity.hmac_key = decode_base64(parser.attribute("encryptedHmacKey"));
  169. data_integrity.hmac_value = decode_base64(parser.attribute("encryptedHmacValue"));
  170. parser.next_expect(xml::parser::event_type::end_element, xmlns, "dataIntegrity");
  171. auto &key_encryptor = result.key_encryptor;
  172. parser.next_expect(xml::parser::event_type::start_element, xmlns, "keyEncryptors");
  173. parser.next_expect(xml::parser::event_type::start_element, xmlns, "keyEncryptor");
  174. parser.attribute("uri");
  175. bool any_password_key = false;
  176. while (parser.peek() != xml::parser::event_type::end_element)
  177. {
  178. parser.next_expect(xml::parser::event_type::start_element);
  179. if (parser.namespace_() == xmlns_p && parser.name() == "encryptedKey")
  180. {
  181. any_password_key = true;
  182. key_encryptor.spin_count = parser.attribute<std::size_t>("spinCount");
  183. key_encryptor.salt_size = parser.attribute<std::size_t>("saltSize");
  184. key_encryptor.block_size = parser.attribute<std::size_t>("blockSize");
  185. key_encryptor.key_bits = parser.attribute<std::size_t>("keyBits");
  186. key_encryptor.hash_size = parser.attribute<std::size_t>("hashSize");
  187. key_encryptor.cipher_algorithm = parser.attribute("cipherAlgorithm");
  188. key_encryptor.cipher_chaining = parser.attribute("cipherChaining");
  189. key_encryptor.hash = parser.attribute<xlnt::detail::hash_algorithm>("hashAlgorithm");
  190. key_encryptor.salt_value = decode_base64(parser.attribute("saltValue"));
  191. key_encryptor.verifier_hash_input = decode_base64(parser.attribute("encryptedVerifierHashInput"));
  192. key_encryptor.verifier_hash_value = decode_base64(parser.attribute("encryptedVerifierHashValue"));
  193. key_encryptor.encrypted_key_value = decode_base64(parser.attribute("encryptedKeyValue"));
  194. }
  195. else
  196. {
  197. throw xlnt::unsupported("other encryption key types not supported");
  198. }
  199. parser.next_expect(xml::parser::event_type::end_element);
  200. }
  201. if (!any_password_key)
  202. {
  203. throw xlnt::exception("no password key in keyEncryptors");
  204. }
  205. parser.next_expect(xml::parser::event_type::end_element, xmlns, "keyEncryptor");
  206. parser.next_expect(xml::parser::event_type::end_element, xmlns, "keyEncryptors");
  207. parser.next_expect(xml::parser::event_type::end_element, xmlns, "encryption");
  208. return result;
  209. }
  210. encryption_info read_encryption_info(std::istream &info_stream, const std::u16string &password)
  211. {
  212. encryption_info info;
  213. info.password = password;
  214. auto version_major = read<std::uint16_t>(info_stream);
  215. auto version_minor = read<std::uint16_t>(info_stream);
  216. auto encryption_flags = read<std::uint32_t>(info_stream);
  217. info.is_agile = version_major == 4 && version_minor == 4;
  218. if (info.is_agile)
  219. {
  220. if (encryption_flags != 0x40)
  221. {
  222. throw xlnt::exception("bad header");
  223. }
  224. info.agile = read_agile_encryption_info(info_stream);
  225. }
  226. else
  227. {
  228. if (version_minor != 2 || (version_major != 2 && version_major != 3 && version_major != 4))
  229. {
  230. throw xlnt::exception("unsupported encryption version");
  231. }
  232. if ((encryption_flags & 0x03) != 0) // Reserved1 and Reserved2, MUST be 0
  233. {
  234. throw xlnt::exception("bad header");
  235. }
  236. if ((encryption_flags & 0x04) == 0 // fCryptoAPI
  237. || (encryption_flags & 0x10) != 0) // fExternal
  238. {
  239. throw xlnt::exception("extensible encryption is not supported");
  240. }
  241. if ((encryption_flags & 0x20) == 0) // fAES
  242. {
  243. throw xlnt::exception("not an OOXML document");
  244. }
  245. info.standard = read_standard_encryption_info(info_stream);
  246. }
  247. return info;
  248. }
  249. std::vector<std::uint8_t> decrypt_xlsx(
  250. const std::vector<std::uint8_t> &bytes,
  251. const std::u16string &password)
  252. {
  253. if (bytes.empty())
  254. {
  255. throw xlnt::exception("empty file");
  256. }
  257. xlnt::detail::vector_istreambuf buffer(bytes);
  258. std::istream stream(&buffer);
  259. xlnt::detail::compound_document document(stream);
  260. auto &encryption_info_stream = document.open_read_stream("/EncryptionInfo");
  261. auto encryption_info = read_encryption_info(encryption_info_stream, password);
  262. auto &encrypted_package_stream = document.open_read_stream("/EncryptedPackage");
  263. return encryption_info.is_agile
  264. ? decrypt_xlsx_agile(encryption_info, encrypted_package_stream)
  265. : decrypt_xlsx_standard(encryption_info, encrypted_package_stream);
  266. }
  267. } // namespace
  268. namespace xlnt {
  269. namespace detail {
  270. std::vector<std::uint8_t> XLNT_API decrypt_xlsx(const std::vector<std::uint8_t> &data, const std::string &password)
  271. {
  272. return ::decrypt_xlsx(data, utf8_to_utf16(password));
  273. }
  274. void xlsx_consumer::read(std::istream &source, const std::string &password)
  275. {
  276. std::vector<std::uint8_t> data((std::istreambuf_iterator<char>(source)), (std::istreambuf_iterator<char>()));
  277. const auto decrypted = decrypt_xlsx(data, password);
  278. vector_istreambuf decrypted_buffer(decrypted);
  279. std::istream decrypted_stream(&decrypted_buffer);
  280. read(decrypted_stream);
  281. }
  282. } // namespace detail
  283. } // namespace xlnt