1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
11 #include "oox/crypto/AgileEngine.hxx"
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 };
24 bool hashCalc( std::vector
<sal_uInt8
>& output
,
25 std::vector
<sal_uInt8
>& input
,
26 const OUString
& algorithm
)
28 if (algorithm
== "SHA1")
29 return sha1(output
, input
);
30 else if (algorithm
== "SHA512")
31 return sha512(output
, input
);
37 AgileEngine::AgileEngine() :
41 AgileEngine::~AgileEngine()
44 AgileEncryptionInfo
& AgileEngine::getInfo()
49 Crypto::CryptoType
AgileEngine::cryptoType(const AgileEncryptionInfo
& rInfo
)
51 if (rInfo
.keyBits
== 128 && rInfo
.cipherAlgorithm
== "AES" && rInfo
.cipherChaining
== "ChainingModeCBC")
52 return Crypto::AES_128_CBC
;
53 else if (rInfo
.keyBits
== 256 && rInfo
.cipherAlgorithm
== "AES" && rInfo
.cipherChaining
== "ChainingModeCBC")
54 return Crypto::AES_256_CBC
;
55 return Crypto::UNKNOWN
;
58 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
)
65 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
66 vector
<sal_uInt8
> salt
= mInfo
.saltValue
;
67 vector
<sal_uInt8
> dataFinal(mInfo
.hashSize
+ aBlockSize
, 0);
68 std::copy(rHashFinal
.begin(), rHashFinal
.end(), dataFinal
.begin());
72 dataFinal
.begin() + mInfo
.hashSize
);
74 hashCalc(hash
, dataFinal
, mInfo
.hashAlgorithm
);
76 sal_Int32 keySize
= mInfo
.keyBits
/ 8;
77 vector
<sal_uInt8
> key(keySize
, 0);
79 std::copy(hash
.begin(), hash
.begin() + keySize
, key
.begin());
81 Decrypt
aDecryptor(key
, salt
, cryptoType(mInfo
));
82 aDecryptor
.update(rOutput
, rInput
);
87 bool AgileEngine::calculateHashFinal(const OUString
& rPassword
, vector
<sal_uInt8
>& aHashFinal
)
89 sal_Int32 saltSize
= mInfo
.saltSize
;
90 vector
<sal_uInt8
> salt
= mInfo
.saltValue
;
91 sal_uInt32 passwordByteLength
= rPassword
.getLength() * 2;
93 vector
<sal_uInt8
> initialData(saltSize
+ passwordByteLength
);
94 std::copy(salt
.begin(), salt
.end(), initialData
.begin());
96 const sal_uInt8
* passwordByteArray
= reinterpret_cast<const sal_uInt8
*>(rPassword
.getStr());
100 passwordByteArray
+ passwordByteLength
,
101 initialData
.begin() + saltSize
);
103 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
105 hashCalc(hash
, initialData
, mInfo
.hashAlgorithm
);
107 vector
<sal_uInt8
> data(mInfo
.hashSize
+ 4, 0);
109 for (int i
= 0; i
< mInfo
.spinCount
; i
++)
111 ByteOrderConverter::writeLittleEndian( &data
[0], i
);
112 std::copy(hash
.begin(), hash
.end(), data
.begin() + 4);
113 hashCalc(hash
, data
, mInfo
.hashAlgorithm
);
116 std::copy(hash
.begin(), hash
.end(), aHashFinal
.begin());
121 bool AgileEngine::generateEncryptionKey(const OUString
& rPassword
)
124 mKey
.resize(mInfo
.keyBits
/ 8, 0);
126 vector
<sal_uInt8
> hashFinal(mInfo
.hashSize
, 0);
127 calculateHashFinal(rPassword
, hashFinal
);
129 vector
<sal_uInt8
> encryptedHashInput
= mInfo
.encryptedVerifierHashInput
;
130 vector
<sal_uInt8
> hashInput(mInfo
.saltSize
, 0);
131 calculateBlock(constBlock1
, sizeof(constBlock1
), hashFinal
, encryptedHashInput
, hashInput
);
133 vector
<sal_uInt8
> encryptedHashValue
= mInfo
.encryptedVerifierHashValue
;
134 vector
<sal_uInt8
> hashValue(encryptedHashValue
.size(), 0);
135 calculateBlock(constBlock2
, sizeof(constBlock2
), hashFinal
, encryptedHashValue
, hashValue
);
137 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
138 hashCalc(hash
, hashInput
, mInfo
.hashAlgorithm
);
140 if (std::equal (hash
.begin(), hash
.end(), hashValue
.begin()) )
142 vector
<sal_uInt8
> encryptedKeyValue
= mInfo
.encryptedKeyValue
;
143 calculateBlock(constBlock3
, sizeof(constBlock3
), hashFinal
, encryptedKeyValue
, mKey
);
150 bool AgileEngine::decrypt(
151 BinaryXInputStream
& aInputStream
,
152 BinaryXOutputStream
& aOutputStream
)
154 sal_uInt32 totalSize
;
155 aInputStream
>> totalSize
; // Document unencrypted size - 4 bytes
156 aInputStream
.skip( 4 ); // Reserved 4 Bytes
158 vector
<sal_uInt8
> keyDataSalt
= mInfo
.keyDataSalt
;
160 sal_uInt32 saltSize
= mInfo
.saltSize
;
161 sal_uInt32 keySize
= mInfo
.keyBits
/ 8;
163 sal_uInt32 segment
= 0;
165 vector
<sal_uInt8
> saltWithBlockKey(saltSize
+ sizeof(segment
), 0);
166 std::copy(keyDataSalt
.begin(), keyDataSalt
.end(), saltWithBlockKey
.begin());
168 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
169 vector
<sal_uInt8
> iv(keySize
, 0);
171 vector
<sal_uInt8
> inputBuffer (SEGMENT_LENGTH
);
172 vector
<sal_uInt8
> outputBuffer(SEGMENT_LENGTH
);
173 sal_uInt32 inputLength
;
174 sal_uInt32 outputLength
;
175 sal_uInt32 remaining
= totalSize
;
177 while( (inputLength
= aInputStream
.readMemory( &inputBuffer
[0], SEGMENT_LENGTH
)) > 0 )
179 sal_uInt8
* segmentBegin
= reinterpret_cast<sal_uInt8
*>(&segment
);
180 sal_uInt8
* segmentEnd
= segmentBegin
+ sizeof(segment
);
181 std::copy(segmentBegin
, segmentEnd
, saltWithBlockKey
.begin() + saltSize
);
183 hashCalc(hash
, saltWithBlockKey
, mInfo
.hashAlgorithm
);
185 // Only if hash > keySize
186 std::copy(hash
.begin(), hash
.begin() + keySize
, iv
.begin());
188 Decrypt
aDecryptor(mKey
, iv
, AgileEngine::cryptoType(mInfo
));
189 outputLength
= aDecryptor
.update(outputBuffer
, inputBuffer
, inputLength
);
191 sal_uInt32 writeLength
= outputLength
> remaining
? remaining
: outputLength
;
192 aOutputStream
.writeMemory( &outputBuffer
[0], writeLength
);
194 remaining
-= outputLength
;
201 bool AgileEngine::writeEncryptionInfo(
202 const OUString
& /*aPassword*/,
203 BinaryXOutputStream
& /*rStream*/)
205 return false; // Agile encrypting is not supported for now
208 bool AgileEngine::encrypt(
209 BinaryXInputStream
& /*aInputStream*/,
210 BinaryXOutputStream
& /*aOutputStream*/)
212 return false; // Agile encrypting is not supported for now
219 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */