[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    koffice/filters/kspread/excel
From:       Marijn Kruisselbrink <m.kruisselbrink () student ! tue ! nl>
Date:       2010-06-09 15:08:33
Message-ID: 20100609150833.1BC42AC8D1 () svn ! kde ! org
[Download RAW message or body]

SVN commit 1136341 by mkruisselbrink:

Add basic support for encrypted xls files. It's not yet possible to specify a \
password, and only one of the three possible encryption types is implemented. Also \
the filter should probably not give the same error message for a) No QCA2 found \
during compile time, b) No md5 support found in QCA2 at runtime, c) unsupported \
encryption type used in the file and d) incorrect password, but better error messages \
would also require some changes in the filter architecture I think.


 M  +4 -0      CMakeLists.txt  
 M  +4 -0      import/CMakeLists.txt  
 M  +4 -0      sidewinder/CMakeLists.txt  
 A             sidewinder/decrypt.cpp   [License: LGPL (v2+)]
 A             sidewinder/decrypt.h   [License: LGPL (v2+)]
 M  +7 -30     sidewinder/excel.cpp  
 M  +0 -34     sidewinder/excel.h  
 M  +44 -0     sidewinder/globalssubstreamhandler.cpp  
 M  +5 -0      sidewinder/globalssubstreamhandler.h  
 M  +21 -0     sidewinder/records.xml  
 M  +8 -0      sidewinder/recordsxml2cpp.cpp  
 M  +8 -0      sidewinder/utils.cpp  
 M  +1 -0      sidewinder/utils.h  


--- trunk/koffice/filters/kspread/excel/CMakeLists.txt #1136340:1136341
@@ -1,4 +1,8 @@
 
+if(QCA2_FOUND)
+    add_definitions( -DHAVE_QCA2 )
+    include_directories(${QCA2_INCLUDE_DIR})
+endif(QCA2_FOUND)
 
 add_subdirectory( sidewinder )
 add_subdirectory( import )
--- trunk/koffice/filters/kspread/excel/import/CMakeLists.txt #1136340:1136341
@@ -22,6 +22,7 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/formulas.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/utils.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/objects.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/decrypt.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/substreamhandler.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/globalssubstreamhandler.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/../sidewinder/worksheetsubstreamhandler.cpp
@@ -38,6 +39,9 @@
 
 
 target_link_libraries(excelimport msooxml komain)
+if(QCA2_FOUND)
+   target_link_libraries(excelimport ${QCA2_LIBRARIES})
+endif(QCA2_FOUND)
 
 install(TARGETS excelimport  DESTINATION ${PLUGIN_INSTALL_DIR})
 
--- trunk/koffice/filters/kspread/excel/sidewinder/CMakeLists.txt #1136340:1136341
@@ -25,6 +25,7 @@
   formulas.cpp
   utils.cpp
   objects.cpp
+  decrypt.cpp
   substreamhandler.cpp
   globalssubstreamhandler.cpp
   worksheetsubstreamhandler.cpp
@@ -36,3 +37,6 @@
 
 kde4_add_executable(sidewinder TEST ${sidewinder_SRCS})
 target_link_libraries(sidewinder ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
+if(QCA2_FOUND)
+   target_link_libraries(sidewinder ${QCA2_LIBRARIES})
+endif(QCA2_FOUND)
--- trunk/koffice/filters/kspread/excel/sidewinder/excel.cpp #1136340:1136341
@@ -652,30 +652,6 @@
 {
 }
 
-// ========== FILEPASS ==========
-
-const unsigned int FilepassRecord::id = 0x002f;
-
-FilepassRecord::FilepassRecord(Workbook *book)
-    : Record(book)
-{
-}
-
-FilepassRecord::~FilepassRecord()
-{
-}
-
-void FilepassRecord::setData(unsigned,  const unsigned char*, const unsigned int*)
-{
-    // TODO
-    std::cout << "TODO FilepassRecord::setData" << std::endl;
-}
-
-void FilepassRecord::dump(std::ostream& out) const
-{
-    out << "FILEPASS" << std::endl;
-}
-
 // ========== FORMULA ==========
 
 const unsigned int FormulaRecord::id = 0x0006;
@@ -2759,10 +2735,6 @@
 {
     return new ExternNameRecord(book);
 }
-static Record* createFilepassRecord(Workbook *book)
-{
-    return new FilepassRecord(book);
-}
 static Record* createFormulaRecord(Workbook *book)
 {
     return new FormulaRecord(book);
@@ -2821,7 +2793,6 @@
     RecordRegistry::registerRecordClass(BOFRecord::id, createBOFRecord);
     RecordRegistry::registerRecordClass(ExternBookRecord::id, \
                createExternBookRecord);
     RecordRegistry::registerRecordClass(ExternNameRecord::id, \
                createExternNameRecord);
-    RecordRegistry::registerRecordClass(FilepassRecord::id, createFilepassRecord);
     RecordRegistry::registerRecordClass(FormulaRecord::id, createFormulaRecord);
     RecordRegistry::registerRecordClass(SharedFormulaRecord::id, \
                createSharedFormulaRecord);
     RecordRegistry::registerRecordClass(MulRKRecord::id, createMulRKRecord);
@@ -3051,7 +3022,7 @@
         // this is set by FILEPASS record
         // subsequent records will need to be decrypted
         // since we do not support it yet, we have to bail out
-        if (d->globals->passwordProtected()) {
+        if (d->globals->passwordProtected() && \
!d->globals->encryptionTypeSupported()) {  d->workbook->setPasswordProtected(true);
             break;
         }
@@ -3063,6 +3034,8 @@
 
         unsigned long type = readU16(buffer);
         unsigned long size = readU16(buffer + 2);
+        d->globals->decryptionSkipBytes(4);
+
         unsigned int continuePositionsCount = 0;
 
         // verify buffer is large enough to hold the record data
@@ -3074,6 +3047,7 @@
         // load actual record data
         bytes_read = stream->read(buffer, size);
         if (bytes_read != size) break;
+        d->globals->decryptRecord(type, size, buffer);
 
         // save current position in stream, to be able to restore the position later \
on  unsigned long saved_pos;
@@ -3116,6 +3090,8 @@
                 std::cout << "ERROR!" << std::endl;
                 break;
             }
+            d->globals->decryptionSkipBytes(4);
+            d->globals->decryptRecord(next_type, next_size, buffer+size);
 
             // and finally update size
             size += next_size;
@@ -3149,6 +3125,7 @@
             record->setPosition(pos);
 
 #ifdef SWINDER_XLS2RAW
+            std::cout << std::setfill('0') << std::setw(8) << std::dec << \
record->position() << " ";  std::cout << "Record 0x";
             std::cout << std::setfill('0') << std::setw(4) << std::hex << \
record->rtti();  std::cout << " (";
--- trunk/koffice/filters/kspread/excel/sidewinder/excel.h #1136340:1136341
@@ -379,41 +379,7 @@
     Private *d;
 };
 
-class FilepassRecord : public Record
-{
-public:
-
-    static const unsigned int id;
-
-    unsigned int rtti() const {
-        return this->id;
-    }
-
     /**
-     * Creates a new FILEPASS record.
-     */
-    FilepassRecord(Workbook *book);
-
-    /**
-     * Destroy the record.
-     */
-    virtual ~FilepassRecord();
-
-    virtual void setData(unsigned size, const unsigned char* data, const unsigned \
                int* continuePositions);
-
-    virtual const char* name() const {
-        return "FILEPASS";
-    }
-
-    virtual void dump(std::ostream& out) const;
-
-private:
-    // no copy or assign
-    FilepassRecord(const FilepassRecord&);
-    FilepassRecord& operator=(const FilepassRecord&);
-};
-
-/**
   \brief Formula.
 
   Class FormulaRecord holds Formula record.
--- trunk/koffice/filters/kspread/excel/sidewinder/globalssubstreamhandler.cpp \
#1136340:1136341 @@ -26,6 +26,7 @@
 #include "excel.h"
 #include "sheet.h"
 #include "workbook.h"
+#include "decrypt.h"
 
 namespace Swinder
 {
@@ -53,6 +54,7 @@
     // password protection flag
     // TODO: password hash for record decryption
     bool passwordProtected;
+    RC4Decryption* decryption;
 
     // table of font
     std::vector<FontRecord> fontTable;
@@ -86,6 +88,7 @@
     d->workbook = workbook;
     d->version = version;
     d->passwordProtected = false;
+    d->decryption = 0;
 
     // initialize palette
     static const char *const default_palette[64-8] = { // default palette for all \
but the first 8 colors @@ -105,6 +108,7 @@
 
 GlobalsSubStreamHandler::~GlobalsSubStreamHandler()
 {
+    delete d->decryption;
     delete d;
 }
 
@@ -118,6 +122,36 @@
     return d->passwordProtected;
 }
 
+bool GlobalsSubStreamHandler::encryptionTypeSupported() const
+{
+    return d->decryption;
+}
+
+void GlobalsSubStreamHandler::decryptionSkipBytes(int count)
+{
+    if (d->decryption) d->decryption->skipBytes(count);
+}
+
+void GlobalsSubStreamHandler::decryptRecord(unsigned type, unsigned size, unsigned \
char* buffer) +{
+    if (!d->decryption) return;
+
+    if (type == BOFRecord::id ||
+        type == FilepassRecord::id ||
+        type == UsrExclRecord::id ||
+        type == FileLockRecord::id ||
+        type == InterfaceHdrRecord::id ||
+        type == RRDInfoRecord::id ||
+        type == RRDHeadRecord::id) {
+        d->decryption->skipBytes(size);
+    } else if (type == BoundSheetRecord::id && size >= 4) { /* skip only first 4 \
bytes */ +        d->decryption->skipBytes(4);
+        d->decryption->decryptBytes(size-4, buffer+4);
+    } else {
+        d->decryption->decryptBytes(size, buffer);
+    }
+}
+
 unsigned GlobalsSubStreamHandler::version() const
 {
     return d->version;
@@ -666,6 +700,16 @@
 {
     if (!record) return;
 
+    if (record->encryptionType() == FilepassRecord::RC4Encryption && \
record->encryptionVersionMajor() == 1) { +        d->decryption = new \
RC4Decryption(record->salt(), record->encryptedVerifier(), \
record->encryptedVerifierHash()); +        if \
(!d->decryption->checkPassword("VelvetSweatshop")) { +            delete \
d->decryption; +            fprintf(stderr, "Invalid password\n");
+        } else {
+            d->decryption->setInitialPosition(record->position() + 54+4);
+        }
+    }
+
     d->passwordProtected = true;
 }
 
--- trunk/koffice/filters/kspread/excel/sidewinder/globalssubstreamhandler.h \
#1136340:1136341 @@ -64,7 +64,12 @@
     virtual void handleRecord(Record* record);
 
     Workbook* workbook() const;
+
     bool passwordProtected() const;
+    bool encryptionTypeSupported() const;
+    void decryptionSkipBytes(int count);
+    void decryptRecord(unsigned type, unsigned size, unsigned char* buffer);
+
     unsigned version() const;
     Sheet* sheetFromPosition(unsigned position) const;
     UString stringFromSST(unsigned index) const;
--- trunk/koffice/filters/kspread/excel/sidewinder/records.xml #1136340:1136341
@@ -1171,4 +1171,25 @@
   </array>
 </record>
 
+<record name="Filepass" id="0x002f">
+  <field name="encryptionType" type="unsigned" size="16">
+    <enum name="XORObfuscation" value="0" />
+    <enum name="RC4Encryption"  value="1" />
+  </field>
+  <if predicate="encryptionType() == RC4Encryption">
+    <field name="encryptionVersionMajor" type="unsigned" size="16" />
+    <field name="encryptionVersionMinor" type="unsigned" size="16" />
+    <if predicate="encryptionVersionMajor() == 0x0001">
+      <field name="salt"                    type="blob" size="128" />
+      <field name="encryptedVerifier"       type="blob" size="128" />
+      <field name="encryptedVerifierHash"   type="blob" size="128" />
+    </if>
+  </if>
+</record>
+
+<record name="UsrExcl" id="0x0194" />
+<record name="FileLock" id="0x0195" />
+<record name="RRDInfo" id="0x0196" />
+<record name="RRDHead" id="0x0138" />
+
 </records>
--- trunk/koffice/filters/kspread/excel/sidewinder/recordsxml2cpp.cpp \
#1136340:1136341 @@ -65,6 +65,7 @@
     else if (xmlType == "float" || xmlType == "fixed") return "double";
     else if (xmlType == "bool") return "bool";
     else if (xmlType == "bytestring" || xmlType == "unicodestring") return \
"UString"; +    else if (xmlType == "blob") return "QByteArray";
     else if (extraTypes.contains(xmlType)) return getFieldType(extraTypes[xmlType], \
bits, otherType, extraTypes);  return "ERROR";
 }
@@ -266,6 +267,13 @@
                 << indent << "}\n";
                 out << indent << "curOffset += stringSize;\n";
                 sizeCheck(indent, out, field.nextSiblingElement(), offset, \
dynamicOffset); +            } else if (f.type == "QByteArray") {
+                out << indent << f.setterName() << "(" << setterArgs;
+                out << "QByteArray(reinterpret_cast<const char*>(";
+                out << "data";
+                if (dynamicOffset) out << " + curOffset";
+                if (offset) out << " + " << (offset / 8);
+                out << "), " << (bits / 8) << "));\n";
             } else if (bits % 8 == 0) {
                 if (f.isStringLength)
                     out << indent << "unsigned " << name << " = ";
--- trunk/koffice/filters/kspread/excel/sidewinder/utils.cpp #1136340:1136341
@@ -20,6 +20,7 @@
  */
 #include "utils.h"
 #include <string.h>
+#include <iomanip>
 
 namespace Swinder
 {
@@ -160,6 +161,13 @@
     return s;
 }
 
+std::ostream& operator<<(std::ostream& s, const QByteArray& d)
+{
+    s << std::hex << std::setfill('0');
+    for (int i = 0; i < d.size(); i++) s << " " << std::setw(2) << int((unsigned \
char)d[i]); +    return s;
+}
+
 Value errorAsValue(int errorCode)
 {
     Value result(Value::Error);
--- trunk/koffice/filters/kspread/excel/sidewinder/utils.h #1136340:1136341
@@ -150,6 +150,7 @@
 UString readUnicodeString(const void* data, unsigned length, unsigned maxSize = -1, \
bool* error = 0, unsigned* size = 0, unsigned continuePosition = -1);  
 std::ostream& operator<<(std::ostream& s, Swinder::UString ustring);
+std::ostream& operator<<(std::ostream& s, const QByteArray& data);
 
 inline QString string(const Swinder::UString& str)
 {


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic