Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / oox / source / crypto / AgileEngine.cxx
blob72539509c965769331ae0273a06be10436fb13b8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include "oox/crypto/AgileEngine.hxx"
13 #include <oox/helper/binaryinputstream.hxx>
14 #include <oox/helper/binaryoutputstream.hxx>
16 #include <comphelper/hash.hxx>
18 namespace oox {
19 namespace core {
21 namespace {
23 const sal_uInt32 constSegmentLength = 4096;
25 bool hashCalc(std::vector<sal_uInt8>& output,
26 std::vector<sal_uInt8>& input,
27 const OUString& sAlgorithm )
29 if (sAlgorithm == "SHA1")
31 std::vector<unsigned char> out = comphelper::Hash::calculateHash(input.data(), input.size(), comphelper::HashType::SHA1);
32 output = out;
33 return true;
35 else if (sAlgorithm == "SHA512")
37 std::vector<unsigned char> out = comphelper::Hash::calculateHash(input.data(), input.size(), comphelper::HashType::SHA512);
38 output = out;
39 return true;
41 return false;
44 } // namespace
46 Crypto::CryptoType AgileEngine::cryptoType(const AgileEncryptionInfo& rInfo)
48 if (rInfo.keyBits == 128 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
49 return Crypto::AES_128_CBC;
50 else if (rInfo.keyBits == 256 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
51 return Crypto::AES_256_CBC;
52 return Crypto::UNKNOWN;
55 void AgileEngine::calculateBlock(
56 std::vector<sal_uInt8> const & rBlock,
57 std::vector<sal_uInt8>& rHashFinal,
58 std::vector<sal_uInt8>& rInput,
59 std::vector<sal_uInt8>& rOutput)
61 std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
62 std::vector<sal_uInt8> dataFinal(mInfo.hashSize + rBlock.size(), 0);
63 std::copy(rHashFinal.begin(), rHashFinal.end(), dataFinal.begin());
64 std::copy(rBlock.begin(), rBlock.end(), dataFinal.begin() + mInfo.hashSize);
66 hashCalc(hash, dataFinal, mInfo.hashAlgorithm);
68 sal_Int32 keySize = mInfo.keyBits / 8;
69 std::vector<sal_uInt8> key(keySize, 0);
71 std::copy(hash.begin(), hash.begin() + keySize, key.begin());
73 Decrypt aDecryptor(key, mInfo.saltValue, cryptoType(mInfo));
74 aDecryptor.update(rOutput, rInput);
77 void AgileEngine::calculateHashFinal(const OUString& rPassword, std::vector<sal_uInt8>& aHashFinal)
79 sal_Int32 saltSize = mInfo.saltSize;
80 std::vector<sal_uInt8>& salt = mInfo.saltValue;
82 sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
84 std::vector<sal_uInt8> initialData(saltSize + passwordByteLength);
85 std::copy(salt.begin(), salt.end(), initialData.begin());
87 const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
89 std::copy(
90 passwordByteArray,
91 passwordByteArray + passwordByteLength,
92 initialData.begin() + saltSize);
94 std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
96 hashCalc(hash, initialData, mInfo.hashAlgorithm);
98 std::vector<sal_uInt8> data(mInfo.hashSize + 4, 0);
100 for (sal_Int32 i = 0; i < mInfo.spinCount; i++)
102 ByteOrderConverter::writeLittleEndian(data.data(), i);
103 std::copy(hash.begin(), hash.end(), data.begin() + 4);
104 hashCalc(hash, data, mInfo.hashAlgorithm);
107 std::copy(hash.begin(), hash.end(), aHashFinal.begin());
110 bool AgileEngine::generateEncryptionKey(const OUString& rPassword)
112 static const std::vector<sal_uInt8> constBlock1{ 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
113 static const std::vector<sal_uInt8> constBlock2{ 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
114 static const std::vector<sal_uInt8> constBlock3{ 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
116 mKey.clear();
117 mKey.resize(mInfo.keyBits / 8, 0);
119 std::vector<sal_uInt8> hashFinal(mInfo.hashSize, 0);
120 calculateHashFinal(rPassword, hashFinal);
122 std::vector<sal_uInt8>& encryptedHashInput = mInfo.encryptedVerifierHashInput;
123 std::vector<sal_uInt8> hashInput(mInfo.saltSize, 0);
124 calculateBlock(constBlock1, hashFinal, encryptedHashInput, hashInput);
126 std::vector<sal_uInt8>& encryptedHashValue = mInfo.encryptedVerifierHashValue;
127 std::vector<sal_uInt8> hashValue(encryptedHashValue.size(), 0);
128 calculateBlock(constBlock2, hashFinal, encryptedHashValue, hashValue);
130 std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
131 hashCalc(hash, hashInput, mInfo.hashAlgorithm);
133 if (std::equal (hash.begin(), hash.end(), hashValue.begin()) )
135 std::vector<sal_uInt8>& encryptedKeyValue = mInfo.encryptedKeyValue;
136 calculateBlock(constBlock3, hashFinal, encryptedKeyValue, mKey);
137 return true;
140 return false;
143 bool AgileEngine::decrypt(BinaryXInputStream& aInputStream,
144 BinaryXOutputStream& aOutputStream)
146 sal_uInt32 totalSize = aInputStream.readuInt32(); // Document unencrypted size - 4 bytes
147 aInputStream.skip(4); // Reserved 4 Bytes
149 std::vector<sal_uInt8>& keyDataSalt = mInfo.keyDataSalt;
151 sal_uInt32 saltSize = mInfo.saltSize;
152 sal_uInt32 keySize = mInfo.keyBits / 8;
154 sal_uInt32 segment = 0;
156 std::vector<sal_uInt8> saltWithBlockKey(saltSize + sizeof(segment), 0);
157 std::copy(keyDataSalt.begin(), keyDataSalt.end(), saltWithBlockKey.begin());
159 std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
160 std::vector<sal_uInt8> iv(keySize, 0);
162 std::vector<sal_uInt8> inputBuffer(constSegmentLength);
163 std::vector<sal_uInt8> outputBuffer(constSegmentLength);
164 sal_uInt32 inputLength;
165 sal_uInt32 outputLength;
166 sal_uInt32 remaining = totalSize;
168 while ((inputLength = aInputStream.readMemory(inputBuffer.data(), constSegmentLength)) > 0)
170 sal_uInt8* segmentBegin = reinterpret_cast<sal_uInt8*>(&segment);
171 sal_uInt8* segmentEnd = segmentBegin + sizeof(segment);
172 std::copy(segmentBegin, segmentEnd, saltWithBlockKey.begin() + saltSize);
174 hashCalc(hash, saltWithBlockKey, mInfo.hashAlgorithm);
176 // Only if hash > keySize
177 std::copy(hash.begin(), hash.begin() + keySize, iv.begin());
179 Decrypt aDecryptor(mKey, iv, AgileEngine::cryptoType(mInfo));
180 outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
182 sal_uInt32 writeLength = outputLength > remaining ? remaining : outputLength;
183 aOutputStream.writeMemory(outputBuffer.data(), writeLength);
185 remaining -= outputLength;
186 segment++;
189 return true;
192 void AgileEngine::writeEncryptionInfo(
193 const OUString& /*aPassword*/,
194 BinaryXOutputStream& /*rStream*/)
196 // Agile encrypting is not supported for now
199 void AgileEngine::encrypt(
200 BinaryXInputStream& /*aInputStream*/,
201 BinaryXOutputStream& /*aOutputStream*/)
203 // Agile encrypting is not supported for now
206 } // namespace core
207 } // namespace oox
209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */