Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / oox / qa / unit / CryptoTest.cxx
blob290fce38eb4b26249cbcee3d804da4086518c2b4
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/.
8 */
10 #include <config_oox.h>
11 #include <cppunit/plugin/TestPlugIn.h>
12 #include <cppunit/extensions/HelperMacros.h>
13 #include <cppunit/TestFixture.h>
15 #include <algorithm>
16 #include <tools/stream.hxx>
17 #include <unotools/streamwrap.hxx>
19 #include <oox/crypto/Standard2007Engine.hxx>
20 #include <oox/crypto/AgileEngine.hxx>
21 #include <oox/helper/binaryinputstream.hxx>
22 #include <oox/helper/binaryoutputstream.hxx>
24 #if USE_TLS_NSS
25 #include <nss.h>
26 #endif
28 using namespace css;
30 class CryptoTest : public CppUnit::TestFixture
32 public:
33 virtual ~CryptoTest() override;
34 void testCryptoHash();
35 void testRoundUp();
36 void testStandard2007();
37 void testAgileEncryptionVerifier();
38 void testAgileEncryptionInfoWritingAndParsing();
39 void testAgileDataIntegrityHmacKey();
40 void testAgileEncryptingAndDecrypting();
42 CPPUNIT_TEST_SUITE(CryptoTest);
43 CPPUNIT_TEST(testCryptoHash);
44 CPPUNIT_TEST(testRoundUp);
45 CPPUNIT_TEST(testStandard2007);
46 CPPUNIT_TEST(testAgileEncryptionVerifier);
47 CPPUNIT_TEST(testAgileEncryptionInfoWritingAndParsing);
48 CPPUNIT_TEST(testAgileDataIntegrityHmacKey);
49 CPPUNIT_TEST(testAgileEncryptingAndDecrypting);
50 CPPUNIT_TEST_SUITE_END();
53 namespace
55 std::string toString(std::vector<sal_uInt8> const& aInput)
57 std::stringstream aStream;
58 for (auto const& aValue : aInput)
60 aStream << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(aValue);
63 return aStream.str();
67 CryptoTest::~CryptoTest()
69 #if USE_TLS_NSS
70 NSS_Shutdown();
71 #endif
74 void CryptoTest::testCryptoHash()
76 // Check examples from Wikipedia (https://en.wikipedia.org/wiki/HMAC)
77 OString aContentString("The quick brown fox jumps over the lazy dog");
78 std::vector<sal_uInt8> aContent(aContentString.getStr(),
79 aContentString.getStr() + aContentString.getLength());
80 std::vector<sal_uInt8> aKey = { 'k', 'e', 'y' };
82 oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA1);
83 aCryptoHash.update(aContent);
84 std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
85 CPPUNIT_ASSERT_EQUAL(std::string("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"),
86 toString(aHash));
90 oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA256);
91 aCryptoHash.update(aContent);
92 std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
93 CPPUNIT_ASSERT_EQUAL(
94 std::string("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"),
95 toString(aHash));
99 oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA384);
100 aCryptoHash.update(aContent);
101 std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
102 CPPUNIT_ASSERT_EQUAL(std::string("d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1"
103 "ae50700582a96cf35e1e554995fe4e03381c237"),
104 toString(aHash));
108 oox::crypto::CryptoHash aCryptoHash(aKey, oox::crypto::CryptoHashType::SHA512);
109 aCryptoHash.update(aContent);
110 std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
111 CPPUNIT_ASSERT_EQUAL(
112 std::string("b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549"
113 "f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a"),
114 toString(aHash));
118 void CryptoTest::testRoundUp()
120 CPPUNIT_ASSERT_EQUAL(16, oox::crypto::roundUp(16, 16));
121 CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(32, 16));
122 CPPUNIT_ASSERT_EQUAL(64, oox::crypto::roundUp(64, 16));
124 CPPUNIT_ASSERT_EQUAL(16, oox::crypto::roundUp(01, 16));
125 CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(17, 16));
126 CPPUNIT_ASSERT_EQUAL(32, oox::crypto::roundUp(31, 16));
129 void CryptoTest::testStandard2007()
131 oox::crypto::Standard2007Engine aEngine;
133 aEngine.setupEncryption("Password");
135 SvMemoryStream aEncryptionInfo;
136 oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
137 new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), false);
139 aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
140 aBinaryEncryptionInfoOutputStream.close();
142 CPPUNIT_ASSERT_EQUAL(sal_uInt64(224), aEncryptionInfo.GetSize());
145 SvMemoryStream aUnencryptedInput;
146 SvMemoryStream aEncryptedStream;
148 OString aTestString = "1234567890ABCDEFG";
150 aUnencryptedInput.WriteBytes(aTestString.getStr(), aTestString.getLength() + 1);
151 aUnencryptedInput.Seek(STREAM_SEEK_TO_BEGIN);
154 uno::Reference<io::XInputStream> xInputStream(
155 new utl::OSeekableInputStreamWrapper(aUnencryptedInput));
156 uno::Reference<io::XOutputStream> xOutputStream(
157 new utl::OSeekableOutputStreamWrapper(aEncryptedStream));
159 aEngine.encrypt(xInputStream, xOutputStream, aUnencryptedInput.GetSize());
161 xOutputStream->flush();
163 const sal_uInt8* pData = static_cast<const sal_uInt8*>(aEncryptedStream.GetData());
164 sal_uInt64 nSize = aEncryptedStream.GetSize();
166 std::vector<sal_uInt8> aData(nSize);
167 std::copy(pData, pData + nSize, aData.data());
169 CPPUNIT_ASSERT_EQUAL(sal_uInt64(40), nSize);
172 aEncryptedStream.Seek(STREAM_SEEK_TO_BEGIN);
173 SvMemoryStream aUnencryptedOutput;
176 oox::BinaryXInputStream aBinaryInputStream(
177 new utl::OSeekableInputStreamWrapper(aEncryptedStream), true);
178 oox::BinaryXOutputStream aBinaryOutputStream(
179 new utl::OSeekableOutputStreamWrapper(aUnencryptedOutput), true);
181 aEngine.decrypt(aBinaryInputStream, aBinaryOutputStream);
182 aBinaryOutputStream.close();
183 aBinaryInputStream.close();
185 const char* pData = static_cast<const char*>(aUnencryptedOutput.GetData());
186 sal_uInt64 nSize = aUnencryptedOutput.GetSize();
188 CPPUNIT_ASSERT_EQUAL(sal_uInt64(18), nSize);
190 OString aString(pData);
192 CPPUNIT_ASSERT_EQUAL(aTestString, aString);
196 void CryptoTest::testAgileEncryptionVerifier()
198 oox::crypto::AgileEngine aEngine;
200 OUString aPassword("Password");
202 aEngine.setupEncryptionParameters({ 100000, 16, 128, 20, 16, OUString("AES"),
203 OUString("ChainingModeCBC"), OUString("SHA1") });
205 CPPUNIT_ASSERT_EQUAL(true, aEngine.generateAndEncryptVerifierHash(aPassword));
206 CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
207 CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
209 aEngine.setupEncryptionParameters({ 100000, 16, 128, 48, 16, OUString("AES"),
210 OUString("ChainingModeCBC"), OUString("SHA384") });
212 CPPUNIT_ASSERT_EQUAL(true, aEngine.generateAndEncryptVerifierHash(aPassword));
213 CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
214 CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
216 aEngine.setupEncryptionParameters({ 100000, 16, 256, 64, 16, OUString("AES"),
217 OUString("ChainingModeCBC"), OUString("SHA512") });
219 CPPUNIT_ASSERT_EQUAL(true, aEngine.generateAndEncryptVerifierHash(aPassword));
220 CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
221 CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
224 void CryptoTest::testAgileEncryptionInfoWritingAndParsing()
226 OUString aPassword("Password");
227 std::vector<sal_uInt8> aKeyDataSalt;
229 { // Preset AES128 - SHA1
230 SvMemoryStream aEncryptionInfo;
232 oox::crypto::AgileEngine aEngine;
234 aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_128_SHA1);
235 aEngine.setupEncryption(aPassword);
236 aKeyDataSalt = aEngine.getInfo().keyDataSalt;
238 oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
239 new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
241 aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
242 aBinaryEncryptionInfoOutputStream.close();
244 CPPUNIT_ASSERT_EQUAL(sal_uInt64(996), aEncryptionInfo.GetSize());
247 aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
250 oox::crypto::AgileEngine aEngine;
252 uno::Reference<io::XInputStream> xInputStream(
253 new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
255 xInputStream->skipBytes(4); // Encryption type -> Agile
257 CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
259 oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo();
260 CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount);
261 CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize);
262 CPPUNIT_ASSERT_EQUAL(sal_Int32(128), rInfo.keyBits);
263 CPPUNIT_ASSERT_EQUAL(sal_Int32(20), rInfo.hashSize);
264 CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.blockSize);
265 CPPUNIT_ASSERT_EQUAL(OUString("AES"), rInfo.cipherAlgorithm);
266 CPPUNIT_ASSERT_EQUAL(OUString("ChainingModeCBC"), rInfo.cipherChaining);
267 CPPUNIT_ASSERT_EQUAL(OUString("SHA1"), rInfo.hashAlgorithm);
268 CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(rInfo.keyDataSalt));
270 CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
271 CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
275 { // Preset AES128 - SHA384
276 SvMemoryStream aEncryptionInfo;
278 oox::crypto::AgileEngine aEngine;
280 aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_128_SHA384);
281 aEngine.setupEncryption(aPassword);
282 aKeyDataSalt = aEngine.getInfo().keyDataSalt;
284 oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
285 new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
287 aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
288 aBinaryEncryptionInfoOutputStream.close();
290 CPPUNIT_ASSERT_EQUAL(sal_uInt64(1040), aEncryptionInfo.GetSize());
293 aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
296 oox::crypto::AgileEngine aEngine;
298 uno::Reference<io::XInputStream> xInputStream(
299 new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
301 xInputStream->skipBytes(4); // Encryption type -> Agile
303 CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
305 oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo();
306 CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount);
307 CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize);
308 CPPUNIT_ASSERT_EQUAL(sal_Int32(128), rInfo.keyBits);
309 CPPUNIT_ASSERT_EQUAL(sal_Int32(48), rInfo.hashSize);
310 CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.blockSize);
311 CPPUNIT_ASSERT_EQUAL(OUString("AES"), rInfo.cipherAlgorithm);
312 CPPUNIT_ASSERT_EQUAL(OUString("ChainingModeCBC"), rInfo.cipherChaining);
313 CPPUNIT_ASSERT_EQUAL(OUString("SHA384"), rInfo.hashAlgorithm);
314 CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(rInfo.keyDataSalt));
316 CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
317 CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
321 { // Preset AES256 - SHA512
322 SvMemoryStream aEncryptionInfo;
324 oox::crypto::AgileEngine aEngine;
326 aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_256_SHA512);
327 aEngine.setupEncryption(aPassword);
328 aKeyDataSalt = aEngine.getInfo().keyDataSalt;
330 oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
331 new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
333 aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
334 aBinaryEncryptionInfoOutputStream.close();
336 CPPUNIT_ASSERT_EQUAL(sal_uInt64(1112), aEncryptionInfo.GetSize());
339 aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
342 oox::crypto::AgileEngine aEngine;
344 uno::Reference<io::XInputStream> xInputStream(
345 new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
347 xInputStream->skipBytes(4); // Encryption type -> Agile
349 CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
351 oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo();
352 CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount);
353 CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize);
354 CPPUNIT_ASSERT_EQUAL(sal_Int32(256), rInfo.keyBits);
355 CPPUNIT_ASSERT_EQUAL(sal_Int32(64), rInfo.hashSize);
356 CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.blockSize);
357 CPPUNIT_ASSERT_EQUAL(OUString("AES"), rInfo.cipherAlgorithm);
358 CPPUNIT_ASSERT_EQUAL(OUString("ChainingModeCBC"), rInfo.cipherChaining);
359 CPPUNIT_ASSERT_EQUAL(OUString("SHA512"), rInfo.hashAlgorithm);
360 CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(rInfo.keyDataSalt));
362 CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
363 CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
368 void CryptoTest::testAgileDataIntegrityHmacKey()
370 OUString aPassword("Password");
372 std::vector<sal_uInt8> aKeyDataSalt;
374 std::vector<sal_uInt8> aHmacKey;
375 std::vector<sal_uInt8> aHmacEncryptedKey;
377 SvMemoryStream aEncryptionInfo;
379 oox::crypto::AgileEngine aEngine;
380 aEngine.setupEncryption(aPassword);
381 oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
382 new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
383 aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
384 aBinaryEncryptionInfoOutputStream.close();
386 aHmacKey = aEngine.getInfo().hmacKey;
387 aKeyDataSalt = aEngine.getInfo().keyDataSalt;
388 aHmacEncryptedKey = aEngine.getInfo().hmacEncryptedKey;
391 aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
394 oox::crypto::AgileEngine aEngine;
396 uno::Reference<io::XInputStream> xInputStream(
397 new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
399 xInputStream->skipBytes(4); // Encryption type -> Agile
401 CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
402 CPPUNIT_ASSERT(aEngine.generateEncryptionKey(aPassword));
404 CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(aEngine.getInfo().keyDataSalt));
406 CPPUNIT_ASSERT_EQUAL(toString(aHmacEncryptedKey),
407 toString(aEngine.getInfo().hmacEncryptedKey));
409 CPPUNIT_ASSERT_EQUAL(size_t(64), aHmacKey.size());
410 CPPUNIT_ASSERT_EQUAL(toString(aHmacKey), toString(aEngine.getInfo().hmacKey));
414 void CryptoTest::testAgileEncryptingAndDecrypting()
416 OUString aPassword("Password");
418 SvMemoryStream aEncryptionInfo;
419 SvMemoryStream aEncryptedStream;
421 OString aTestString = "1234567890ABCDEFGH";
424 oox::crypto::AgileEngine aEngine;
426 // Setup input
427 SvMemoryStream aUnencryptedInput;
428 uno::Reference<io::XInputStream> xInputStream(
429 new utl::OSeekableInputStreamWrapper(aUnencryptedInput));
431 aUnencryptedInput.WriteBytes(aTestString.getStr(), aTestString.getLength() + 1);
432 aUnencryptedInput.Seek(STREAM_SEEK_TO_BEGIN);
434 // Setup output
435 uno::Reference<io::XOutputStream> xOutputStream(
436 new utl::OSeekableOutputStreamWrapper(aEncryptedStream));
438 // Write content
439 aEngine.setupEncryption(aPassword);
440 aEngine.encrypt(xInputStream, xOutputStream, aUnencryptedInput.GetSize());
441 xOutputStream->flush();
443 // Check content
444 sal_uInt64 nSize = aEncryptedStream.GetSize();
446 CPPUNIT_ASSERT_EQUAL(sal_uInt64(40), nSize);
448 // Setup and write encryption info
449 oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
450 new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
451 aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
452 aBinaryEncryptionInfoOutputStream.close();
455 aEncryptedStream.Seek(STREAM_SEEK_TO_BEGIN);
456 aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
459 oox::crypto::AgileEngine aEngine;
461 // Read encryption info
462 uno::Reference<io::XInputStream> xEncryptionInfo(
463 new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
465 xEncryptionInfo->skipBytes(4); // Encryption type -> Agile
467 CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xEncryptionInfo));
469 // Setup password
470 CPPUNIT_ASSERT(aEngine.generateEncryptionKey(aPassword));
472 // Setup encrypted input stream
473 oox::BinaryXInputStream aBinaryInputStream(
474 new utl::OSeekableInputStreamWrapper(aEncryptedStream), true);
476 // Setup output stream
477 SvMemoryStream aUnencryptedOutput;
478 oox::BinaryXOutputStream aBinaryOutputStream(
479 new utl::OSeekableOutputStreamWrapper(aUnencryptedOutput), true);
481 // Decrypt
482 aEngine.decrypt(aBinaryInputStream, aBinaryOutputStream);
483 aBinaryOutputStream.close();
484 aBinaryInputStream.close();
486 // Check decrypted output
487 CPPUNIT_ASSERT_EQUAL(sal_uInt64(19), aUnencryptedOutput.GetSize());
489 OString aString(static_cast<const char*>(aUnencryptedOutput.GetData()));
490 CPPUNIT_ASSERT_EQUAL(aTestString, aString);
492 // Check data integrity
493 CPPUNIT_ASSERT_EQUAL(true, aEngine.checkDataIntegrity());
497 CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTest);
499 CPPUNIT_PLUGIN_IMPLEMENT();
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */