Branch libreoffice-5-0-4
[LibreOffice.git] / oox / source / crypto / Standard2007Engine.cxx
blobbcaba3052aeb3b8fdfb1aac6983a2ae94fe58413
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/.
9 */
11 #include "oox/crypto/Standard2007Engine.hxx"
13 #include <osl/time.h>
14 #include <rtl/random.h>
16 namespace oox {
17 namespace core {
19 using namespace std;
21 /* =========================================================================== */
22 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
23 /* =========================================================================== */
24 namespace
27 void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
29 TimeValue aTime;
30 osl_getSystemTime( &aTime );
31 rtlRandomPool aRandomPool = rtl_random_createPool ();
32 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
33 rtl_random_getBytes ( aRandomPool, aArray, aSize );
34 rtl_random_destroyPool ( aRandomPool );
37 static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
39 } // namespace
41 EncryptionStandardHeader::EncryptionStandardHeader()
43 flags = 0;
44 sizeExtra = 0;
45 algId = 0;
46 algIdHash = 0;
47 keyBits = 0;
48 providedType = 0;
49 reserved1 = 0;
50 reserved2 = 0;
53 EncryptionVerifierAES::EncryptionVerifierAES() :
54 saltSize(SALT_LENGTH),
55 encryptedVerifierHashSize(Digest::DIGEST_LENGTH_SHA1)
57 memset(salt, 0, sizeof(salt));
58 memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
59 memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
62 Standard2007Engine::Standard2007Engine() :
63 CryptoEngine()
66 Standard2007Engine::~Standard2007Engine()
69 bool Standard2007Engine::generateVerifier()
71 // only support key of size 128 bit (16 byte)
72 if (mKey.size() != 16)
73 return false;
75 sal_uInt32 outputLength;
76 vector<sal_uInt8> verifier(ENCRYPTED_VERIFIER_LENGTH);
77 vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
79 lclRandomGenerateValues(&verifier[0], verifier.size());
81 vector<sal_uInt8> iv;
82 Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
83 outputLength = aEncryptorVerifier.update(encryptedVerifier, verifier);
84 if (outputLength != ENCRYPTED_VERIFIER_LENGTH)
85 return false;
86 std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
88 vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
89 mInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
90 Digest::sha1(hash, verifier);
91 hash.resize(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
93 vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
95 Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
96 outputLength = aEncryptorHash.update(encryptedHash, hash, hash.size());
97 std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
99 return true;
102 bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
104 sal_uInt32 saltSize = mInfo.verifier.saltSize;
105 sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
106 const sal_uInt8* saltArray = mInfo.verifier.salt;
108 // Prepare initial data -> salt + password (in 16-bit chars)
109 vector<sal_uInt8> initialData(saltSize + passwordByteLength);
110 std::copy(saltArray, saltArray + saltSize, initialData.begin());
112 const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
114 std::copy(
115 passwordByteArray,
116 passwordByteArray + passwordByteLength,
117 initialData.begin() + saltSize);
119 // use "hash" vector for result of sha1 hashing
120 vector<sal_uInt8> hash(Digest::DIGEST_LENGTH_SHA1, 0);
122 // calculate SHA1 hash of initialData
123 Digest::sha1(hash, initialData);
125 // data = iterator (4bytes) + hash
126 vector<sal_uInt8> data(Digest::DIGEST_LENGTH_SHA1 + 4, 0);
128 for (sal_Int32 i = 0; i < 50000; ++i)
130 ByteOrderConverter::writeLittleEndian( &data[0], i );
131 std::copy(hash.begin(), hash.end(), data.begin() + 4);
132 Digest::sha1(hash, data);
134 std::copy(hash.begin(), hash.end(), data.begin() );
135 std::fill(data.begin() + Digest::DIGEST_LENGTH_SHA1, data.end(), 0 );
137 Digest::sha1(hash, data);
139 // derive key
140 vector<sal_uInt8> buffer(64, 0x36);
141 for( sal_uInt32 i = 0; i < hash.size(); ++i )
142 buffer[i] ^= hash[i];
144 Digest::sha1(hash, buffer);
145 std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
147 return true;
150 bool Standard2007Engine::generateEncryptionKey(const OUString& password)
152 mKey.clear();
153 mKey.resize(mInfo.header.keyBits / 8, 0);
155 calculateEncryptionKey(password);
157 vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
158 std::copy(
159 mInfo.verifier.encryptedVerifier,
160 mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
161 encryptedVerifier.begin());
163 vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH);
164 std::copy(
165 mInfo.verifier.encryptedVerifierHash,
166 mInfo.verifier.encryptedVerifierHash + ENCRYPTED_VERIFIER_HASH_LENGTH,
167 encryptedHash.begin());
169 vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
170 Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
172 vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
173 Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
175 vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
176 Digest::sha1(hash, verifier);
178 return std::equal( hash.begin(), hash.end(), verifierHash.begin() );
181 bool Standard2007Engine::decrypt(
182 BinaryXInputStream& aInputStream,
183 BinaryXOutputStream& aOutputStream)
185 aInputStream.skip(4); // Document unencrypted size - 4 bytes
186 aInputStream.skip(4); // Reserved 4 Bytes
188 vector<sal_uInt8> iv;
189 Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
190 vector<sal_uInt8> inputBuffer (4096);
191 vector<sal_uInt8> outputBuffer(4096);
192 sal_uInt32 inputLength;
193 sal_uInt32 outputLength;
195 while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
197 outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
198 aOutputStream.writeMemory( &outputBuffer[0], outputLength );
200 return true;
203 bool Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
205 mInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
206 mInfo.header.algId = ENCRYPT_ALGO_AES128;
207 mInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
208 mInfo.header.keyBits = ENCRYPT_KEY_SIZE_AES_128;
209 mInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
211 lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
212 const sal_Int32 keyLength = mInfo.header.keyBits / 8;
214 mKey.clear();
215 mKey.resize(keyLength, 0);
217 if (!calculateEncryptionKey(password))
218 return false;
220 if (!generateVerifier())
221 return false;
223 rStream.WriteUInt32(VERSION_INFO_2007_FORMAT);
225 sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
227 sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
229 rStream.WriteUInt32( mInfo.header.flags );
230 sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
231 rStream.WriteUInt32( headerSize );
233 rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
234 rStream.writeUnicodeArray(lclCspName);
235 rStream.WriteUInt16(0);
237 sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
238 rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
240 return true;
243 bool Standard2007Engine::encrypt(
244 BinaryXInputStream& aInputStream,
245 BinaryXOutputStream& aOutputStream)
247 vector<sal_uInt8> inputBuffer(1024);
248 vector<sal_uInt8> outputBuffer(1024);
250 sal_uInt32 inputLength;
251 sal_uInt32 outputLength;
253 vector<sal_uInt8> iv;
254 Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
256 while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
258 inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
259 outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
260 aOutputStream.writeMemory( &outputBuffer[0], outputLength );
262 return true;
265 } // namespace core
266 } // namespace oox
268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */