Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : *
9 : */
10 :
11 : #include "oox/crypto/Standard2007Engine.hxx"
12 :
13 : #include <osl/time.h>
14 : #include <rtl/random.h>
15 :
16 : namespace oox {
17 : namespace core {
18 :
19 : using namespace std;
20 :
21 : /* =========================================================================== */
22 : /* Kudos to Caolan McNamara who provided the core decryption implementations. */
23 : /* =========================================================================== */
24 : namespace
25 : {
26 :
27 0 : void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
28 : {
29 : TimeValue aTime;
30 0 : osl_getSystemTime( &aTime );
31 0 : rtlRandomPool aRandomPool = rtl_random_createPool ();
32 0 : rtl_random_addBytes ( aRandomPool, &aTime, 8 );
33 0 : rtl_random_getBytes ( aRandomPool, aArray, aSize );
34 0 : rtl_random_destroyPool ( aRandomPool );
35 0 : }
36 :
37 0 : static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
38 :
39 : } // namespace
40 :
41 0 : EncryptionStandardHeader::EncryptionStandardHeader()
42 : {
43 0 : flags = 0;
44 0 : sizeExtra = 0;
45 0 : algId = 0;
46 0 : algIdHash = 0;
47 0 : keyBits = 0;
48 0 : providedType = 0;
49 0 : reserved1 = 0;
50 0 : reserved2 = 0;
51 0 : }
52 :
53 0 : EncryptionVerifierAES::EncryptionVerifierAES() :
54 : saltSize(SALT_LENGTH),
55 0 : encryptedVerifierHashSize(Digest::DIGEST_LENGTH_SHA1)
56 : {
57 0 : memset(salt, 0, sizeof(salt));
58 0 : memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
59 0 : memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
60 0 : }
61 :
62 0 : Standard2007Engine::Standard2007Engine() :
63 0 : CryptoEngine()
64 0 : {}
65 :
66 0 : Standard2007Engine::~Standard2007Engine()
67 0 : {}
68 :
69 0 : StandardEncryptionInfo& Standard2007Engine::getInfo()
70 : {
71 0 : return mInfo;
72 : }
73 :
74 0 : bool Standard2007Engine::generateVerifier()
75 : {
76 : // only support key of size 128 bit (16 byte)
77 0 : if (mKey.size() != 16)
78 0 : return false;
79 :
80 : sal_uInt32 outputLength;
81 0 : vector<sal_uInt8> verifier(ENCRYPTED_VERIFIER_LENGTH);
82 0 : vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
83 :
84 0 : lclRandomGenerateValues(&verifier[0], verifier.size());
85 :
86 0 : vector<sal_uInt8> iv;
87 0 : Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
88 0 : outputLength = aEncryptorVerifier.update(encryptedVerifier, verifier);
89 0 : if (outputLength != ENCRYPTED_VERIFIER_LENGTH)
90 0 : return false;
91 0 : std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
92 :
93 0 : vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
94 0 : mInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
95 0 : Digest::sha1(hash, verifier);
96 0 : hash.resize(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
97 :
98 0 : vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
99 :
100 0 : Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
101 0 : outputLength = aEncryptorHash.update(encryptedHash, hash, hash.size());
102 0 : std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
103 :
104 0 : return true;
105 : }
106 :
107 0 : bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
108 : {
109 0 : sal_uInt32 saltSize = mInfo.verifier.saltSize;
110 0 : sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
111 0 : const sal_uInt8* saltArray = mInfo.verifier.salt;
112 :
113 : // Prepare initial data -> salt + password (in 16-bit chars)
114 0 : vector<sal_uInt8> initialData(saltSize + passwordByteLength);
115 0 : std::copy(saltArray, saltArray + saltSize, initialData.begin());
116 :
117 0 : const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
118 :
119 : std::copy(
120 : passwordByteArray,
121 : passwordByteArray + passwordByteLength,
122 0 : initialData.begin() + saltSize);
123 :
124 : // use "hash" vector for result of sha1 hashing
125 0 : vector<sal_uInt8> hash(Digest::DIGEST_LENGTH_SHA1, 0);
126 :
127 : // calculate SHA1 hash of initialData
128 0 : Digest::sha1(hash, initialData);
129 :
130 : // data = iterator (4bytes) + hash
131 0 : vector<sal_uInt8> data(Digest::DIGEST_LENGTH_SHA1 + 4, 0);
132 :
133 0 : for (sal_Int32 i = 0; i < 50000; ++i)
134 : {
135 0 : ByteOrderConverter::writeLittleEndian( &data[0], i );
136 0 : std::copy(hash.begin(), hash.end(), data.begin() + 4);
137 0 : Digest::sha1(hash, data);
138 : }
139 0 : std::copy(hash.begin(), hash.end(), data.begin() );
140 0 : std::fill(data.begin() + Digest::DIGEST_LENGTH_SHA1, data.end(), 0 );
141 :
142 0 : Digest::sha1(hash, data);
143 :
144 : // derive key
145 0 : vector<sal_uInt8> buffer(64, 0x36);
146 0 : for( sal_uInt32 i = 0; i < hash.size(); ++i )
147 0 : buffer[i] ^= hash[i];
148 :
149 0 : Digest::sha1(hash, buffer);
150 0 : std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
151 :
152 0 : return true;
153 : }
154 :
155 0 : bool Standard2007Engine::generateEncryptionKey(const OUString& password)
156 : {
157 0 : mKey.clear();
158 0 : mKey.resize(mInfo.header.keyBits / 8, 0);
159 :
160 0 : calculateEncryptionKey(password);
161 :
162 0 : vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
163 : std::copy(
164 : mInfo.verifier.encryptedVerifier,
165 : mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
166 0 : encryptedVerifier.begin());
167 :
168 0 : vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH);
169 : std::copy(
170 : mInfo.verifier.encryptedVerifierHash,
171 : mInfo.verifier.encryptedVerifierHash + ENCRYPTED_VERIFIER_HASH_LENGTH,
172 0 : encryptedHash.begin());
173 :
174 0 : vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
175 0 : Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
176 :
177 0 : vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
178 0 : Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
179 :
180 0 : vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
181 0 : Digest::sha1(hash, verifier);
182 :
183 0 : return std::equal( hash.begin(), hash.end(), verifierHash.begin() );
184 : }
185 :
186 0 : bool Standard2007Engine::decrypt(
187 : BinaryXInputStream& aInputStream,
188 : BinaryXOutputStream& aOutputStream)
189 : {
190 : sal_uInt32 totalSize;
191 0 : aInputStream >> totalSize; // Document unencrypted size - 4 bytes
192 0 : aInputStream.skip( 4 ); // Reserved 4 Bytes
193 :
194 0 : vector<sal_uInt8> iv;
195 0 : Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
196 0 : vector<sal_uInt8> inputBuffer (4096);
197 0 : vector<sal_uInt8> outputBuffer(4096);
198 : sal_uInt32 inputLength;
199 : sal_uInt32 outputLength;
200 :
201 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
202 : {
203 0 : outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
204 0 : aOutputStream.writeMemory( &outputBuffer[0], outputLength );
205 : }
206 0 : return true;
207 : }
208 :
209 0 : bool Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
210 : {
211 0 : mInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
212 0 : mInfo.header.algId = ENCRYPT_ALGO_AES128;
213 0 : mInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
214 0 : mInfo.header.keyBits = ENCRYPT_KEY_SIZE_AES_128;
215 0 : mInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
216 :
217 0 : lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
218 0 : const sal_Int32 keyLength = mInfo.header.keyBits / 8;
219 :
220 0 : mKey.clear();
221 0 : mKey.resize(keyLength, 0);
222 :
223 0 : if (!calculateEncryptionKey(password))
224 0 : return false;
225 :
226 0 : if (!generateVerifier())
227 0 : return false;
228 :
229 0 : rStream.writeValue(VERSION_INFO_2007_FORMAT);
230 :
231 0 : sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
232 :
233 0 : sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
234 :
235 0 : rStream << mInfo.header.flags;
236 0 : sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
237 0 : rStream << headerSize;
238 :
239 0 : rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
240 0 : rStream.writeUnicodeArray(lclCspName);
241 0 : rStream.writeValue<sal_uInt16>(0);
242 :
243 0 : sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
244 0 : rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
245 :
246 0 : return true;
247 : }
248 :
249 0 : bool Standard2007Engine::encrypt(
250 : BinaryXInputStream& aInputStream,
251 : BinaryXOutputStream& aOutputStream)
252 : {
253 0 : vector<sal_uInt8> inputBuffer(1024);
254 0 : vector<sal_uInt8> outputBuffer(1024);
255 :
256 : sal_uInt32 inputLength;
257 : sal_uInt32 outputLength;
258 :
259 0 : vector<sal_uInt8> iv;
260 0 : Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
261 :
262 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
263 : {
264 0 : inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
265 0 : outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
266 0 : aOutputStream.writeMemory( &outputBuffer[0], outputLength );
267 : }
268 0 : return true;
269 : }
270 :
271 : } // namespace core
272 0 : } // namespace oox
273 :
274 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|