bump product version to 6.3.0.0.beta1
[LibreOffice.git] / oox / source / crypto / Standard2007Engine.cxx
blob38c4e03baf15dc8a32e17b928c391f9eb6361ce2
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";
38 constexpr const sal_uInt32 AES128Size = 16;
40 } // end anonymous namespace
42 bool Standard2007Engine::generateVerifier()
44 // only support key of size 128 bit (16 byte)
45 if (mKey.size() != 16)
46 return false;
48 std::vector<sal_uInt8> verifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
49 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
51 lclRandomGenerateValues(verifier.data(), verifier.size());
53 std::vector<sal_uInt8> iv;
54 Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
55 if (aEncryptorVerifier.update(encryptedVerifier, verifier) != msfilter::ENCRYPTED_VERIFIER_LENGTH)
56 return false;
57 std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
59 mInfo.verifier.encryptedVerifierHashSize = msfilter::SHA1_HASH_LENGTH;
60 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
61 hash.resize(msfilter::SHA256_HASH_LENGTH, 0);
63 std::vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH, 0);
65 Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
66 aEncryptorHash.update(encryptedHash, hash, hash.size());
67 std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
69 return true;
72 bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
74 sal_uInt32 saltSize = mInfo.verifier.saltSize;
75 sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
76 const sal_uInt8* saltArray = mInfo.verifier.salt;
78 // Prepare initial data -> salt + password (in 16-bit chars)
79 std::vector<sal_uInt8> initialData(saltSize + passwordByteLength);
80 std::copy(saltArray, saltArray + saltSize, initialData.begin());
82 const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
84 std::copy(
85 passwordByteArray,
86 passwordByteArray + passwordByteLength,
87 initialData.begin() + saltSize);
89 // use "hash" vector for result of sha1 hashing
90 // calculate SHA1 hash of initialData
91 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(initialData.data(), initialData.size(), comphelper::HashType::SHA1);
93 // data = iterator (4bytes) + hash
94 std::vector<sal_uInt8> data(msfilter::SHA1_HASH_LENGTH + 4, 0);
96 for (sal_Int32 i = 0; i < 50000; ++i)
98 ByteOrderConverter::writeLittleEndian(data.data(), i);
99 std::copy(hash.begin(), hash.end(), data.begin() + 4);
100 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
102 std::copy(hash.begin(), hash.end(), data.begin() );
103 std::fill(data.begin() + msfilter::SHA1_HASH_LENGTH, data.end(), 0 );
105 hash = comphelper::Hash::calculateHash(data.data(), data.size(), comphelper::HashType::SHA1);
107 // derive key
108 std::vector<sal_uInt8> buffer(64, 0x36);
109 for (size_t i = 0; i < hash.size(); ++i)
110 buffer[i] ^= hash[i];
112 hash = comphelper::Hash::calculateHash(buffer.data(), buffer.size(), comphelper::HashType::SHA1);
113 if (mKey.size() > hash.size())
114 return false;
115 std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
117 return true;
120 bool Standard2007Engine::generateEncryptionKey(const OUString& password)
122 mKey.clear();
124 KeySize (4 bytes): An unsigned integer that specifies the number of bits in the encryption key.
125 MUST be a multiple of 8. MUST be one of the values in the following table:
126 Algorithm Value Comment
127 Any 0x00000000 Determined by Flags
128 RC4 0x00000028 – 0x00000080 (inclusive) 8-bit increments.
129 AES 0x00000080, 0x000000C0, 0x00000100 128, 192 or 256-bit
131 if (mInfo.header.keyBits > 8192) // should we strictly enforce the above 256 bit limit ?
132 return false;
133 mKey.resize(mInfo.header.keyBits / 8, 0);
134 if (mKey.empty())
135 return false;
137 calculateEncryptionKey(password);
139 std::vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
140 std::copy(
141 mInfo.verifier.encryptedVerifier,
142 mInfo.verifier.encryptedVerifier + msfilter::ENCRYPTED_VERIFIER_LENGTH,
143 encryptedVerifier.begin());
145 std::vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH);
146 std::copy(
147 mInfo.verifier.encryptedVerifierHash,
148 mInfo.verifier.encryptedVerifierHash + msfilter::SHA256_HASH_LENGTH,
149 encryptedHash.begin());
151 std::vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
152 Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
154 std::vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
155 Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
157 std::vector<sal_uInt8> hash = comphelper::Hash::calculateHash(verifier.data(), verifier.size(), comphelper::HashType::SHA1);
159 return std::equal(hash.begin(), hash.end(), verifierHash.begin());
162 bool Standard2007Engine::decrypt(BinaryXInputStream& aInputStream,
163 BinaryXOutputStream& aOutputStream)
165 sal_uInt32 totalSize = aInputStream.readuInt32(); // Document unencrypted size - 4 bytes
166 aInputStream.skip(4); // Reserved 4 Bytes
168 std::vector<sal_uInt8> iv;
169 Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
170 std::vector<sal_uInt8> inputBuffer (4096);
171 std::vector<sal_uInt8> outputBuffer(4096);
172 sal_uInt32 inputLength;
173 sal_uInt32 outputLength;
174 sal_uInt32 remaining = totalSize;
176 while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
178 outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
179 sal_uInt32 writeLength = std::min(outputLength, remaining);
180 aOutputStream.writeMemory(outputBuffer.data(), writeLength);
181 remaining -= outputLength;
183 return true;
186 bool Standard2007Engine::checkDataIntegrity()
188 return true;
191 bool Standard2007Engine::setupEncryption(OUString const & password)
193 mInfo.header.flags = msfilter::ENCRYPTINFO_AES | msfilter::ENCRYPTINFO_CRYPTOAPI;
194 mInfo.header.algId = msfilter::ENCRYPT_ALGO_AES128;
195 mInfo.header.algIdHash = msfilter::ENCRYPT_HASH_SHA1;
196 mInfo.header.keyBits = msfilter::ENCRYPT_KEY_SIZE_AES_128;
197 mInfo.header.providedType = msfilter::ENCRYPT_PROVIDER_TYPE_AES;
199 lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
200 const sal_Int32 keyLength = mInfo.header.keyBits / 8;
202 mKey.clear();
203 mKey.resize(keyLength, 0);
205 if (!calculateEncryptionKey(password))
206 return false;
208 if (!generateVerifier())
209 return false;
211 return true;
214 void Standard2007Engine::writeEncryptionInfo(BinaryXOutputStream& rStream)
216 rStream.WriteUInt32(msfilter::VERSION_INFO_2007_FORMAT);
218 sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
220 sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(msfilter::EncryptionStandardHeader));
222 rStream.WriteUInt32(mInfo.header.flags);
223 sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
224 rStream.WriteUInt32(headerSize);
226 rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
227 rStream.writeUnicodeArray(lclCspName);
228 rStream.WriteUInt16(0);
230 rStream.writeMemory(&mInfo.verifier, sizeof(msfilter::EncryptionVerifierAES));
233 void Standard2007Engine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputStream,
234 css::uno::Reference<css::io::XOutputStream> & rxOutputStream,
235 sal_uInt32 nSize)
237 if (mKey.empty())
238 return;
240 BinaryXOutputStream aBinaryOutputStream(rxOutputStream, false);
241 BinaryXInputStream aBinaryInputStream(rxInputStream, false);
243 aBinaryOutputStream.WriteUInt32(nSize); // size
244 aBinaryOutputStream.WriteUInt32(0U); // reserved
246 std::vector<sal_uInt8> inputBuffer(1024);
247 std::vector<sal_uInt8> outputBuffer(1024);
249 sal_uInt32 inputLength;
250 sal_uInt32 outputLength;
252 std::vector<sal_uInt8> iv;
253 Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
255 while ((inputLength = aBinaryInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
257 // increase size to multiple of 16 (size of mKey) if necessary
258 inputLength = inputLength % AES128Size == 0 ?
259 inputLength : roundUp(inputLength, AES128Size);
260 outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
261 aBinaryOutputStream.writeMemory(outputBuffer.data(), outputLength);
265 bool Standard2007Engine::readEncryptionInfo(css::uno::Reference<css::io::XInputStream> & rxInputStream)
267 BinaryXInputStream aBinaryStream(rxInputStream, false);
269 mInfo.header.flags = aBinaryStream.readuInt32();
270 if (getFlag(mInfo.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
271 return false;
273 sal_uInt32 nHeaderSize = aBinaryStream.readuInt32();
275 sal_uInt32 actualHeaderSize = sizeof(mInfo.header);
277 if (nHeaderSize < actualHeaderSize)
278 return false;
280 mInfo.header.flags = aBinaryStream.readuInt32();
281 mInfo.header.sizeExtra = aBinaryStream.readuInt32();
282 mInfo.header.algId = aBinaryStream.readuInt32();
283 mInfo.header.algIdHash = aBinaryStream.readuInt32();
284 mInfo.header.keyBits = aBinaryStream.readuInt32();
285 mInfo.header.providedType = aBinaryStream.readuInt32();
286 mInfo.header.reserved1 = aBinaryStream.readuInt32();
287 mInfo.header.reserved2 = aBinaryStream.readuInt32();
289 aBinaryStream.skip(nHeaderSize - actualHeaderSize);
291 mInfo.verifier.saltSize = aBinaryStream.readuInt32();
292 aBinaryStream.readArray(mInfo.verifier.salt, SAL_N_ELEMENTS(mInfo.verifier.salt));
293 aBinaryStream.readArray(mInfo.verifier.encryptedVerifier, SAL_N_ELEMENTS(mInfo.verifier.encryptedVerifier));
294 mInfo.verifier.encryptedVerifierHashSize = aBinaryStream.readuInt32();
295 aBinaryStream.readArray(mInfo.verifier.encryptedVerifierHash, SAL_N_ELEMENTS(mInfo.verifier.encryptedVerifierHash));
297 if (mInfo.verifier.saltSize != 16)
298 return false;
300 // check flags and algorithm IDs, required are AES128 and SHA-1
301 if (!getFlag(mInfo.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
302 return false;
304 if (!getFlag(mInfo.header.flags, msfilter::ENCRYPTINFO_AES))
305 return false;
307 // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
308 if (mInfo.header.algId != 0 && mInfo.header.algId != msfilter::ENCRYPT_ALGO_AES128)
309 return false;
311 // hash algorithm ID 0 defaults to SHA-1 too
312 if (mInfo.header.algIdHash != 0 && mInfo.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
313 return false;
315 if (mInfo.verifier.encryptedVerifierHashSize != 20)
316 return false;
318 return !aBinaryStream.isEof();
321 } // namespace core
322 } // namespace oox
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */