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/AgileEngine.hxx"
12 :
13 : namespace oox {
14 : namespace core {
15 :
16 : using namespace std;
17 :
18 : namespace {
19 :
20 : const sal_uInt8 constBlock1[] = { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
21 : const sal_uInt8 constBlock2[] = { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
22 : const sal_uInt8 constBlock3[] = { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
23 :
24 0 : bool hashCalc( std::vector<sal_uInt8>& output,
25 : std::vector<sal_uInt8>& input,
26 : const OUString& algorithm )
27 : {
28 0 : if (algorithm == "SHA1")
29 0 : return Digest::sha1(output, input);
30 0 : else if (algorithm == "SHA512")
31 0 : return Digest::sha512(output, input);
32 0 : return false;
33 : }
34 :
35 : } // namespace
36 :
37 0 : AgileEngine::AgileEngine() :
38 0 : CryptoEngine()
39 0 : {}
40 :
41 0 : AgileEngine::~AgileEngine()
42 0 : {}
43 :
44 0 : AgileEncryptionInfo& AgileEngine::getInfo()
45 : {
46 0 : return mInfo;
47 : }
48 :
49 0 : Crypto::CryptoType AgileEngine::cryptoType(const AgileEncryptionInfo& rInfo)
50 : {
51 0 : if (rInfo.keyBits == 128 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
52 0 : return Crypto::AES_128_CBC;
53 0 : else if (rInfo.keyBits == 256 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
54 0 : return Crypto::AES_256_CBC;
55 0 : return Crypto::UNKNOWN;
56 : }
57 :
58 0 : bool AgileEngine::calculateBlock(
59 : const sal_uInt8* rBlock,
60 : sal_uInt32 aBlockSize,
61 : vector<sal_uInt8>& rHashFinal,
62 : vector<sal_uInt8>& rInput,
63 : vector<sal_uInt8>& rOutput)
64 : {
65 0 : vector<sal_uInt8> hash(mInfo.hashSize, 0);
66 0 : vector<sal_uInt8> salt = mInfo.saltValue;
67 0 : vector<sal_uInt8> dataFinal(mInfo.hashSize + aBlockSize, 0);
68 0 : std::copy(rHashFinal.begin(), rHashFinal.end(), dataFinal.begin());
69 : std::copy(
70 : rBlock,
71 : rBlock + aBlockSize,
72 0 : dataFinal.begin() + mInfo.hashSize);
73 :
74 0 : hashCalc(hash, dataFinal, mInfo.hashAlgorithm);
75 :
76 0 : sal_Int32 keySize = mInfo.keyBits / 8;
77 0 : vector<sal_uInt8> key(keySize, 0);
78 :
79 0 : std::copy(hash.begin(), hash.begin() + keySize, key.begin());
80 :
81 0 : Decrypt aDecryptor(key, salt, cryptoType(mInfo));
82 0 : aDecryptor.update(rOutput, rInput);
83 :
84 0 : return true;
85 : }
86 :
87 0 : bool AgileEngine::calculateHashFinal(const OUString& rPassword, vector<sal_uInt8>& aHashFinal)
88 : {
89 0 : sal_Int32 saltSize = mInfo.saltSize;
90 0 : vector<sal_uInt8> salt = mInfo.saltValue;
91 0 : sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
92 :
93 0 : vector<sal_uInt8> initialData(saltSize + passwordByteLength);
94 0 : std::copy(salt.begin(), salt.end(), initialData.begin());
95 :
96 0 : const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
97 :
98 : std::copy(
99 : passwordByteArray,
100 : passwordByteArray + passwordByteLength,
101 0 : initialData.begin() + saltSize);
102 :
103 0 : vector<sal_uInt8> hash(mInfo.hashSize, 0);
104 :
105 0 : hashCalc(hash, initialData, mInfo.hashAlgorithm);
106 :
107 0 : vector<sal_uInt8> data(mInfo.hashSize + 4, 0);
108 :
109 0 : for (sal_Int32 i = 0; i < mInfo.spinCount; i++)
110 : {
111 0 : ByteOrderConverter::writeLittleEndian( &data[0], i );
112 0 : std::copy(hash.begin(), hash.end(), data.begin() + 4);
113 0 : hashCalc(hash, data, mInfo.hashAlgorithm);
114 : }
115 :
116 0 : std::copy(hash.begin(), hash.end(), aHashFinal.begin());
117 :
118 0 : return true;
119 : }
120 :
121 0 : bool AgileEngine::generateEncryptionKey(const OUString& rPassword)
122 : {
123 0 : mKey.clear();
124 0 : mKey.resize(mInfo.keyBits / 8, 0);
125 :
126 0 : vector<sal_uInt8> hashFinal(mInfo.hashSize, 0);
127 0 : calculateHashFinal(rPassword, hashFinal);
128 :
129 0 : vector<sal_uInt8> encryptedHashInput = mInfo.encryptedVerifierHashInput;
130 0 : vector<sal_uInt8> hashInput(mInfo.saltSize, 0);
131 0 : calculateBlock(constBlock1, sizeof(constBlock1), hashFinal, encryptedHashInput, hashInput);
132 :
133 0 : vector<sal_uInt8> encryptedHashValue = mInfo.encryptedVerifierHashValue;
134 0 : vector<sal_uInt8> hashValue(encryptedHashValue.size(), 0);
135 0 : calculateBlock(constBlock2, sizeof(constBlock2), hashFinal, encryptedHashValue, hashValue);
136 :
137 0 : vector<sal_uInt8> hash(mInfo.hashSize, 0);
138 0 : hashCalc(hash, hashInput, mInfo.hashAlgorithm);
139 :
140 0 : if (std::equal (hash.begin(), hash.end(), hashValue.begin()) )
141 : {
142 0 : vector<sal_uInt8> encryptedKeyValue = mInfo.encryptedKeyValue;
143 0 : calculateBlock(constBlock3, sizeof(constBlock3), hashFinal, encryptedKeyValue, mKey);
144 0 : return true;
145 : }
146 :
147 0 : return false;
148 : }
149 :
150 0 : bool AgileEngine::decrypt(
151 : BinaryXInputStream& aInputStream,
152 : BinaryXOutputStream& aOutputStream)
153 : {
154 : sal_uInt32 totalSize;
155 0 : aInputStream >> totalSize; // Document unencrypted size - 4 bytes
156 0 : aInputStream.skip( 4 ); // Reserved 4 Bytes
157 :
158 0 : vector<sal_uInt8> keyDataSalt = mInfo.keyDataSalt;
159 :
160 0 : sal_uInt32 saltSize = mInfo.saltSize;
161 0 : sal_uInt32 keySize = mInfo.keyBits / 8;
162 :
163 0 : sal_uInt32 segment = 0;
164 :
165 0 : vector<sal_uInt8> saltWithBlockKey(saltSize + sizeof(segment), 0);
166 0 : std::copy(keyDataSalt.begin(), keyDataSalt.end(), saltWithBlockKey.begin());
167 :
168 0 : vector<sal_uInt8> hash(mInfo.hashSize, 0);
169 0 : vector<sal_uInt8> iv(keySize, 0);
170 :
171 0 : vector<sal_uInt8> inputBuffer (SEGMENT_LENGTH);
172 0 : vector<sal_uInt8> outputBuffer(SEGMENT_LENGTH);
173 : sal_uInt32 inputLength;
174 : sal_uInt32 outputLength;
175 0 : sal_uInt32 remaining = totalSize;
176 :
177 0 : while( (inputLength = aInputStream.readMemory( &inputBuffer[0], SEGMENT_LENGTH )) > 0 )
178 : {
179 0 : sal_uInt8* segmentBegin = reinterpret_cast<sal_uInt8*>(&segment);
180 0 : sal_uInt8* segmentEnd = segmentBegin + sizeof(segment);
181 0 : std::copy(segmentBegin, segmentEnd, saltWithBlockKey.begin() + saltSize);
182 :
183 0 : hashCalc(hash, saltWithBlockKey, mInfo.hashAlgorithm);
184 :
185 : // Only if hash > keySize
186 0 : std::copy(hash.begin(), hash.begin() + keySize, iv.begin());
187 :
188 0 : Decrypt aDecryptor(mKey, iv, AgileEngine::cryptoType(mInfo));
189 0 : outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
190 :
191 0 : sal_uInt32 writeLength = outputLength > remaining ? remaining : outputLength;
192 0 : aOutputStream.writeMemory( &outputBuffer[0], writeLength );
193 :
194 0 : remaining -= outputLength;
195 0 : segment++;
196 0 : }
197 :
198 0 : return true;
199 : }
200 :
201 0 : bool AgileEngine::writeEncryptionInfo(
202 : const OUString& /*aPassword*/,
203 : BinaryXOutputStream& /*rStream*/)
204 : {
205 0 : return false; // Agile encrypting is not supported for now
206 : }
207 :
208 0 : bool AgileEngine::encrypt(
209 : BinaryXInputStream& /*aInputStream*/,
210 : BinaryXOutputStream& /*aOutputStream*/)
211 : {
212 0 : return false; // Agile encrypting is not supported for now
213 : }
214 :
215 :
216 : } // namespace core
217 : } // namespace oox
218 :
219 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|