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/Standard2007Engine.hxx"
14 #include <rtl/random.h>
21 /* =========================================================================== */
22 /* Kudos to Caolan McNamara who provided the core decryption implementations. */
23 /* =========================================================================== */
27 void lclRandomGenerateValues(sal_uInt8
* aArray
, sal_uInt32 aSize
)
30 osl_getSystemTime( &aTime
);
31 rtlRandomPool aRandomPool
= rtl_random_createPool ();
32 rtl_random_addBytes ( aRandomPool
, &aTime
, 8 );
33 rtl_random_getBytes ( aRandomPool
, aArray
, aSize
);
34 rtl_random_destroyPool ( aRandomPool
);
37 static const OUString lclCspName
= "Microsoft Enhanced RSA and AES Cryptographic Provider";
41 EncryptionStandardHeader::EncryptionStandardHeader()
53 EncryptionVerifierAES::EncryptionVerifierAES() :
54 saltSize(SALT_LENGTH
),
55 encryptedVerifierHashSize(Digest::DIGEST_LENGTH_SHA1
)
57 memset(salt
, 0, sizeof(salt
));
58 memset(encryptedVerifier
, 0, sizeof(encryptedVerifier
));
59 memset(encryptedVerifierHash
, 0, sizeof(encryptedVerifierHash
));
62 Standard2007Engine::Standard2007Engine() :
66 Standard2007Engine::~Standard2007Engine()
69 bool Standard2007Engine::generateVerifier()
71 // only support key of size 128 bit (16 byte)
72 if (mKey
.size() != 16)
75 sal_uInt32 outputLength
;
76 vector
<sal_uInt8
> verifier(ENCRYPTED_VERIFIER_LENGTH
);
77 vector
<sal_uInt8
> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH
);
79 lclRandomGenerateValues(&verifier
[0], verifier
.size());
82 Encrypt
aEncryptorVerifier(mKey
, iv
, Crypto::AES_128_ECB
);
83 outputLength
= aEncryptorVerifier
.update(encryptedVerifier
, verifier
);
84 if (outputLength
!= ENCRYPTED_VERIFIER_LENGTH
)
86 std::copy(encryptedVerifier
.begin(), encryptedVerifier
.end(), mInfo
.verifier
.encryptedVerifier
);
88 vector
<sal_uInt8
> hash(RTL_DIGEST_LENGTH_SHA1
, 0);
89 mInfo
.verifier
.encryptedVerifierHashSize
= RTL_DIGEST_LENGTH_SHA1
;
90 Digest::sha1(hash
, verifier
);
91 hash
.resize(ENCRYPTED_VERIFIER_HASH_LENGTH
, 0);
93 vector
<sal_uInt8
> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH
, 0);
95 Encrypt
aEncryptorHash(mKey
, iv
, Crypto::AES_128_ECB
);
96 outputLength
= aEncryptorHash
.update(encryptedHash
, hash
, hash
.size());
97 std::copy(encryptedHash
.begin(), encryptedHash
.end(), mInfo
.verifier
.encryptedVerifierHash
);
102 bool Standard2007Engine::calculateEncryptionKey(const OUString
& rPassword
)
104 sal_uInt32 saltSize
= mInfo
.verifier
.saltSize
;
105 sal_uInt32 passwordByteLength
= rPassword
.getLength() * 2;
106 const sal_uInt8
* saltArray
= mInfo
.verifier
.salt
;
108 // Prepare initial data -> salt + password (in 16-bit chars)
109 vector
<sal_uInt8
> initialData(saltSize
+ passwordByteLength
);
110 std::copy(saltArray
, saltArray
+ saltSize
, initialData
.begin());
112 const sal_uInt8
* passwordByteArray
= reinterpret_cast<const sal_uInt8
*>(rPassword
.getStr());
116 passwordByteArray
+ passwordByteLength
,
117 initialData
.begin() + saltSize
);
119 // use "hash" vector for result of sha1 hashing
120 vector
<sal_uInt8
> hash(Digest::DIGEST_LENGTH_SHA1
, 0);
122 // calculate SHA1 hash of initialData
123 Digest::sha1(hash
, initialData
);
125 // data = iterator (4bytes) + hash
126 vector
<sal_uInt8
> data(Digest::DIGEST_LENGTH_SHA1
+ 4, 0);
128 for (sal_Int32 i
= 0; i
< 50000; ++i
)
130 ByteOrderConverter::writeLittleEndian( &data
[0], i
);
131 std::copy(hash
.begin(), hash
.end(), data
.begin() + 4);
132 Digest::sha1(hash
, data
);
134 std::copy(hash
.begin(), hash
.end(), data
.begin() );
135 std::fill(data
.begin() + Digest::DIGEST_LENGTH_SHA1
, data
.end(), 0 );
137 Digest::sha1(hash
, data
);
140 vector
<sal_uInt8
> buffer(64, 0x36);
141 for( sal_uInt32 i
= 0; i
< hash
.size(); ++i
)
142 buffer
[i
] ^= hash
[i
];
144 Digest::sha1(hash
, buffer
);
145 std::copy(hash
.begin(), hash
.begin() + mKey
.size(), mKey
.begin());
150 bool Standard2007Engine::generateEncryptionKey(const OUString
& password
)
153 mKey
.resize(mInfo
.header
.keyBits
/ 8, 0);
155 calculateEncryptionKey(password
);
157 vector
<sal_uInt8
> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH
);
159 mInfo
.verifier
.encryptedVerifier
,
160 mInfo
.verifier
.encryptedVerifier
+ ENCRYPTED_VERIFIER_LENGTH
,
161 encryptedVerifier
.begin());
163 vector
<sal_uInt8
> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH
);
165 mInfo
.verifier
.encryptedVerifierHash
,
166 mInfo
.verifier
.encryptedVerifierHash
+ ENCRYPTED_VERIFIER_HASH_LENGTH
,
167 encryptedHash
.begin());
169 vector
<sal_uInt8
> verifier(encryptedVerifier
.size(), 0);
170 Decrypt::aes128ecb(verifier
, encryptedVerifier
, mKey
);
172 vector
<sal_uInt8
> verifierHash(encryptedHash
.size(), 0);
173 Decrypt::aes128ecb(verifierHash
, encryptedHash
, mKey
);
175 vector
<sal_uInt8
> hash(RTL_DIGEST_LENGTH_SHA1
, 0);
176 Digest::sha1(hash
, verifier
);
178 return std::equal( hash
.begin(), hash
.end(), verifierHash
.begin() );
181 bool Standard2007Engine::decrypt(
182 BinaryXInputStream
& aInputStream
,
183 BinaryXOutputStream
& aOutputStream
)
185 aInputStream
.skip(4); // Document unencrypted size - 4 bytes
186 aInputStream
.skip(4); // Reserved 4 Bytes
188 vector
<sal_uInt8
> iv
;
189 Decrypt
aDecryptor(mKey
, iv
, Crypto::AES_128_ECB
);
190 vector
<sal_uInt8
> inputBuffer (4096);
191 vector
<sal_uInt8
> outputBuffer(4096);
192 sal_uInt32 inputLength
;
193 sal_uInt32 outputLength
;
195 while( (inputLength
= aInputStream
.readMemory( &inputBuffer
[0], inputBuffer
.size() )) > 0 )
197 outputLength
= aDecryptor
.update(outputBuffer
, inputBuffer
, inputLength
);
198 aOutputStream
.writeMemory( &outputBuffer
[0], outputLength
);
203 bool Standard2007Engine::writeEncryptionInfo(const OUString
& password
, BinaryXOutputStream
& rStream
)
205 mInfo
.header
.flags
= ENCRYPTINFO_AES
| ENCRYPTINFO_CRYPTOAPI
;
206 mInfo
.header
.algId
= ENCRYPT_ALGO_AES128
;
207 mInfo
.header
.algIdHash
= ENCRYPT_HASH_SHA1
;
208 mInfo
.header
.keyBits
= ENCRYPT_KEY_SIZE_AES_128
;
209 mInfo
.header
.providedType
= ENCRYPT_PROVIDER_TYPE_AES
;
211 lclRandomGenerateValues(mInfo
.verifier
.salt
, mInfo
.verifier
.saltSize
);
212 const sal_Int32 keyLength
= mInfo
.header
.keyBits
/ 8;
215 mKey
.resize(keyLength
, 0);
217 if (!calculateEncryptionKey(password
))
220 if (!generateVerifier())
223 rStream
.WriteUInt32(VERSION_INFO_2007_FORMAT
);
225 sal_uInt32 cspNameSize
= (lclCspName
.getLength() * 2) + 2;
227 sal_uInt32 encryptionHeaderSize
= static_cast<sal_uInt32
>(sizeof(EncryptionStandardHeader
));
229 rStream
.WriteUInt32( mInfo
.header
.flags
);
230 sal_uInt32 headerSize
= encryptionHeaderSize
+ cspNameSize
;
231 rStream
.WriteUInt32( headerSize
);
233 rStream
.writeMemory(&mInfo
.header
, encryptionHeaderSize
);
234 rStream
.writeUnicodeArray(lclCspName
);
235 rStream
.WriteUInt16(0);
237 sal_uInt32 encryptionVerifierSize
= static_cast<sal_uInt32
>(sizeof(EncryptionVerifierAES
));
238 rStream
.writeMemory(&mInfo
.verifier
, encryptionVerifierSize
);
243 bool Standard2007Engine::encrypt(
244 BinaryXInputStream
& aInputStream
,
245 BinaryXOutputStream
& aOutputStream
)
247 vector
<sal_uInt8
> inputBuffer(1024);
248 vector
<sal_uInt8
> outputBuffer(1024);
250 sal_uInt32 inputLength
;
251 sal_uInt32 outputLength
;
253 vector
<sal_uInt8
> iv
;
254 Encrypt
aEncryptor(mKey
, iv
, Crypto::AES_128_ECB
);
256 while( (inputLength
= aInputStream
.readMemory( &inputBuffer
[0], inputBuffer
.size() )) > 0 )
258 inputLength
= inputLength
% 16 == 0 ? inputLength
: ((inputLength
/ 16) * 16) + 16;
259 outputLength
= aEncryptor
.update(outputBuffer
, inputBuffer
, inputLength
);
260 aOutputStream
.writeMemory( &outputBuffer
[0], outputLength
);
268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */