1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
11 #include "oox/crypto/Standard2007Engine.hxx"
13 #include <oox/crypto/CryptTools.hxx>
14 #include <oox/helper/binaryinputstream.hxx>
15 #include <oox/helper/binaryoutputstream.hxx>
17 #include <rtl/digest.h>
18 #include <rtl/random.h>
20 #include <comphelper/hash.hxx>
25 /* =========================================================================== */
26 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
27 /* =========================================================================== */
31 void lclRandomGenerateValues(sal_uInt8
* aArray
, sal_uInt32 aSize
)
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)
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
)
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
);
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());
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
);
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());
121 bool Standard2007Engine::generateEncryptionKey(const OUString
& password
)
124 mKey
.resize(mInfo
.header
.keyBits
/ 8, 0);
126 calculateEncryptionKey(password
);
128 std::vector
<sal_uInt8
> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH
);
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
);
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
);
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;
184 mKey
.resize(keyLength
, 0);
186 if (!calculateEncryptionKey(password
))
189 if (!generateVerifier())
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
);
233 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */