Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / oox / source / crypto / Standard2007Engine.cxx
bloba045046c3bc4cbbaca7cc51c47f02fb3cfd0b6ad
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/random.h>
18 #include <comphelper/hash.hxx>
20 namespace oox::crypto {
22 /* =========================================================================== */
23 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
24 /* =========================================================================== */
25 namespace
28 void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
30 rtlRandomPool aRandomPool = rtl_random_createPool();
31 rtl_random_getBytes(aRandomPool, aArray, aSize);
32 rtl_random_destroyPool(aRandomPool);
35 constexpr OUStringLiteral lclCspName = u"Microsoft Enhanced RSA and AES Cryptographic Provider";
36 constexpr const sal_uInt32 AES128Size = 16;
38 } // end anonymous namespace
40 bool Standard2007Engine::generateVerifier()
42 // only support key of size 128 bit (16 byte)
43 if (mKey.size() != 16)
44 return false;
46 std::vector<sal_uInt8> verifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
47 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
49 lclRandomGenerateValues(verifier.data(), verifier.size());
51 std::vector<sal_uInt8> iv;
52 Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
53 if (aEncryptorVerifier.update(encryptedVerifier, verifier) != msfilter::ENCRYPTED_VERIFIER_LENGTH)
54 return false;
55 std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
57 mInfo.verifier.encryptedVerifierHashSize = comphelper::SHA1_HASH_LENGTH;
58 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
59 hash.resize(comphelper::SHA256_HASH_LENGTH, 0);
61 std::vector<sal_uInt8> encryptedHash(comphelper::SHA256_HASH_LENGTH, 0);
63 Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
64 aEncryptorHash.update(encryptedHash, hash, hash.size());
65 std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
67 return true;
70 bool Standard2007Engine::calculateEncryptionKey(std::u16string_view rPassword)
72 sal_uInt32 saltSize = mInfo.verifier.saltSize;
73 size_t passwordByteLength = rPassword.size() * 2;
74 const sal_uInt8* saltArray = mInfo.verifier.salt;
76 // Prepare initial data -> salt + password (in 16-bit chars)
77 std::vector<sal_uInt8> initialData(saltSize + passwordByteLength);
78 std::copy(saltArray, saltArray + saltSize, initialData.begin());
80 auto p = initialData.begin() + saltSize;
81 for (size_t i = 0; i != rPassword.size(); ++i) {
82 auto c = rPassword[i];
83 *p++ = c & 0xFF;
84 *p++ = c >> 8;
87 // use "hash" vector for result of sha1 hashing
88 // calculate SHA1 hash of initialData
89 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(initialData.data(), initialData.size(), comphelper::HashType::SHA1);
91 // data = iterator (4bytes) + hash
92 std::vector<sal_uInt8> data(comphelper::SHA1_HASH_LENGTH + 4, 0);
94 for (sal_Int32 i = 0; i < 50000; ++i)
96 ByteOrderConverter::writeLittleEndian(data.data(), i);
97 std::copy(hash.begin(), hash.end(), data.begin() + 4);
98 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
100 std::copy(hash.begin(), hash.end(), data.begin() );
101 std::fill(data.begin() + comphelper::SHA1_HASH_LENGTH, data.end(), 0 );
103 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
105 // derive key
106 std::vector<sal_uInt8> buffer(64, 0x36);
107 for (size_t i = 0; i < hash.size(); ++i)
108 buffer[i] ^= hash[i];
110 hash = comphelper::Hash::calculateHash(buffer.data(), buffer.size(), comphelper::HashType::SHA1);
111 if (mKey.size() > hash.size())
112 return false;
113 std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
115 return true;
118 bool Standard2007Engine::generateEncryptionKey(const OUString& password)
120 mKey.clear();
122 KeySize (4 bytes): An unsigned integer that specifies the number of bits in the encryption key.
123 MUST be a multiple of 8. MUST be one of the values in the following table:
124 Algorithm Value Comment
125 Any 0x00000000 Determined by Flags
126 RC4 0x00000028 – 0x00000080 (inclusive) 8-bit increments.
127 AES 0x00000080, 0x000000C0, 0x00000100 128, 192 or 256-bit
129 if (mInfo.header.keyBits > 8192) // should we strictly enforce the above 256 bit limit ?
130 return false;
131 mKey.resize(mInfo.header.keyBits / 8, 0);
132 if (mKey.empty())
133 return false;
135 calculateEncryptionKey(password);
137 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
138 std::copy(
139 mInfo.verifier.encryptedVerifier,
140 mInfo.verifier.encryptedVerifier + msfilter::ENCRYPTED_VERIFIER_LENGTH,
141 encryptedVerifier.begin());
143 std::vector<sal_uInt8> encryptedHash(comphelper::SHA256_HASH_LENGTH);
144 std::copy(
145 mInfo.verifier.encryptedVerifierHash,
146 mInfo.verifier.encryptedVerifierHash + comphelper::SHA256_HASH_LENGTH,
147 encryptedHash.begin());
149 std::vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
150 Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
152 std::vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
153 Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
155 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
157 return std::equal(hash.begin(), hash.end(), verifierHash.begin());
160 bool Standard2007Engine::decrypt(BinaryXInputStream& aInputStream,
161 BinaryXOutputStream& aOutputStream)
163 sal_uInt32 totalSize = aInputStream.readuInt32(); // Document unencrypted size - 4 bytes
164 aInputStream.skip(4); // Reserved 4 Bytes
166 std::vector<sal_uInt8> iv;
167 Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
168 std::vector<sal_uInt8> inputBuffer (4096);
169 std::vector<sal_uInt8> outputBuffer(4096);
170 sal_uInt32 inputLength;
171 sal_uInt32 outputLength;
172 sal_uInt32 remaining = totalSize;
174 while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
176 outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
177 sal_uInt32 writeLength = std::min(outputLength, remaining);
178 aOutputStream.writeMemory(outputBuffer.data(), writeLength);
179 remaining -= outputLength;
181 return true;
184 bool Standard2007Engine::checkDataIntegrity()
186 return true;
189 bool Standard2007Engine::setupEncryption(OUString const & password)
191 mInfo.header.flags = msfilter::ENCRYPTINFO_AES | msfilter::ENCRYPTINFO_CRYPTOAPI;
192 mInfo.header.algId = msfilter::ENCRYPT_ALGO_AES128;
193 mInfo.header.algIdHash = msfilter::ENCRYPT_HASH_SHA1;
194 mInfo.header.keyBits = msfilter::ENCRYPT_KEY_SIZE_AES_128;
195 mInfo.header.providedType = msfilter::ENCRYPT_PROVIDER_TYPE_AES;
197 lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
198 const sal_Int32 keyLength = mInfo.header.keyBits / 8;
200 mKey.clear();
201 mKey.resize(keyLength, 0);
203 if (!calculateEncryptionKey(password))
204 return false;
206 if (!generateVerifier())
207 return false;
209 return true;
212 void Standard2007Engine::writeEncryptionInfo(BinaryXOutputStream& rStream)
214 rStream.WriteUInt32(msfilter::VERSION_INFO_2007_FORMAT);
216 sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
218 sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(msfilter::EncryptionStandardHeader));
220 rStream.WriteUInt32(mInfo.header.flags);
221 sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
222 rStream.WriteUInt32(headerSize);
224 rStream.WriteUInt32(mInfo.header.flags);
225 rStream.WriteUInt32(mInfo.header.sizeExtra);
226 rStream.WriteUInt32(mInfo.header.algId);
227 rStream.WriteUInt32(mInfo.header.algIdHash);
228 rStream.WriteUInt32(mInfo.header.keyBits);
229 rStream.WriteUInt32(mInfo.header.providedType);
230 rStream.WriteUInt32(mInfo.header.reserved1);
231 rStream.WriteUInt32(mInfo.header.reserved2);
232 rStream.writeUnicodeArray(lclCspName);
233 rStream.WriteUInt16(0);
235 rStream.WriteUInt32(mInfo.verifier.saltSize);
236 rStream.writeMemory(&mInfo.verifier.salt, sizeof mInfo.verifier.salt);
237 rStream.writeMemory(&mInfo.verifier.encryptedVerifier, sizeof mInfo.verifier.encryptedVerifier);
238 rStream.WriteUInt32(mInfo.verifier.encryptedVerifierHashSize);
239 rStream.writeMemory(
240 &mInfo.verifier.encryptedVerifierHash, sizeof mInfo.verifier.encryptedVerifierHash);
243 void Standard2007Engine::encrypt(const css::uno::Reference<css::io::XInputStream> & rxInputStream,
244 css::uno::Reference<css::io::XOutputStream> & rxOutputStream,
245 sal_uInt32 nSize)
247 if (mKey.empty())
248 return;
250 BinaryXOutputStream aBinaryOutputStream(rxOutputStream, false);
251 BinaryXInputStream aBinaryInputStream(rxInputStream, false);
253 aBinaryOutputStream.WriteUInt32(nSize); // size
254 aBinaryOutputStream.WriteUInt32(0U); // reserved
256 std::vector<sal_uInt8> inputBuffer(1024);
257 std::vector<sal_uInt8> outputBuffer(1024);
259 sal_uInt32 inputLength;
260 sal_uInt32 outputLength;
262 std::vector<sal_uInt8> iv;
263 Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
265 while ((inputLength = aBinaryInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
267 // increase size to multiple of 16 (size of mKey) if necessary
268 inputLength = inputLength % AES128Size == 0 ?
269 inputLength : roundUp(inputLength, AES128Size);
270 outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
271 aBinaryOutputStream.writeMemory(outputBuffer.data(), outputLength);
275 bool Standard2007Engine::readEncryptionInfo(css::uno::Reference<css::io::XInputStream> & rxInputStream)
277 BinaryXInputStream aBinaryStream(rxInputStream, false);
279 mInfo.header.flags = aBinaryStream.readuInt32();
280 if (getFlag(mInfo.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
281 return false;
283 sal_uInt32 nHeaderSize = aBinaryStream.readuInt32();
285 sal_uInt32 actualHeaderSize = sizeof(mInfo.header);
287 if (nHeaderSize < actualHeaderSize)
288 return false;
290 mInfo.header.flags = aBinaryStream.readuInt32();
291 mInfo.header.sizeExtra = aBinaryStream.readuInt32();
292 mInfo.header.algId = aBinaryStream.readuInt32();
293 mInfo.header.algIdHash = aBinaryStream.readuInt32();
294 mInfo.header.keyBits = aBinaryStream.readuInt32();
295 mInfo.header.providedType = aBinaryStream.readuInt32();
296 mInfo.header.reserved1 = aBinaryStream.readuInt32();
297 mInfo.header.reserved2 = aBinaryStream.readuInt32();
299 aBinaryStream.skip(nHeaderSize - actualHeaderSize);
301 mInfo.verifier.saltSize = aBinaryStream.readuInt32();
302 aBinaryStream.readArray(mInfo.verifier.salt, SAL_N_ELEMENTS(mInfo.verifier.salt));
303 aBinaryStream.readArray(mInfo.verifier.encryptedVerifier, SAL_N_ELEMENTS(mInfo.verifier.encryptedVerifier));
304 mInfo.verifier.encryptedVerifierHashSize = aBinaryStream.readuInt32();
305 aBinaryStream.readArray(mInfo.verifier.encryptedVerifierHash, SAL_N_ELEMENTS(mInfo.verifier.encryptedVerifierHash));
307 if (mInfo.verifier.saltSize != 16)
308 return false;
310 // check flags and algorithm IDs, required are AES128 and SHA-1
311 if (!getFlag(mInfo.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
312 return false;
314 if (!getFlag(mInfo.header.flags, msfilter::ENCRYPTINFO_AES))
315 return false;
317 // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
318 if (mInfo.header.algId != 0 && mInfo.header.algId != msfilter::ENCRYPT_ALGO_AES128)
319 return false;
321 // hash algorithm ID 0 defaults to SHA-1 too
322 if (mInfo.header.algIdHash != 0 && mInfo.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
323 return false;
325 if (mInfo.verifier.encryptedVerifierHashSize != 20)
326 return false;
328 return !aBinaryStream.isEof();
331 } // namespace oox::crypto
333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */