Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / oox / source / crypto / Standard2007Engine.cxx
blob8955101f6842e177ed783b5df5c4c403419e29a9
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 <rtl/digest.h>
17 #include <rtl/random.h>
19 #include <comphelper/hash.hxx>
21 namespace oox {
22 namespace core {
24 /* =========================================================================== */
25 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
26 /* =========================================================================== */
27 namespace
30 void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
32 rtlRandomPool aRandomPool = rtl_random_createPool();
33 rtl_random_getBytes(aRandomPool, aArray, aSize);
34 rtl_random_destroyPool(aRandomPool);
37 static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
39 } // end anonymous namespace
41 bool Standard2007Engine::generateVerifier()
43 // only support key of size 128 bit (16 byte)
44 if (mKey.size() != 16)
45 return false;
47 std::vector<sal_uInt8> verifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
48 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
50 lclRandomGenerateValues(verifier.data(), verifier.size());
52 std::vector<sal_uInt8> iv;
53 Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
54 if (aEncryptorVerifier.update(encryptedVerifier, verifier) != msfilter::ENCRYPTED_VERIFIER_LENGTH)
55 return false;
56 std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
58 mInfo.verifier.encryptedVerifierHashSize = msfilter::SHA1_HASH_LENGTH;
59 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
60 hash.resize(msfilter::SHA256_HASH_LENGTH, 0);
62 std::vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH, 0);
64 Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
65 aEncryptorHash.update(encryptedHash, hash, hash.size());
66 std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
68 return true;
71 bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
73 sal_uInt32 saltSize = mInfo.verifier.saltSize;
74 sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
75 const sal_uInt8* saltArray = mInfo.verifier.salt;
77 // Prepare initial data -> salt + password (in 16-bit chars)
78 std::vector<sal_uInt8> initialData(saltSize + passwordByteLength);
79 std::copy(saltArray, saltArray + saltSize, initialData.begin());
81 const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
83 std::copy(
84 passwordByteArray,
85 passwordByteArray + passwordByteLength,
86 initialData.begin() + saltSize);
88 // use "hash" vector for result of sha1 hashing
89 // calculate SHA1 hash of initialData
90 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(initialData.data(), initialData.size(), comphelper::HashType::SHA1);
92 // data = iterator (4bytes) + hash
93 std::vector<sal_uInt8> data(msfilter::SHA1_HASH_LENGTH + 4, 0);
95 for (sal_Int32 i = 0; i < 50000; ++i)
97 ByteOrderConverter::writeLittleEndian(data.data(), i);
98 std::copy(hash.begin(), hash.end(), data.begin() + 4);
99 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
101 std::copy(hash.begin(), hash.end(), data.begin() );
102 std::fill(data.begin() + msfilter::SHA1_HASH_LENGTH, data.end(), 0 );
104 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
106 // derive key
107 std::vector<sal_uInt8> buffer(64, 0x36);
108 for (size_t i = 0; i < hash.size(); ++i)
109 buffer[i] ^= hash[i];
111 hash = comphelper::Hash::calculateHash(buffer.data(), buffer.size(), comphelper::HashType::SHA1);
112 if (mKey.size() > hash.size())
113 return false;
114 std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
116 return true;
119 bool Standard2007Engine::generateEncryptionKey(const OUString& password)
121 mKey.clear();
122 mKey.resize(mInfo.header.keyBits / 8, 0);
123 if (mKey.empty())
124 return false;
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 rStream.writeMemory(&mInfo.verifier, sizeof(msfilter::EncryptionVerifierAES));
209 void Standard2007Engine::encrypt(BinaryXInputStream& aInputStream,
210 BinaryXOutputStream& aOutputStream)
212 std::vector<sal_uInt8> inputBuffer(1024);
213 std::vector<sal_uInt8> outputBuffer(1024);
215 sal_uInt32 inputLength;
216 sal_uInt32 outputLength;
218 std::vector<sal_uInt8> iv;
219 Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
221 while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
223 inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
224 outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
225 aOutputStream.writeMemory(outputBuffer.data(), outputLength);
229 } // namespace core
230 } // namespace oox
232 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */