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 136 : 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 : bool Standard2007Engine::generateVerifier()
70 : {
71 : // only support key of size 128 bit (16 byte)
72 0 : if (mKey.size() != 16)
73 0 : return false;
74 :
75 : sal_uInt32 outputLength;
76 0 : vector<sal_uInt8> verifier(ENCRYPTED_VERIFIER_LENGTH);
77 0 : vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
78 :
79 0 : lclRandomGenerateValues(&verifier[0], verifier.size());
80 :
81 0 : vector<sal_uInt8> iv;
82 0 : Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
83 0 : outputLength = aEncryptorVerifier.update(encryptedVerifier, verifier);
84 0 : if (outputLength != ENCRYPTED_VERIFIER_LENGTH)
85 0 : return false;
86 0 : std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
87 :
88 0 : vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
89 0 : mInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
90 0 : Digest::sha1(hash, verifier);
91 0 : hash.resize(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
92 :
93 0 : vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
94 :
95 0 : Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
96 0 : outputLength = aEncryptorHash.update(encryptedHash, hash, hash.size());
97 0 : std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
98 :
99 0 : return true;
100 : }
101 :
102 0 : bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
103 : {
104 0 : sal_uInt32 saltSize = mInfo.verifier.saltSize;
105 0 : sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
106 0 : const sal_uInt8* saltArray = mInfo.verifier.salt;
107 :
108 : // Prepare initial data -> salt + password (in 16-bit chars)
109 0 : vector<sal_uInt8> initialData(saltSize + passwordByteLength);
110 0 : std::copy(saltArray, saltArray + saltSize, initialData.begin());
111 :
112 0 : const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
113 :
114 : std::copy(
115 : passwordByteArray,
116 : passwordByteArray + passwordByteLength,
117 0 : initialData.begin() + saltSize);
118 :
119 : // use "hash" vector for result of sha1 hashing
120 0 : vector<sal_uInt8> hash(Digest::DIGEST_LENGTH_SHA1, 0);
121 :
122 : // calculate SHA1 hash of initialData
123 0 : Digest::sha1(hash, initialData);
124 :
125 : // data = iterator (4bytes) + hash
126 0 : vector<sal_uInt8> data(Digest::DIGEST_LENGTH_SHA1 + 4, 0);
127 :
128 0 : for (sal_Int32 i = 0; i < 50000; ++i)
129 : {
130 0 : ByteOrderConverter::writeLittleEndian( &data[0], i );
131 0 : std::copy(hash.begin(), hash.end(), data.begin() + 4);
132 0 : Digest::sha1(hash, data);
133 : }
134 0 : std::copy(hash.begin(), hash.end(), data.begin() );
135 0 : std::fill(data.begin() + Digest::DIGEST_LENGTH_SHA1, data.end(), 0 );
136 :
137 0 : Digest::sha1(hash, data);
138 :
139 : // derive key
140 0 : vector<sal_uInt8> buffer(64, 0x36);
141 0 : for( sal_uInt32 i = 0; i < hash.size(); ++i )
142 0 : buffer[i] ^= hash[i];
143 :
144 0 : Digest::sha1(hash, buffer);
145 0 : std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
146 :
147 0 : return true;
148 : }
149 :
150 0 : bool Standard2007Engine::generateEncryptionKey(const OUString& password)
151 : {
152 0 : mKey.clear();
153 0 : mKey.resize(mInfo.header.keyBits / 8, 0);
154 :
155 0 : calculateEncryptionKey(password);
156 :
157 0 : vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
158 : std::copy(
159 : mInfo.verifier.encryptedVerifier,
160 : mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
161 0 : encryptedVerifier.begin());
162 :
163 0 : vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH);
164 : std::copy(
165 : mInfo.verifier.encryptedVerifierHash,
166 : mInfo.verifier.encryptedVerifierHash + ENCRYPTED_VERIFIER_HASH_LENGTH,
167 0 : encryptedHash.begin());
168 :
169 0 : vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
170 0 : Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
171 :
172 0 : vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
173 0 : Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
174 :
175 0 : vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
176 0 : Digest::sha1(hash, verifier);
177 :
178 0 : return std::equal( hash.begin(), hash.end(), verifierHash.begin() );
179 : }
180 :
181 0 : bool Standard2007Engine::decrypt(
182 : BinaryXInputStream& aInputStream,
183 : BinaryXOutputStream& aOutputStream)
184 : {
185 : sal_uInt32 totalSize;
186 0 : aInputStream >> totalSize; // Document unencrypted size - 4 bytes
187 0 : aInputStream.skip( 4 ); // Reserved 4 Bytes
188 :
189 0 : vector<sal_uInt8> iv;
190 0 : Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
191 0 : vector<sal_uInt8> inputBuffer (4096);
192 0 : vector<sal_uInt8> outputBuffer(4096);
193 : sal_uInt32 inputLength;
194 : sal_uInt32 outputLength;
195 :
196 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
197 : {
198 0 : outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
199 0 : aOutputStream.writeMemory( &outputBuffer[0], outputLength );
200 : }
201 0 : return true;
202 : }
203 :
204 0 : bool Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
205 : {
206 0 : mInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
207 0 : mInfo.header.algId = ENCRYPT_ALGO_AES128;
208 0 : mInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
209 0 : mInfo.header.keyBits = ENCRYPT_KEY_SIZE_AES_128;
210 0 : mInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
211 :
212 0 : lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
213 0 : const sal_Int32 keyLength = mInfo.header.keyBits / 8;
214 :
215 0 : mKey.clear();
216 0 : mKey.resize(keyLength, 0);
217 :
218 0 : if (!calculateEncryptionKey(password))
219 0 : return false;
220 :
221 0 : if (!generateVerifier())
222 0 : return false;
223 :
224 0 : rStream.writeValue(VERSION_INFO_2007_FORMAT);
225 :
226 0 : sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
227 :
228 0 : sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
229 :
230 0 : rStream << mInfo.header.flags;
231 0 : sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
232 0 : rStream << headerSize;
233 :
234 0 : rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
235 0 : rStream.writeUnicodeArray(lclCspName);
236 0 : rStream.writeValue<sal_uInt16>(0);
237 :
238 0 : sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
239 0 : rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
240 :
241 0 : return true;
242 : }
243 :
244 0 : bool Standard2007Engine::encrypt(
245 : BinaryXInputStream& aInputStream,
246 : BinaryXOutputStream& aOutputStream)
247 : {
248 0 : vector<sal_uInt8> inputBuffer(1024);
249 0 : vector<sal_uInt8> outputBuffer(1024);
250 :
251 : sal_uInt32 inputLength;
252 : sal_uInt32 outputLength;
253 :
254 0 : vector<sal_uInt8> iv;
255 0 : Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
256 :
257 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
258 : {
259 0 : inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
260 0 : outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
261 0 : aOutputStream.writeMemory( &outputBuffer[0], outputLength );
262 : }
263 0 : return true;
264 : }
265 :
266 : } // namespace core
267 408 : } // namespace oox
268 :
269 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|