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"
13 #include <oox/helper/binaryinputstream.hxx>
14 #include <oox/helper/binaryoutputstream.hxx>
16 #include <comphelper/hash.hxx>
23 const sal_uInt32 constSegmentLength
= 4096;
25 bool hashCalc(std::vector
<sal_uInt8
>& output
,
26 std::vector
<sal_uInt8
>& input
,
27 const OUString
& sAlgorithm
)
29 if (sAlgorithm
== "SHA1")
31 std::vector
<unsigned char> out
= comphelper::Hash::calculateHash(input
.data(), input
.size(), comphelper::HashType::SHA1
);
35 else if (sAlgorithm
== "SHA512")
37 std::vector
<unsigned char> out
= comphelper::Hash::calculateHash(input
.data(), input
.size(), comphelper::HashType::SHA512
);
46 Crypto::CryptoType
AgileEngine::cryptoType(const AgileEncryptionInfo
& rInfo
)
48 if (rInfo
.keyBits
== 128 && rInfo
.cipherAlgorithm
== "AES" && rInfo
.cipherChaining
== "ChainingModeCBC")
49 return Crypto::AES_128_CBC
;
50 else if (rInfo
.keyBits
== 256 && rInfo
.cipherAlgorithm
== "AES" && rInfo
.cipherChaining
== "ChainingModeCBC")
51 return Crypto::AES_256_CBC
;
52 return Crypto::UNKNOWN
;
55 void AgileEngine::calculateBlock(
56 std::vector
<sal_uInt8
> const & rBlock
,
57 std::vector
<sal_uInt8
>& rHashFinal
,
58 std::vector
<sal_uInt8
>& rInput
,
59 std::vector
<sal_uInt8
>& rOutput
)
61 std::vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
62 std::vector
<sal_uInt8
> dataFinal(mInfo
.hashSize
+ rBlock
.size(), 0);
63 std::copy(rHashFinal
.begin(), rHashFinal
.end(), dataFinal
.begin());
64 std::copy(rBlock
.begin(), rBlock
.end(), dataFinal
.begin() + mInfo
.hashSize
);
66 hashCalc(hash
, dataFinal
, mInfo
.hashAlgorithm
);
68 sal_Int32 keySize
= mInfo
.keyBits
/ 8;
69 std::vector
<sal_uInt8
> key(keySize
, 0);
71 std::copy(hash
.begin(), hash
.begin() + keySize
, key
.begin());
73 Decrypt
aDecryptor(key
, mInfo
.saltValue
, cryptoType(mInfo
));
74 aDecryptor
.update(rOutput
, rInput
);
77 void AgileEngine::calculateHashFinal(const OUString
& rPassword
, std::vector
<sal_uInt8
>& aHashFinal
)
79 sal_Int32 saltSize
= mInfo
.saltSize
;
80 std::vector
<sal_uInt8
>& salt
= mInfo
.saltValue
;
82 sal_uInt32 passwordByteLength
= rPassword
.getLength() * 2;
84 std::vector
<sal_uInt8
> initialData(saltSize
+ passwordByteLength
);
85 std::copy(salt
.begin(), salt
.end(), initialData
.begin());
87 const sal_uInt8
* passwordByteArray
= reinterpret_cast<const sal_uInt8
*>(rPassword
.getStr());
91 passwordByteArray
+ passwordByteLength
,
92 initialData
.begin() + saltSize
);
94 std::vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
96 hashCalc(hash
, initialData
, mInfo
.hashAlgorithm
);
98 std::vector
<sal_uInt8
> data(mInfo
.hashSize
+ 4, 0);
100 for (sal_Int32 i
= 0; i
< mInfo
.spinCount
; i
++)
102 ByteOrderConverter::writeLittleEndian(data
.data(), i
);
103 std::copy(hash
.begin(), hash
.end(), data
.begin() + 4);
104 hashCalc(hash
, data
, mInfo
.hashAlgorithm
);
107 std::copy(hash
.begin(), hash
.end(), aHashFinal
.begin());
110 bool AgileEngine::generateEncryptionKey(const OUString
& rPassword
)
112 static const std::vector
<sal_uInt8
> constBlock1
{ 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
113 static const std::vector
<sal_uInt8
> constBlock2
{ 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
114 static const std::vector
<sal_uInt8
> constBlock3
{ 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
117 mKey
.resize(mInfo
.keyBits
/ 8, 0);
119 std::vector
<sal_uInt8
> hashFinal(mInfo
.hashSize
, 0);
120 calculateHashFinal(rPassword
, hashFinal
);
122 std::vector
<sal_uInt8
>& encryptedHashInput
= mInfo
.encryptedVerifierHashInput
;
123 std::vector
<sal_uInt8
> hashInput(mInfo
.saltSize
, 0);
124 calculateBlock(constBlock1
, hashFinal
, encryptedHashInput
, hashInput
);
126 std::vector
<sal_uInt8
>& encryptedHashValue
= mInfo
.encryptedVerifierHashValue
;
127 std::vector
<sal_uInt8
> hashValue(encryptedHashValue
.size(), 0);
128 calculateBlock(constBlock2
, hashFinal
, encryptedHashValue
, hashValue
);
130 std::vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
131 hashCalc(hash
, hashInput
, mInfo
.hashAlgorithm
);
133 if (std::equal (hash
.begin(), hash
.end(), hashValue
.begin()) )
135 std::vector
<sal_uInt8
>& encryptedKeyValue
= mInfo
.encryptedKeyValue
;
136 calculateBlock(constBlock3
, hashFinal
, encryptedKeyValue
, mKey
);
143 bool AgileEngine::decrypt(BinaryXInputStream
& aInputStream
,
144 BinaryXOutputStream
& aOutputStream
)
146 sal_uInt32 totalSize
= aInputStream
.readuInt32(); // Document unencrypted size - 4 bytes
147 aInputStream
.skip(4); // Reserved 4 Bytes
149 std::vector
<sal_uInt8
>& keyDataSalt
= mInfo
.keyDataSalt
;
151 sal_uInt32 saltSize
= mInfo
.saltSize
;
152 sal_uInt32 keySize
= mInfo
.keyBits
/ 8;
154 sal_uInt32 segment
= 0;
156 std::vector
<sal_uInt8
> saltWithBlockKey(saltSize
+ sizeof(segment
), 0);
157 std::copy(keyDataSalt
.begin(), keyDataSalt
.end(), saltWithBlockKey
.begin());
159 std::vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
160 std::vector
<sal_uInt8
> iv(keySize
, 0);
162 std::vector
<sal_uInt8
> inputBuffer(constSegmentLength
);
163 std::vector
<sal_uInt8
> outputBuffer(constSegmentLength
);
164 sal_uInt32 inputLength
;
165 sal_uInt32 outputLength
;
166 sal_uInt32 remaining
= totalSize
;
168 while ((inputLength
= aInputStream
.readMemory(inputBuffer
.data(), constSegmentLength
)) > 0)
170 sal_uInt8
* segmentBegin
= reinterpret_cast<sal_uInt8
*>(&segment
);
171 sal_uInt8
* segmentEnd
= segmentBegin
+ sizeof(segment
);
172 std::copy(segmentBegin
, segmentEnd
, saltWithBlockKey
.begin() + saltSize
);
174 hashCalc(hash
, saltWithBlockKey
, mInfo
.hashAlgorithm
);
176 // Only if hash > keySize
177 std::copy(hash
.begin(), hash
.begin() + keySize
, iv
.begin());
179 Decrypt
aDecryptor(mKey
, iv
, AgileEngine::cryptoType(mInfo
));
180 outputLength
= aDecryptor
.update(outputBuffer
, inputBuffer
, inputLength
);
182 sal_uInt32 writeLength
= outputLength
> remaining
? remaining
: outputLength
;
183 aOutputStream
.writeMemory(outputBuffer
.data(), writeLength
);
185 remaining
-= outputLength
;
192 void AgileEngine::writeEncryptionInfo(
193 const OUString
& /*aPassword*/,
194 BinaryXOutputStream
& /*rStream*/)
196 // Agile encrypting is not supported for now
199 void AgileEngine::encrypt(
200 BinaryXInputStream
& /*aInputStream*/,
201 BinaryXOutputStream
& /*aOutputStream*/)
203 // Agile encrypting is not supported for now
209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */