/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ #include #include #include #include #include namespace oox { namespace core { namespace { const sal_uInt32 constSegmentLength = 4096; bool hashCalc(std::vector& output, std::vector& input, const OUString& sAlgorithm ) { if (sAlgorithm == "SHA1") { std::vector out = comphelper::Hash::calculateHash(input.data(), input.size(), comphelper::HashType::SHA1); output = out; return true; } else if (sAlgorithm == "SHA512") { std::vector out = comphelper::Hash::calculateHash(input.data(), input.size(), comphelper::HashType::SHA512); output = out; return true; } return false; } } // namespace Crypto::CryptoType AgileEngine::cryptoType(const AgileEncryptionInfo& rInfo) { if (rInfo.keyBits == 128 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC") return Crypto::AES_128_CBC; else if (rInfo.keyBits == 256 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC") return Crypto::AES_256_CBC; return Crypto::UNKNOWN; } void AgileEngine::calculateBlock( std::vector const & rBlock, std::vector& rHashFinal, std::vector& rInput, std::vector& rOutput) { std::vector hash(mInfo.hashSize, 0); std::vector dataFinal(mInfo.hashSize + rBlock.size(), 0); std::copy(rHashFinal.begin(), rHashFinal.end(), dataFinal.begin()); std::copy(rBlock.begin(), rBlock.end(), dataFinal.begin() + mInfo.hashSize); hashCalc(hash, dataFinal, mInfo.hashAlgorithm); sal_Int32 keySize = mInfo.keyBits / 8; std::vector key(keySize, 0); std::copy(hash.begin(), hash.begin() + keySize, key.begin()); Decrypt aDecryptor(key, mInfo.saltValue, cryptoType(mInfo)); aDecryptor.update(rOutput, rInput); } void AgileEngine::calculateHashFinal(const OUString& rPassword, std::vector& aHashFinal) { aHashFinal = comphelper::DocPasswordHelper::GetOoxHashAsVector( rPassword, mInfo.saltValue, mInfo.spinCount, comphelper::Hash::IterCount::PREPEND, mInfo.hashAlgorithm); } bool AgileEngine::generateEncryptionKey(const OUString& rPassword) { static const std::vector constBlock1{ 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 }; static const std::vector constBlock2{ 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e }; static const std::vector constBlock3{ 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 }; mKey.clear(); mKey.resize(mInfo.keyBits / 8, 0); std::vector hashFinal(mInfo.hashSize, 0); calculateHashFinal(rPassword, hashFinal); std::vector& encryptedHashInput = mInfo.encryptedVerifierHashInput; std::vector hashInput(mInfo.saltSize, 0); calculateBlock(constBlock1, hashFinal, encryptedHashInput, hashInput); std::vector& encryptedHashValue = mInfo.encryptedVerifierHashValue; std::vector hashValue(encryptedHashValue.size(), 0); calculateBlock(constBlock2, hashFinal, encryptedHashValue, hashValue); std::vector hash(mInfo.hashSize, 0); hashCalc(hash, hashInput, mInfo.hashAlgorithm); if (hash.size() <= hashValue.size() && std::equal(hash.begin(), hash.end(), hashValue.begin())) { std::vector& encryptedKeyValue = mInfo.encryptedKeyValue; calculateBlock(constBlock3, hashFinal, encryptedKeyValue, mKey); return true; } return false; } bool AgileEngine::decrypt(BinaryXInputStream& aInputStream, BinaryXOutputStream& aOutputStream) { sal_uInt32 totalSize = aInputStream.readuInt32(); // Document unencrypted size - 4 bytes aInputStream.skip(4); // Reserved 4 Bytes std::vector& keyDataSalt = mInfo.keyDataSalt; sal_uInt32 saltSize = mInfo.saltSize; sal_uInt32 keySize = mInfo.keyBits / 8; sal_uInt32 segment = 0; std::vector saltWithBlockKey(saltSize + sizeof(segment), 0); std::copy(keyDataSalt.begin(), keyDataSalt.end(), saltWithBlockKey.begin()); std::vector hash(mInfo.hashSize, 0); std::vector iv(keySize, 0); std::vector inputBuffer(constSegmentLength); std::vector outputBuffer(constSegmentLength); sal_uInt32 inputLength; sal_uInt32 outputLength; sal_uInt32 remaining = totalSize; while ((inputLength = aInputStream.readMemory(inputBuffer.data(), constSegmentLength)) > 0) { sal_uInt8* segmentBegin = reinterpret_cast(&segment); sal_uInt8* segmentEnd = segmentBegin + sizeof(segment); std::copy(segmentBegin, segmentEnd, saltWithBlockKey.begin() + saltSize); hashCalc(hash, saltWithBlockKey, mInfo.hashAlgorithm); // Only if hash > keySize std::copy(hash.begin(), hash.begin() + keySize, iv.begin()); Decrypt aDecryptor(mKey, iv, AgileEngine::cryptoType(mInfo)); outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength); sal_uInt32 writeLength = std::min(outputLength, remaining); aOutputStream.writeMemory(outputBuffer.data(), writeLength); remaining -= outputLength; segment++; } return true; } void AgileEngine::writeEncryptionInfo( const OUString& /*aPassword*/, BinaryXOutputStream& /*rStream*/) { // Agile encrypting is not supported for now } void AgileEngine::encrypt( BinaryXInputStream& /*aInputStream*/, BinaryXOutputStream& /*aOutputStream*/) { // Agile encrypting is not supported for now } } // namespace core } // namespace oox /* vim:set shiftwidth=4 softtabstop=4 expandtab: */