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 82 : 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( size_t 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 0 : aInputStream.skip(4); // Document unencrypted size - 4 bytes
186 0 : aInputStream.skip(4); // Reserved 4 Bytes
187 :
188 0 : vector<sal_uInt8> iv;
189 0 : Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
190 0 : vector<sal_uInt8> inputBuffer (4096);
191 0 : vector<sal_uInt8> outputBuffer(4096);
192 : sal_uInt32 inputLength;
193 : sal_uInt32 outputLength;
194 :
195 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
196 : {
197 0 : outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
198 0 : aOutputStream.writeMemory( &outputBuffer[0], outputLength );
199 : }
200 0 : return true;
201 : }
202 :
203 0 : bool Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
204 : {
205 0 : mInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
206 0 : mInfo.header.algId = ENCRYPT_ALGO_AES128;
207 0 : mInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
208 0 : mInfo.header.keyBits = ENCRYPT_KEY_SIZE_AES_128;
209 0 : mInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
210 :
211 0 : lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
212 0 : const sal_Int32 keyLength = mInfo.header.keyBits / 8;
213 :
214 0 : mKey.clear();
215 0 : mKey.resize(keyLength, 0);
216 :
217 0 : if (!calculateEncryptionKey(password))
218 0 : return false;
219 :
220 0 : if (!generateVerifier())
221 0 : return false;
222 :
223 0 : rStream.WriteUInt32(VERSION_INFO_2007_FORMAT);
224 :
225 0 : sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
226 :
227 0 : sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
228 :
229 0 : rStream.WriteUInt32( mInfo.header.flags );
230 0 : sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
231 0 : rStream.WriteUInt32( headerSize );
232 :
233 0 : rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
234 0 : rStream.writeUnicodeArray(lclCspName);
235 0 : rStream.WriteUInt16(0);
236 :
237 0 : sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
238 0 : rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
239 :
240 0 : return true;
241 : }
242 :
243 0 : bool Standard2007Engine::encrypt(
244 : BinaryXInputStream& aInputStream,
245 : BinaryXOutputStream& aOutputStream)
246 : {
247 0 : vector<sal_uInt8> inputBuffer(1024);
248 0 : vector<sal_uInt8> outputBuffer(1024);
249 :
250 : sal_uInt32 inputLength;
251 : sal_uInt32 outputLength;
252 :
253 0 : vector<sal_uInt8> iv;
254 0 : Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
255 :
256 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
257 : {
258 0 : inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
259 0 : outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
260 0 : aOutputStream.writeMemory( &outputBuffer[0], outputLength );
261 : }
262 0 : return true;
263 : }
264 :
265 : } // namespace core
266 246 : } // namespace oox
267 :
268 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|