Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / oox / source / crypto / Standard2007Engine.cxx
blobb9c259fa02acdff92a7c0514a4f6cd954bb324c7
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/Standard2007Engine.hxx"
13 #include <oox/crypto/CryptTools.hxx>
14 #include <oox/helper/binaryinputstream.hxx>
15 #include <oox/helper/binaryoutputstream.hxx>
16 #include <osl/time.h>
17 #include <rtl/digest.h>
18 #include <rtl/random.h>
20 #include <comphelper/hash.hxx>
22 namespace oox {
23 namespace core {
25 /* =========================================================================== */
26 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
27 /* =========================================================================== */
28 namespace
31 void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
33 TimeValue aTime;
34 osl_getSystemTime(&aTime);
35 rtlRandomPool aRandomPool = rtl_random_createPool();
36 rtl_random_addBytes(aRandomPool, &aTime, 8);
37 rtl_random_getBytes(aRandomPool, aArray, aSize);
38 rtl_random_destroyPool(aRandomPool);
41 static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
43 } // end anonymous namespace
45 bool Standard2007Engine::generateVerifier()
47 // only support key of size 128 bit (16 byte)
48 if (mKey.size() != 16)
49 return false;
51 std::vector<sal_uInt8> verifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
52 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
54 lclRandomGenerateValues(verifier.data(), verifier.size());
56 std::vector<sal_uInt8> iv;
57 Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
58 if (aEncryptorVerifier.update(encryptedVerifier, verifier) != msfilter::ENCRYPTED_VERIFIER_LENGTH)
59 return false;
60 std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
62 mInfo.verifier.encryptedVerifierHashSize = msfilter::SHA1_HASH_LENGTH;
63 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
64 hash.resize(msfilter::SHA256_HASH_LENGTH, 0);
66 std::vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH, 0);
68 Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
69 aEncryptorHash.update(encryptedHash, hash, hash.size());
70 std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
72 return true;
75 bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
77 sal_uInt32 saltSize = mInfo.verifier.saltSize;
78 sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
79 const sal_uInt8* saltArray = mInfo.verifier.salt;
81 // Prepare initial data -> salt + password (in 16-bit chars)
82 std::vector<sal_uInt8> initialData(saltSize + passwordByteLength);
83 std::copy(saltArray, saltArray + saltSize, initialData.begin());
85 const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
87 std::copy(
88 passwordByteArray,
89 passwordByteArray + passwordByteLength,
90 initialData.begin() + saltSize);
92 // use "hash" vector for result of sha1 hashing
93 // calculate SHA1 hash of initialData
94 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(initialData.data(), initialData.size(), comphelper::HashType::SHA1);
96 // data = iterator (4bytes) + hash
97 std::vector<sal_uInt8> data(msfilter::SHA1_HASH_LENGTH + 4, 0);
99 for (sal_Int32 i = 0; i < 50000; ++i)
101 ByteOrderConverter::writeLittleEndian(data.data(), i);
102 std::copy(hash.begin(), hash.end(), data.begin() + 4);
103 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
105 std::copy(hash.begin(), hash.end(), data.begin() );
106 std::fill(data.begin() + msfilter::SHA1_HASH_LENGTH, data.end(), 0 );
108 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
110 // derive key
111 std::vector<sal_uInt8> buffer(64, 0x36);
112 for (size_t i = 0; i < hash.size(); ++i)
113 buffer[i] ^= hash[i];
115 hash = comphelper::Hash::calculateHash(buffer.data(), buffer.size(), comphelper::HashType::SHA1);
116 std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
118 return true;
121 bool Standard2007Engine::generateEncryptionKey(const OUString& password)
123 mKey.clear();
124 mKey.resize(mInfo.header.keyBits / 8, 0);
126 calculateEncryptionKey(password);
128 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
129 std::copy(
130 mInfo.verifier.encryptedVerifier,
131 mInfo.verifier.encryptedVerifier + msfilter::ENCRYPTED_VERIFIER_LENGTH,
132 encryptedVerifier.begin());
134 std::vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH);
135 std::copy(
136 mInfo.verifier.encryptedVerifierHash,
137 mInfo.verifier.encryptedVerifierHash + msfilter::SHA256_HASH_LENGTH,
138 encryptedHash.begin());
140 std::vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
141 Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
143 std::vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
144 Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
146 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
148 return std::equal(hash.begin(), hash.end(), verifierHash.begin());
151 bool Standard2007Engine::decrypt(BinaryXInputStream& aInputStream,
152 BinaryXOutputStream& aOutputStream)
154 aInputStream.skip(4); // Document unencrypted size - 4 bytes
155 aInputStream.skip(4); // Reserved 4 Bytes
157 std::vector<sal_uInt8> iv;
158 Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
159 std::vector<sal_uInt8> inputBuffer (4096);
160 std::vector<sal_uInt8> outputBuffer(4096);
161 sal_uInt32 inputLength;
162 sal_uInt32 outputLength;
164 while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
166 outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
167 aOutputStream.writeMemory(outputBuffer.data(), outputLength);
169 return true;
172 void Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
174 mInfo.header.flags = msfilter::ENCRYPTINFO_AES | msfilter::ENCRYPTINFO_CRYPTOAPI;
175 mInfo.header.algId = msfilter::ENCRYPT_ALGO_AES128;
176 mInfo.header.algIdHash = msfilter::ENCRYPT_HASH_SHA1;
177 mInfo.header.keyBits = msfilter::ENCRYPT_KEY_SIZE_AES_128;
178 mInfo.header.providedType = msfilter::ENCRYPT_PROVIDER_TYPE_AES;
180 lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
181 const sal_Int32 keyLength = mInfo.header.keyBits / 8;
183 mKey.clear();
184 mKey.resize(keyLength, 0);
186 if (!calculateEncryptionKey(password))
187 return;
189 if (!generateVerifier())
190 return;
192 rStream.WriteUInt32(msfilter::VERSION_INFO_2007_FORMAT);
194 sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
196 sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(msfilter::EncryptionStandardHeader));
198 rStream.WriteUInt32(mInfo.header.flags);
199 sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
200 rStream.WriteUInt32(headerSize);
202 rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
203 rStream.writeUnicodeArray(lclCspName);
204 rStream.WriteUInt16(0);
206 sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(msfilter::EncryptionVerifierAES));
207 rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
210 void Standard2007Engine::encrypt(BinaryXInputStream& aInputStream,
211 BinaryXOutputStream& aOutputStream)
213 std::vector<sal_uInt8> inputBuffer(1024);
214 std::vector<sal_uInt8> outputBuffer(1024);
216 sal_uInt32 inputLength;
217 sal_uInt32 outputLength;
219 std::vector<sal_uInt8> iv;
220 Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
222 while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
224 inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
225 outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
226 aOutputStream.writeMemory(outputBuffer.data(), outputLength);
230 } // namespace core
231 } // namespace oox
233 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */