LCOV - code coverage report
Current view: top level - oox/source/crypto - Standard2007Engine.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 2 137 1.5 %
Date: 2014-11-03 Functions: 2 14 14.3 %
Legend: Lines: hit not hit

          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/Standard2007Engine.hxx"
      12             : 
      13             : #include <osl/time.h>
      14             : #include <rtl/random.h>
      15             : 
      16             : namespace oox {
      17             : namespace core {
      18             : 
      19             : using namespace std;
      20             : 
      21             : /* =========================================================================== */
      22             : /*  Kudos to Caolan McNamara who provided the core decryption implementations. */
      23             : /* =========================================================================== */
      24             : namespace
      25             : {
      26             : 
      27           0 : void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
      28             : {
      29             :     TimeValue aTime;
      30           0 :     osl_getSystemTime( &aTime );
      31           0 :     rtlRandomPool aRandomPool = rtl_random_createPool ();
      32           0 :     rtl_random_addBytes ( aRandomPool, &aTime, 8 );
      33           0 :     rtl_random_getBytes ( aRandomPool, aArray, aSize );
      34           0 :     rtl_random_destroyPool ( aRandomPool );
      35           0 : }
      36             : 
      37         136 : static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
      38             : 
      39             : } // namespace
      40             : 
      41           0 : EncryptionStandardHeader::EncryptionStandardHeader()
      42             : {
      43           0 :     flags        = 0;
      44           0 :     sizeExtra    = 0;
      45           0 :     algId        = 0;
      46           0 :     algIdHash    = 0;
      47           0 :     keyBits      = 0;
      48           0 :     providedType = 0;
      49           0 :     reserved1    = 0;
      50           0 :     reserved2    = 0;
      51           0 : }
      52             : 
      53           0 : EncryptionVerifierAES::EncryptionVerifierAES() :
      54             :     saltSize(SALT_LENGTH),
      55           0 :     encryptedVerifierHashSize(Digest::DIGEST_LENGTH_SHA1)
      56             : {
      57           0 :     memset(salt, 0, sizeof(salt));
      58           0 :     memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
      59           0 :     memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
      60           0 : }
      61             : 
      62           0 : Standard2007Engine::Standard2007Engine() :
      63           0 :     CryptoEngine()
      64           0 : {}
      65             : 
      66           0 : Standard2007Engine::~Standard2007Engine()
      67           0 : {}
      68             : 
      69           0 : bool Standard2007Engine::generateVerifier()
      70             : {
      71             :     // only support key of size 128 bit (16 byte)
      72           0 :     if (mKey.size() != 16)
      73           0 :         return false;
      74             : 
      75             :     sal_uInt32 outputLength;
      76           0 :     vector<sal_uInt8> verifier(ENCRYPTED_VERIFIER_LENGTH);
      77           0 :     vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
      78             : 
      79           0 :     lclRandomGenerateValues(&verifier[0], verifier.size());
      80             : 
      81           0 :     vector<sal_uInt8> iv;
      82           0 :     Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
      83           0 :     outputLength = aEncryptorVerifier.update(encryptedVerifier, verifier);
      84           0 :     if (outputLength != ENCRYPTED_VERIFIER_LENGTH)
      85           0 :         return false;
      86           0 :     std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
      87             : 
      88           0 :     vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
      89           0 :     mInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
      90           0 :     Digest::sha1(hash, verifier);
      91           0 :     hash.resize(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
      92             : 
      93           0 :     vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
      94             : 
      95           0 :     Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
      96           0 :     outputLength = aEncryptorHash.update(encryptedHash, hash, hash.size());
      97           0 :     std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
      98             : 
      99           0 :     return true;
     100             : }
     101             : 
     102           0 : bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
     103             : {
     104           0 :     sal_uInt32 saltSize = mInfo.verifier.saltSize;
     105           0 :     sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
     106           0 :     const sal_uInt8* saltArray = mInfo.verifier.salt;
     107             : 
     108             :     // Prepare initial data -> salt + password (in 16-bit chars)
     109           0 :     vector<sal_uInt8> initialData(saltSize + passwordByteLength);
     110           0 :     std::copy(saltArray, saltArray + saltSize, initialData.begin());
     111             : 
     112           0 :     const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
     113             : 
     114             :     std::copy(
     115             :         passwordByteArray,
     116             :         passwordByteArray + passwordByteLength,
     117           0 :         initialData.begin() + saltSize);
     118             : 
     119             :     // use "hash" vector for result of sha1 hashing
     120           0 :     vector<sal_uInt8> hash(Digest::DIGEST_LENGTH_SHA1, 0);
     121             : 
     122             :     // calculate SHA1 hash of initialData
     123           0 :     Digest::sha1(hash, initialData);
     124             : 
     125             :     // data = iterator (4bytes) + hash
     126           0 :     vector<sal_uInt8> data(Digest::DIGEST_LENGTH_SHA1 + 4, 0);
     127             : 
     128           0 :     for (sal_Int32 i = 0; i < 50000; ++i)
     129             :     {
     130           0 :         ByteOrderConverter::writeLittleEndian( &data[0], i );
     131           0 :         std::copy(hash.begin(), hash.end(), data.begin() + 4);
     132           0 :         Digest::sha1(hash, data);
     133             :     }
     134           0 :     std::copy(hash.begin(), hash.end(), data.begin() );
     135           0 :     std::fill(data.begin() + Digest::DIGEST_LENGTH_SHA1, data.end(), 0 );
     136             : 
     137           0 :     Digest::sha1(hash, data);
     138             : 
     139             :     // derive key
     140           0 :     vector<sal_uInt8> buffer(64, 0x36);
     141           0 :     for( sal_uInt32 i = 0; i < hash.size(); ++i )
     142           0 :         buffer[i] ^= hash[i];
     143             : 
     144           0 :     Digest::sha1(hash, buffer);
     145           0 :     std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
     146             : 
     147           0 :     return true;
     148             : }
     149             : 
     150           0 : bool Standard2007Engine::generateEncryptionKey(const OUString& password)
     151             : {
     152           0 :     mKey.clear();
     153           0 :     mKey.resize(mInfo.header.keyBits / 8, 0);
     154             : 
     155           0 :     calculateEncryptionKey(password);
     156             : 
     157           0 :     vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
     158             :     std::copy(
     159             :         mInfo.verifier.encryptedVerifier,
     160             :         mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
     161           0 :         encryptedVerifier.begin());
     162             : 
     163           0 :     vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH);
     164             :     std::copy(
     165             :         mInfo.verifier.encryptedVerifierHash,
     166             :         mInfo.verifier.encryptedVerifierHash + ENCRYPTED_VERIFIER_HASH_LENGTH,
     167           0 :         encryptedHash.begin());
     168             : 
     169           0 :     vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
     170           0 :     Decrypt::aes128ecb(verifier, encryptedVerifier, mKey);
     171             : 
     172           0 :     vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
     173           0 :     Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
     174             : 
     175           0 :     vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
     176           0 :     Digest::sha1(hash, verifier);
     177             : 
     178           0 :     return std::equal( hash.begin(), hash.end(), verifierHash.begin() );
     179             : }
     180             : 
     181           0 : bool Standard2007Engine::decrypt(
     182             :                             BinaryXInputStream& aInputStream,
     183             :                             BinaryXOutputStream& aOutputStream)
     184             : {
     185             :     sal_uInt32 totalSize;
     186           0 :     aInputStream >> totalSize; // Document unencrypted size - 4 bytes
     187           0 :     aInputStream.skip( 4 );    // Reserved 4 Bytes
     188             : 
     189           0 :     vector<sal_uInt8> iv;
     190           0 :     Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
     191           0 :     vector<sal_uInt8> inputBuffer (4096);
     192           0 :     vector<sal_uInt8> outputBuffer(4096);
     193             :     sal_uInt32 inputLength;
     194             :     sal_uInt32 outputLength;
     195             : 
     196           0 :     while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
     197             :     {
     198           0 :         outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
     199           0 :         aOutputStream.writeMemory( &outputBuffer[0], outputLength );
     200             :     }
     201           0 :     return true;
     202             : }
     203             : 
     204           0 : bool Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
     205             : {
     206           0 :     mInfo.header.flags        = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
     207           0 :     mInfo.header.algId        = ENCRYPT_ALGO_AES128;
     208           0 :     mInfo.header.algIdHash    = ENCRYPT_HASH_SHA1;
     209           0 :     mInfo.header.keyBits      = ENCRYPT_KEY_SIZE_AES_128;
     210           0 :     mInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
     211             : 
     212           0 :     lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
     213           0 :     const sal_Int32 keyLength = mInfo.header.keyBits / 8;
     214             : 
     215           0 :     mKey.clear();
     216           0 :     mKey.resize(keyLength, 0);
     217             : 
     218           0 :     if (!calculateEncryptionKey(password))
     219           0 :         return false;
     220             : 
     221           0 :     if (!generateVerifier())
     222           0 :         return false;
     223             : 
     224           0 :     rStream.writeValue(VERSION_INFO_2007_FORMAT);
     225             : 
     226           0 :     sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
     227             : 
     228           0 :     sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
     229             : 
     230           0 :     rStream << mInfo.header.flags;
     231           0 :     sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
     232           0 :     rStream << headerSize;
     233             : 
     234           0 :     rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
     235           0 :     rStream.writeUnicodeArray(lclCspName);
     236           0 :     rStream.writeValue<sal_uInt16>(0);
     237             : 
     238           0 :     sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
     239           0 :     rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
     240             : 
     241           0 :     return true;
     242             : }
     243             : 
     244           0 : bool Standard2007Engine::encrypt(
     245             :                             BinaryXInputStream& aInputStream,
     246             :                             BinaryXOutputStream& aOutputStream)
     247             : {
     248           0 :     vector<sal_uInt8> inputBuffer(1024);
     249           0 :     vector<sal_uInt8> outputBuffer(1024);
     250             : 
     251             :     sal_uInt32 inputLength;
     252             :     sal_uInt32 outputLength;
     253             : 
     254           0 :     vector<sal_uInt8> iv;
     255           0 :     Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
     256             : 
     257           0 :     while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
     258             :     {
     259           0 :         inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
     260           0 :         outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
     261           0 :         aOutputStream.writeMemory( &outputBuffer[0], outputLength );
     262             :     }
     263           0 :     return true;
     264             : }
     265             : 
     266             : } // namespace core
     267         408 : } // namespace oox
     268             : 
     269             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10