// Copyright (c) 2014-2017 Thomas Fussell // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE // // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file #include #include #include #include #include #include #include #include #include #include #include namespace { using xlnt::detail::encryption_info; encryption_info generate_encryption_info(const std::u16string &password) { encryption_info result; result.is_agile = true; result.agile = encryption_info::agile_encryption_info{}; result.agile.key_data.block_size = 16; result.agile.key_data.cipher_algorithm = "AES"; result.agile.key_data.cipher_chaining = "CBC"; result.agile.key_data.hash_algorithm = "SHA512"; result.agile.key_data.hash_size = 64; result.agile.key_data.key_bits = 128; result.agile.key_data.salt_size = 10; result.agile.key_data.salt_value = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; result.agile.data_integrity.hmac_key = { 1, 2, 3 }; result.agile.data_integrity.hmac_value = { 3, 4, 5 }; result.agile.key_encryptor.spin_count = 100000; result.agile.key_encryptor.block_size = 16; result.agile.key_encryptor.cipher_algorithm = "AES"; result.agile.key_encryptor.cipher_chaining = "CBC"; result.agile.key_encryptor.hash = xlnt::detail::hash_algorithm::sha512; result.agile.key_encryptor.hash_size = 64; result.agile.key_encryptor.key_bits = 128; result.agile.key_encryptor.salt_size = 10; result.agile.key_encryptor.salt_value = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; result.agile.key_encryptor.verifier_hash_input = { 1, 2, 3 }; result.agile.key_encryptor.verifier_hash_value = { 1, 2, 3 }; result.agile.key_encryptor.encrypted_key_value = { 3, 4, 5 }; result.agile.key_data.salt_value.assign( reinterpret_cast(password.data()), reinterpret_cast(password.data() + password.size())); return result; } std::vector write_agile_encryption_info( const encryption_info &info) { static const auto &xmlns = xlnt::constants::ns("encryption"); static const auto &xmlns_p = xlnt::constants::ns("encryption-password"); std::vector encryption_info; xlnt::detail::vector_ostreambuf encryption_info_buffer(encryption_info); std::ostream encryption_info_stream(&encryption_info_buffer); xml::serializer serializer(encryption_info_stream, "EncryptionInfo"); serializer.start_element(xmlns, "encryption"); const auto key_data = info.agile.key_data; serializer.start_element(xmlns, "keyData"); serializer.attribute("saltSize", key_data.salt_size); serializer.attribute("blockSize", key_data.block_size); serializer.attribute("keyBits", key_data.key_bits); serializer.attribute("hashSize", key_data.hash_size); serializer.attribute("cipherAlgorithm", key_data.cipher_algorithm); serializer.attribute("cipherChaining", key_data.cipher_chaining); serializer.attribute("hashAlgorithm", key_data.hash_algorithm); serializer.attribute("saltValue", xlnt::detail::encode_base64(key_data.salt_value)); serializer.end_element(xmlns, "keyData"); const auto data_integrity = info.agile.data_integrity; serializer.start_element(xmlns, "dataIntegrity"); serializer.attribute("encryptedHmacKey", xlnt::detail::encode_base64(data_integrity.hmac_key)); serializer.attribute("encryptedHmacValue", xlnt::detail::encode_base64(data_integrity.hmac_value)); serializer.end_element(xmlns, "dataIntegrity"); const auto key_encryptor = info.agile.key_encryptor; serializer.start_element(xmlns, "keyEncryptors"); serializer.start_element(xmlns, "keyEncryptor"); serializer.attribute("uri", ""); serializer.start_element(xmlns_p, "encryptedKey"); serializer.attribute("spinCount", key_encryptor.spin_count); serializer.attribute("saltSize", key_encryptor.salt_size); serializer.attribute("blockSize", key_encryptor.block_size); serializer.attribute("keyBits", key_encryptor.key_bits); serializer.attribute("hashSize", key_encryptor.hash_size); serializer.attribute("cipherAlgorithm", key_encryptor.cipher_algorithm); serializer.attribute("cipherChaining", key_encryptor.cipher_chaining); serializer.attribute("hashAlgorithm", key_encryptor.hash); serializer.attribute("saltValue", xlnt::detail::encode_base64(key_encryptor.salt_value)); serializer.attribute("encryptedVerifierHashInput", xlnt::detail::encode_base64(key_encryptor.verifier_hash_input)); serializer.attribute("encryptedVerifierHashValue", xlnt::detail::encode_base64(key_encryptor.verifier_hash_value)); serializer.attribute("encryptedKeyValue", xlnt::detail::encode_base64(key_encryptor.encrypted_key_value)); serializer.end_element(xmlns_p, "encryptedKey"); serializer.end_element(xmlns, "keyEncryptor"); serializer.end_element(xmlns, "keyEncryptors"); serializer.end_element(xmlns, "encryption"); return encryption_info; } std::vector write_standard_encryption_info( const encryption_info &/*info*/) { return {}; } std::vector encrypt_xlsx_agile( const encryption_info &/*info*/, const std::vector &/*plaintext*/) { return {}; } std::vector encrypt_xlsx_standard( const encryption_info &/*info*/, const std::vector &/*plaintext*/) { //auto key = info.calculate_key(); return {}; } std::vector encrypt_xlsx( const std::vector &plaintext, const std::u16string &password) { auto encryption_info = generate_encryption_info(password); xlnt::detail::compound_document document; document.add_stream(u"EncryptionInfo", encryption_info.is_agile ? write_agile_encryption_info(encryption_info) : write_standard_encryption_info(encryption_info)); document.add_stream(u"EncryptedPackage", encryption_info.is_agile ? encrypt_xlsx_agile(encryption_info, plaintext) : encrypt_xlsx_standard(encryption_info, plaintext)); return document.save(); } } // namespace namespace xlnt { namespace detail { std::vector XLNT_API encrypt_xlsx( const std::vector &plaintext, const std::string &password) { return ::encrypt_xlsx(plaintext, utf8_to_utf16(password)); } void xlsx_producer::write(std::ostream &destination, const std::string &password) { std::vector plaintext; vector_ostreambuf plaintext_buffer(plaintext); std::ostream decrypted_stream(&plaintext_buffer); write(decrypted_stream); const auto ciphertext = ::encrypt_xlsx(plaintext, utf8_to_utf16(password)); vector_istreambuf encrypted_buffer(ciphertext); destination << &encrypted_buffer; } } // namespace detail } // namespace xlnt