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