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 Digest::sha1(output
, input
);
30 else if (algorithm
== "SHA512")
31 return Digest::sha512(output
, input
);
37 AgileEngine::AgileEngine() :
41 AgileEngine::~AgileEngine()
44 Crypto::CryptoType
AgileEngine::cryptoType(const AgileEncryptionInfo
& rInfo
)
46 if (rInfo
.keyBits
== 128 && rInfo
.cipherAlgorithm
== "AES" && rInfo
.cipherChaining
== "ChainingModeCBC")
47 return Crypto::AES_128_CBC
;
48 else if (rInfo
.keyBits
== 256 && rInfo
.cipherAlgorithm
== "AES" && rInfo
.cipherChaining
== "ChainingModeCBC")
49 return Crypto::AES_256_CBC
;
50 return Crypto::UNKNOWN
;
53 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
)
60 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
61 vector
<sal_uInt8
> salt
= mInfo
.saltValue
;
62 vector
<sal_uInt8
> dataFinal(mInfo
.hashSize
+ aBlockSize
, 0);
63 std::copy(rHashFinal
.begin(), rHashFinal
.end(), dataFinal
.begin());
67 dataFinal
.begin() + mInfo
.hashSize
);
69 hashCalc(hash
, dataFinal
, mInfo
.hashAlgorithm
);
71 sal_Int32 keySize
= mInfo
.keyBits
/ 8;
72 vector
<sal_uInt8
> key(keySize
, 0);
74 std::copy(hash
.begin(), hash
.begin() + keySize
, key
.begin());
76 Decrypt
aDecryptor(key
, salt
, cryptoType(mInfo
));
77 aDecryptor
.update(rOutput
, rInput
);
82 bool AgileEngine::calculateHashFinal(const OUString
& rPassword
, vector
<sal_uInt8
>& aHashFinal
)
84 sal_Int32 saltSize
= mInfo
.saltSize
;
85 vector
<sal_uInt8
> salt
= mInfo
.saltValue
;
86 sal_uInt32 passwordByteLength
= rPassword
.getLength() * 2;
88 vector
<sal_uInt8
> initialData(saltSize
+ passwordByteLength
);
89 std::copy(salt
.begin(), salt
.end(), initialData
.begin());
91 const sal_uInt8
* passwordByteArray
= reinterpret_cast<const sal_uInt8
*>(rPassword
.getStr());
95 passwordByteArray
+ passwordByteLength
,
96 initialData
.begin() + saltSize
);
98 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
100 hashCalc(hash
, initialData
, mInfo
.hashAlgorithm
);
102 vector
<sal_uInt8
> data(mInfo
.hashSize
+ 4, 0);
104 for (sal_Int32 i
= 0; i
< mInfo
.spinCount
; i
++)
106 ByteOrderConverter::writeLittleEndian( &data
[0], i
);
107 std::copy(hash
.begin(), hash
.end(), data
.begin() + 4);
108 hashCalc(hash
, data
, mInfo
.hashAlgorithm
);
111 std::copy(hash
.begin(), hash
.end(), aHashFinal
.begin());
116 bool AgileEngine::generateEncryptionKey(const OUString
& rPassword
)
119 mKey
.resize(mInfo
.keyBits
/ 8, 0);
121 vector
<sal_uInt8
> hashFinal(mInfo
.hashSize
, 0);
122 calculateHashFinal(rPassword
, hashFinal
);
124 vector
<sal_uInt8
> encryptedHashInput
= mInfo
.encryptedVerifierHashInput
;
125 vector
<sal_uInt8
> hashInput(mInfo
.saltSize
, 0);
126 calculateBlock(constBlock1
, sizeof(constBlock1
), hashFinal
, encryptedHashInput
, hashInput
);
128 vector
<sal_uInt8
> encryptedHashValue
= mInfo
.encryptedVerifierHashValue
;
129 vector
<sal_uInt8
> hashValue(encryptedHashValue
.size(), 0);
130 calculateBlock(constBlock2
, sizeof(constBlock2
), hashFinal
, encryptedHashValue
, hashValue
);
132 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
133 hashCalc(hash
, hashInput
, mInfo
.hashAlgorithm
);
135 if (std::equal (hash
.begin(), hash
.end(), hashValue
.begin()) )
137 vector
<sal_uInt8
> encryptedKeyValue
= mInfo
.encryptedKeyValue
;
138 calculateBlock(constBlock3
, sizeof(constBlock3
), hashFinal
, encryptedKeyValue
, mKey
);
145 bool AgileEngine::decrypt(
146 BinaryXInputStream
& aInputStream
,
147 BinaryXOutputStream
& aOutputStream
)
149 sal_uInt32 totalSize
= aInputStream
.readuInt32(); // Document unencrypted size - 4 bytes
150 aInputStream
.skip( 4 ); // Reserved 4 Bytes
152 vector
<sal_uInt8
> keyDataSalt
= mInfo
.keyDataSalt
;
154 sal_uInt32 saltSize
= mInfo
.saltSize
;
155 sal_uInt32 keySize
= mInfo
.keyBits
/ 8;
157 sal_uInt32 segment
= 0;
159 vector
<sal_uInt8
> saltWithBlockKey(saltSize
+ sizeof(segment
), 0);
160 std::copy(keyDataSalt
.begin(), keyDataSalt
.end(), saltWithBlockKey
.begin());
162 vector
<sal_uInt8
> hash(mInfo
.hashSize
, 0);
163 vector
<sal_uInt8
> iv(keySize
, 0);
165 vector
<sal_uInt8
> inputBuffer (SEGMENT_LENGTH
);
166 vector
<sal_uInt8
> outputBuffer(SEGMENT_LENGTH
);
167 sal_uInt32 inputLength
;
168 sal_uInt32 outputLength
;
169 sal_uInt32 remaining
= totalSize
;
171 while( (inputLength
= aInputStream
.readMemory( &inputBuffer
[0], SEGMENT_LENGTH
)) > 0 )
173 sal_uInt8
* segmentBegin
= reinterpret_cast<sal_uInt8
*>(&segment
);
174 sal_uInt8
* segmentEnd
= segmentBegin
+ sizeof(segment
);
175 std::copy(segmentBegin
, segmentEnd
, saltWithBlockKey
.begin() + saltSize
);
177 hashCalc(hash
, saltWithBlockKey
, mInfo
.hashAlgorithm
);
179 // Only if hash > keySize
180 std::copy(hash
.begin(), hash
.begin() + keySize
, iv
.begin());
182 Decrypt
aDecryptor(mKey
, iv
, AgileEngine::cryptoType(mInfo
));
183 outputLength
= aDecryptor
.update(outputBuffer
, inputBuffer
, inputLength
);
185 sal_uInt32 writeLength
= outputLength
> remaining
? remaining
: outputLength
;
186 aOutputStream
.writeMemory( &outputBuffer
[0], writeLength
);
188 remaining
-= outputLength
;
195 bool AgileEngine::writeEncryptionInfo(
196 const OUString
& /*aPassword*/,
197 BinaryXOutputStream
& /*rStream*/)
199 return false; // Agile encrypting is not supported for now
202 bool AgileEngine::encrypt(
203 BinaryXInputStream
& /*aInputStream*/,
204 BinaryXOutputStream
& /*aOutputStream*/)
206 return false; // Agile encrypting is not supported for now
212 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */