[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