LYX_OPTION(CONCEPT_CHECKS "Enable concept-checks" OFF GCC)
LYX_OPTION(QUIET "Don't generate verbose makefiles" OFF ALL)
LYX_OPTION(SHARED_LIBRARIES "Build shared libraries" OFF ALL)
+LYX_OPTION(ENCRYPTION "Build with encryption functionality" OFF ALL)
message(STATUS)
endif()
+
+
+
# Supress regeneration
set(CMAKE_SUPPRESS_REGENERATION TRUE)
add_subdirectory(boost)
endif()
+if(LYX_ENCRYPTION)
+ #Ubuntu: libssl-dev
+ find_package(OpenSSL REQUIRED)
+ add_definitions(-DLYX_ENCRYPTION)
+endif()
+
if(NOT LYX_USE_EXTERNAL_LIBINTL)
add_subdirectory(intl)
#cmakedefine WORDS_BIGENDIAN 1
-#cmakedefine HAVE_ASPELL_ASPELL_H 1
-#cmakedefine HAVE_ASPELL_H 1
+
#cmakedefine PACKAGE "${PACKAGE}"
#cmakedefine PACKAGE_VERSION "${PACKAGE_VERSION}"
#cmakedefine LYX_USE_TR1_REGEX 1
+
+
+
#endif
--- /dev/null
+# - Try to find the OpenSSL encryption library
+# Once done this will define
+#
+# OPENSSL_ROOT_DIR - Set this variable to the root installation of OpenSSL
+#
+# Read-Only variables:
+# OPENSSL_FOUND - system has the OpenSSL library
+# OPENSSL_INCLUDE_DIR - the OpenSSL include directory
+# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL
+
+#=============================================================================
+# Copyright 2006-2009 Kitware, Inc.
+# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
+# Copyright 2009-2010 Mathieu Malaterre <mathieu.malaterre@gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# http://www.slproweb.com/products/Win32OpenSSL.html
+SET(_OPENSSL_ROOT_HINTS
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
+ "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
+ )
+SET(_OPENSSL_ROOT_PATHS
+ "C:/OpenSSL/"
+ )
+FIND_PATH(OPENSSL_ROOT_DIR
+ NAMES include/openssl/ssl.h
+ HINTS ${_OPENSSL_ROOT_HINTS}
+ PATHS ${_OPENSSL_ROOT_PATHS}
+)
+MARK_AS_ADVANCED(OPENSSL_ROOT_DIR)
+
+# Re-use the previous path:
+FIND_PATH(OPENSSL_INCLUDE_DIR openssl/ssl.h
+ ${OPENSSL_ROOT_DIR}/include
+)
+
+IF(WIN32 AND NOT CYGWIN)
+ # MINGW should go here too
+ IF(MSVC)
+ # /MD and /MDd are the standard values - if someone wants to use
+ # others, the libnames have to change here too
+ # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b
+ # TODO: handle /MT and static lib
+ # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix:
+ # * MD for dynamic-release
+ # * MDd for dynamic-debug
+ # * MT for static-release
+ # * MTd for static-debug
+
+ # Implementation details:
+ # We are using the libraries located in the VC subdir instead of the parent directory eventhough :
+ # libeay32MD.lib is identical to ../libeay32.lib, and
+ # ssleay32MD.lib is identical to ../ssleay32.lib
+ FIND_LIBRARY(OPENSSL_LIB_EAY_DEBUG NAMES libeay32MDd libeay32
+ ${OPENSSL_ROOT_DIR}/lib/VC
+ )
+ FIND_LIBRARY(OPENSSL_LIB_EAY_RELEASE NAMES libeay32MD libeay32
+ ${OPENSSL_ROOT_DIR}/lib/VC
+ )
+ FIND_LIBRARY(OPENSSL_SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32 ssl
+ ${OPENSSL_ROOT_DIR}/lib/VC
+ )
+ FIND_LIBRARY(OPENSSL_SSL_EAY_RELEASE NAMES ssleay32MD ssleay32 ssl
+ ${OPENSSL_ROOT_DIR}/lib/VC
+ )
+ if( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE )
+ set( OPENSSL_LIBRARIES
+ optimized ${OPENSSL_SSL_EAY_RELEASE} ${OPENSSL_LIB_EAY_RELEASE}
+ debug ${OPENSSL_SSL_EAY_DEBUG} ${OPENSSL_LIB_EAY_DEBUG}
+ )
+ else()
+ set( OPENSSL_LIBRARIES ${OPENSSL_SSL_EAY_RELEASE} ${OPENSSL_LIB_EAY_RELEASE} )
+ endif()
+ MARK_AS_ADVANCED(OPENSSL_SSL_EAY_DEBUG OPENSSL_SSL_EAY_RELEASE)
+ MARK_AS_ADVANCED(OPENSSL_LIB_EAY_DEBUG OPENSSL_LIB_EAY_RELEASE)
+ ELSEIF(MINGW)
+ # same player, for MingW
+ FIND_LIBRARY(OPENSSL_LIB_EAY NAMES libeay32
+ ${OPENSSL_ROOT_DIR}/lib/MinGW
+ )
+ FIND_LIBRARY(OPENSSL_SSL_EAY NAMES ssleay32
+ ${OPENSSL_ROOT_DIR}/lib/MinGW
+ )
+ MARK_AS_ADVANCED(OPENSSL_SSL_EAY OPENSSL_LIB_EAY)
+ set( OPENSSL_LIBRARIES ${OPENSSL_SSL_EAY} ${OPENSSL_LIB_EAY} )
+ ELSE(MSVC)
+ # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues:
+ FIND_LIBRARY(OPENSSL_LIB_EAY NAMES libeay32
+ ${OPENSSL_ROOT_DIR}/lib
+ )
+ FIND_LIBRARY(OPENSSL_SSL_EAY NAMES ssleay32
+ ${OPENSSL_ROOT_DIR}/lib
+ )
+ MARK_AS_ADVANCED(OPENSSL_SSL_EAY LIB_EAY)
+ set( OPENSSL_LIBRARIES ${OPENSSL_SSL_EAY} ${OPENSSL_LIB_EAY} )
+ ENDIF(MSVC)
+ELSE(WIN32 AND NOT CYGWIN)
+
+ FIND_LIBRARY(OPENSSL_SSL_LIBRARIES NAMES ssl ssleay32 ssleay32MD)
+ FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARIES NAMES crypto)
+ MARK_AS_ADVANCED(OPENSSL_CRYPTO_LIBRARIES OPENSSL_SSL_LIBRARIES)
+
+ SET(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES})
+
+ENDIF(WIN32 AND NOT CYGWIN)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpenSSL DEFAULT_MSG
+ OPENSSL_LIBRARIES
+ OPENSSL_INCLUDE_DIR
+)
+
+set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} CACHE STRING "OpenSSL libs" FORCE)
+MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
+
${LIBINTL_LIBRARIES}
${ICONV_LIBRARY}
${QT_QTMAIN_LIBRARY}
- ${vld_dll})
+ ${vld_dll}
+ ${OPENSSL_LIBRARIES})
if (HUNSPELL_FOUND)
target_link_libraries(${_lyx} ${HUNSPELL_LIBRARY})
${TOP_SRC_DIR}/src/support/mythes
${QT_INCLUDES}
${ICONV_INCLUDE_DIR}
- ${ZLIB_INCLUDE_DIR})
+ ${ZLIB_INCLUDE_DIR}
+ ${OPENSSL_INCLUDE_DIR})
if(NOT LYX_MERGE_FILES)
${support_mythes_sources} ${support_linkback_sources} ${support_headers} ${dont_merge})
endif()
-target_link_libraries(support ${Lyx_Boost_Libraries} ${QT_QTCORE_LIBRARY} ${ZLIB_LIBRARY})
+target_link_libraries(support ${Lyx_Boost_Libraries} ${QT_QTCORE_LIBRARY} ${ZLIB_LIBRARY} ${OPENSSL_LIBRARIES})
lyx_add_gcc_pch(support)
${Lyx_Boost_Libraries}
${QT_QTCORE_LIBRARY}
${LIBINTL_LIBRARIES}
- ${ICONV_LIBRARY})
+ ${ICONV_LIBRARY}
+ ${OPENSSL_LIBRARIES})
if(WIN32)
target_link_libraries(${_tex2lyx} shlwapi ole32 psapi)
Item "Close All" "buffer-close-all"
Item "Save|S" "buffer-write"
Item "Save As...|A" "buffer-write-as"
+# Item "Save Encrypted" "buffer-write-encrypted"
Item "Save All|l" "buffer-write-all"
Item "Revert to Saved|R" "buffer-reload"
Submenu "Version Control|V" "file_vc"
LFUN_FORWARD_SEARCH,
LFUN_INSET_COPY_AS, // vfr, 20100419
LFUN_BUFFER_TOGGLE_OUTPUT_SYNC,
+ LFUN_BUFFER_WRITE_ENCRYPTED,
+ // 350
LFUN_LASTACTION // end of the table
};
* \endvar
*/
{ LFUN_BUFFER_WRITE, "buffer-write", ReadOnly, Buffer },
+/*!
+ * \var lyx::FuncCode lyx::LFUN_BUFFER_WRITE_ENCRYPTED
+ * \li Action: Saves the current buffer encyrpted.
+ * \li Notion: Saves the current buffer encyrpted to disk, asks for a new filename
+ * \li Syntax: buffer-write-encyrypted
+ * \endvar
+ */
+ { LFUN_BUFFER_WRITE_ENCRYPTED, "buffer-write-encrypted", ReadOnly, Buffer },
/*!
* \var lyx::FuncCode lyx::LFUN_BUFFER_WRITE_AS
* \li Action: Rename and save current buffer.
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file GuiEncryptionDialog.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Peter Kümmel
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "GuiEncryptionDialog.h"
+
+#include "qt_i18n.h"
+#include "support/qstring_helpers.h"
+
+#include <QHBoxLayout>
+#include <QGridLayout>
+
+
+namespace lyx {
+namespace frontend {
+
+
+GuiEncryptionDialog::GuiEncryptionDialog(QWidget *parent) : QDialog(parent)
+{
+ pwd_label_ = new QLabel(qt_("Password:"));
+ pwd_edit_ = new QLineEdit;
+ pwd_edit_->setEchoMode(QLineEdit::Password);
+ pwd_label_->setBuddy(pwd_edit_);
+
+ button_box_ = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ connect(button_box_, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(button_box_, SIGNAL(rejected()), this, SLOT(reject()));
+
+ QHBoxLayout *hLayout = new QHBoxLayout;
+ hLayout->addWidget(pwd_label_);
+ hLayout->addWidget(pwd_edit_);
+
+ QGridLayout *mainLayout = new QGridLayout;
+ mainLayout->setSizeConstraint(QLayout::SetFixedSize);
+ mainLayout->addLayout(hLayout, 0, 0);
+ mainLayout->addWidget(button_box_, 1, 0);
+ setLayout(mainLayout);
+}
+
+QString GuiEncryptionDialog::password() const
+{
+ return pwd_edit_->text();
+}
+
+void GuiEncryptionDialog::clearPassword()
+{
+ pwd_edit_->setText("");
+}
+
+
+} // namespace frontend
+} // namespace lyx
+
+#include "moc_GuiEncryptionDialog.cpp"
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file GuiEncryptionDialog.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Peter Kümmel
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef GUI_ENCRYPTION_DIALOG_H
+#define GUI_ENCRYPTION_DIALOG_H
+
+#include <QDialog>
+#include <QLabel>
+#include <QLineEdit>
+#include <QDialogButtonBox>
+#include <QPushButton>
+
+
+namespace lyx {
+namespace frontend {
+
+
+class GuiEncryptionDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ GuiEncryptionDialog(QWidget *parent = 0);
+
+ void clearPassword();
+ QString password() const;
+
+private:
+ QLabel * pwd_label_;
+ QLineEdit * pwd_edit_;
+ QDialogButtonBox * button_box_;
+};
+
+
+} // namespace frontend
+} // namespace lyx
+
+#endif
+
#include "LayoutBox.h"
#include "Menus.h"
#include "TocModel.h"
-
+#include "GuiProgress.h"
#include "qt_helpers.h"
#include "frontends/alert.h"
#include "Text.h"
#include "Toolbars.h"
#include "version.h"
+#include "GuiEncryptionDialog.h"
#include "support/convert.h"
#include "support/debug.h"
#include "support/Systemcall.h"
#include "support/Timeout.h"
#include "support/ProgressInterface.h"
-#include "GuiProgress.h"
+#include "support/CryptographicEncryption.h"
+
#include <QAction>
#include <QApplication>
#include <QToolBar>
#include <QUrl>
#include <QScrollBar>
-
-
+#include <QLineEdit>
+#include <QHBoxLayout>
+#include <QDialog>
+#include <QFile>
#define EXPORT_in_THREAD 1
break;
}
+ case LFUN_BUFFER_WRITE_ENCRYPTED:
+ enable = doc_buffer;
+ break;
+
case LFUN_BUFFER_WRITE_AS:
enable = doc_buffer;
break;
return FileName(fromqstr(result.second));
}
+/// checks if the file is encrypted and creates a decrypted tmp file
+#define LYX_ENC_VERSION 1
+static FileName decryptedFileName(FileName const & filename)
+{
+ if (!filename.isEncryptedFile()) {
+ return filename;
+ }
+
+ int encVersion = filename.encryptionVersion();
+ if (encVersion < 0 || encVersion > LYX_ENC_VERSION) {
+ Alert::error(_("Encryption"), _("This LyX program is to old to read encrypted file."));
+ return filename;
+ }
+
+ QByteArray encrypted;
+ QFile file(toqstr(filename.absFileName()));
+ if (file.open(QIODevice::ReadOnly)) {
+ encrypted = file.readAll();
+ } else {
+ return filename;
+ }
+
+ QByteArray key;
+ CryptographicEncryption enc;
+
+ int keytype = filename.encryptionKeytype();
+ if (keytype == CryptographicEncryption::Password) {
+ GuiEncryptionDialog dlg;
+ dlg.setWindowTitle(qt_("Enter Password"));
+ dlg.exec();
+ QString pwd = dlg.password();
+ key = enc.stringToKey(pwd);
+ } else {
+ Alert::error(_("Encryption"), _("Don't know how to generate decryption key."));
+ return filename;
+ }
+
+ // remove the encryption prefix
+ encrypted.remove(0, FileName::encryptionPrefix(LYX_ENC_VERSION, 1).size());
+
+ QByteArray decrypted;
+ if (!enc.decyrpt(encrypted, &decrypted, key)) {
+ Alert::error(_("Encryption"), _("Error when decryting file."));
+ return filename;
+ }
+
+ // TODO decrypt in memory
+ // TODO find a better solution than showing the
+ // generated filename
+ FileName tempDecrypted = FileName::tempName();
+ QFile defile(toqstr(tempDecrypted.absFileName()));
+ if (defile.open(QIODevice::WriteOnly)) {
+ defile.write(decrypted);
+ }
+
+ return tempDecrypted;
+}
+
-Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
+Buffer * GuiView::loadDocument(FileName const & filenameIn, bool tolastfiles)
{
setBusy(true);
+ FileName filename = decryptedFileName(filenameIn);
+
Buffer * newBuffer = checkAndLoadLyXFile(filename);
if (!newBuffer) {
}
-bool GuiView::saveBuffer(Buffer & b)
+bool GuiView::saveBuffer(Buffer & b, ostream* stream)
{
if (workArea(b) && workArea(b)->inDialogMode())
return true;
if (b.isUnnamed())
return renameBuffer(b, docstring());
- if (b.save()) {
+ if ( (stream ? b.write(*stream) : b.save()) ) {
theSession().lastFiles().add(b.fileName());
return true;
}
return false;
}
- return saveBuffer(b);
+ return saveBuffer(b, stream);
}
+bool GuiView::saveBufferEncrypted(Buffer & b)
+{
+ FileName fname = b.fileName();
+
+ // Switch to this Buffer.
+ setBuffer(&b);
+
+ // No argument? Ask user through dialog.
+ // FIXME UNICODE
+ FileDialog dlg(qt_("Choose a filename to export document"),
+ LFUN_BUFFER_WRITE_AS);
+ dlg.setButton1(qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
+ dlg.setButton2(qt_("Templates|#T#t"), toqstr(lyxrc.template_path));
+
+ if (!isLyXFileName(fname.absFileName()))
+ fname.changeExtension(".lyx");
+
+ FileDialog::Result result =
+ dlg.save(toqstr(fname.onlyPath().absFileName()),
+ QStringList(qt_("LyX Documents (*.lyx)")),
+ toqstr(fname.onlyFileName()));
+
+ if (result.first == FileDialog::Later)
+ return false;
+
+ fname.set(fromqstr(result.second));
+
+ if (fname.empty())
+ return false;
+
+ if (!isLyXFileName(fname.absFileName()))
+ fname.changeExtension(".lyx");
+
+
+ // fname is now the new Buffer location.
+ if (FileName(fname).exists()) {
+ docstring const file = makeDisplayPath(fname.absFileName(), 30);
+ docstring text = bformat(_("The document %1$s already "
+ "exists.\n\nDo you want to "
+ "overwrite that document?"),
+ file);
+ int const ret = Alert::prompt(_("Overwrite document?"),
+ text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
+ switch (ret) {
+ case 0: break;
+ case 1: break;
+ case 2: return false;
+ }
+ }
+
+ FileName oldauto = b.getAutosaveFileName();
+
+ // bring the autosave file with us, just in case.
+ b.moveAutosaveFile(oldauto);
+
+ stringbuf stringBuffer(ios::out|ios::trunc);
+ ostream stream(&stringBuffer);
+ if (!saveBuffer(b, &stream)) {
+ return false;
+ }
+
+ // the file has now been saved to the new location.
+ // we need to check that the locations of child buffers
+ // are still valid.
+ b.checkChildBuffers();
+
+ // get password
+ GuiEncryptionDialog pwddlg;
+ pwddlg.setWindowTitle(qt_("Enter Password"));
+ pwddlg.exec();
+ if (pwddlg.result() != QDialog::Accepted)
+ return false;
+ QString pwd = pwddlg.password();
+
+ pwddlg.setWindowTitle(qt_("Enter Password again"));
+ pwddlg.clearPassword();
+ pwddlg.exec();
+ if (pwddlg.result() != QDialog::Accepted)
+ return false;
+ QString pwd2 = pwddlg.password();
+
+ if (pwd != pwd2) {
+ Alert::error(_("Password"), _("Passwords do not match"));
+ return false;
+ }
+
+ string fileString = stringBuffer.str();
+ QByteArray data(fileString.c_str(), fileString.size());
+
+ CryptographicEncryption enc;
+ QByteArray key = enc.stringToKey(pwd);
+
+ QByteArray encrypted;
+ if (!enc.encyrpt(data, &encrypted, key)) {
+ Alert::error(_("Encryption"), _("Error when encrypting file"));
+ return false;
+ }
+
+ // check
+ QByteArray decrypted;
+ if (!enc.decyrpt(encrypted, &decrypted, key) || data != decrypted) {
+ Alert::error(_("Encryption"), _("Error when verifying encrypted file"));
+ return false;
+ }
+
+ QString guessStr = toqstr(FileName::encryptionPrefix(LYX_ENC_VERSION, CryptographicEncryption::Password));
+ QByteArray bytestoSave = guessStr.toAscii() + encrypted;
+
+ QFile file(toqstr(fname.absFileName()));
+ if (file.open(QIODevice::WriteOnly)) {
+ file.write(bytestoSave);
+ }
+
+ return true;
+}
+
bool GuiView::hideWorkArea(GuiWorkArea * wa)
{
return closeWorkArea(wa, false);
saveBuffer(*doc_buffer);
break;
+ case LFUN_BUFFER_WRITE_ENCRYPTED:
+ LASSERT(doc_buffer, break);
+ saveBufferEncrypted(*doc_buffer);
+ break;
+
case LFUN_BUFFER_WRITE_AS:
LASSERT(doc_buffer, break);
renameBuffer(*doc_buffer, cmd.argument());
*/
bool renameBuffer(Buffer & b, docstring const & newname);
///
- bool saveBuffer(Buffer & b);
+ bool saveBuffer(Buffer & b, std::ostream* stream = 0);
+ /// Gets a new filename and saves the buffer encrypted
+ bool saveBufferEncrypted(Buffer & b);
/// closes a workarea, if close_buffer is true the buffer will
/// also be released, otherwise the buffer will be hidden.
bool closeWorkArea(GuiWorkArea * wa, bool close_buffer);
GuiDelimiter.cpp \
GuiDialog.cpp \
GuiDocument.cpp \
+ GuiEncryptionDialog.cpp \
GuiErrorList.cpp \
GuiERT.cpp \
GuiExternal.cpp \
GuiDelimiter.h \
GuiDialog.h \
GuiDocument.h \
+ GuiEncryptionDialog.h \
GuiErrorList.h \
GuiERT.h \
GuiExternal.h \
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file CryptographicEncryption.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Peter Kümmel
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "CryptographicEncryption.h"
+
+#include <QDataStream>
+
+
+#ifdef LYX_ENCRYPTION
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#endif
+
+
+namespace lyx {
+namespace support {
+
+
+
+CryptographicEncryption::CryptographicEncryption()
+{
+}
+
+
+int CryptographicEncryption::blockAlign(int blockSize, QByteArray& bytes)
+{
+ int pad = 2 * blockSize - (bytes.size() % blockSize); // pad at least one block
+ bytes.append(QByteArray(pad, (char)pad));
+ return pad;
+}
+
+
+int CryptographicEncryption::blockDealign(QByteArray& bytes)
+{
+ int size = bytes.size();
+ if (size == 0)
+ return 0;
+ char padded = bytes.at(size - 1);
+ bytes.resize(size - padded);
+ return padded;
+}
+
+
+bool CryptographicEncryption::aesEnryption(QByteArray const & in, QByteArray* out, QByteArray const & key, bool encrypt)
+{
+#ifndef LYX_ENCRYPTION
+ (void) in;
+ (void) out;
+ (void) key;
+ (void) encrypt;
+ return false;
+#else
+ if (!out)
+ return false;
+
+ int keySize = key.size();
+ if (keySize != 16 && keySize != 24 && keySize != 32) {
+ return false;
+ }
+
+ // AES needs aligned data, but we must not touch already encrypted data
+ QByteArray aligned = in;
+ if (encrypt) {
+ blockAlign(AES_BLOCK_SIZE, aligned);
+ }
+ if ((aligned.size() % AES_BLOCK_SIZE) != 0) {
+ return false;
+ }
+
+ *out = QByteArray(aligned.size(), 0);
+ AES_KEY aeskey;
+ if (encrypt)
+ AES_set_encrypt_key((unsigned char*)key.constData(), keySize * 8, &aeskey);
+ else
+ AES_set_decrypt_key((unsigned char*)key.constData(), keySize * 8, &aeskey);
+
+ // use some arbitrary start values
+ unsigned char iv[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ AES_cbc_encrypt((unsigned char*)aligned.constData(),
+ (unsigned char*)out->data(),
+ aligned.size(), &aeskey, iv,
+ (encrypt ? AES_ENCRYPT : AES_DECRYPT));
+
+ if (!encrypt)
+ blockDealign(*out);
+
+ return true;
+#endif
+}
+
+
+QByteArray CryptographicEncryption::hash(QByteArray const & bytes, QCryptographicHash::Algorithm algorithm)
+{
+ QCryptographicHash hashAlgo(algorithm);
+ hashAlgo.addData(bytes);
+ return hashAlgo.result();
+}
+
+
+bool CryptographicEncryption::encyrpt(QByteArray const & plain, QByteArray* encrypted, QByteArray const & key)
+{
+ if (!encrypted)
+ return false;
+
+ QByteArray bytes;
+ QDataStream stream(&bytes, QIODevice::WriteOnly);
+ stream.setVersion(QDataStream::Qt_4_6);
+ stream << plain;
+ stream << hash(plain, QCryptographicHash::Md5);
+
+ if (!aesEnryption(bytes, encrypted, key, true)) {
+ encrypted->clear();
+ return false;
+ }
+
+ return true;
+}
+
+
+bool CryptographicEncryption::decyrpt(QByteArray const & encrypted, QByteArray* plain, QByteArray const & key)
+{
+ if (!plain)
+ return false;
+
+ QByteArray bytes;
+ if (!aesEnryption(encrypted, &bytes, key, false))
+ return false;
+
+ QByteArray decryptedHash;
+ QDataStream stream(bytes);
+ stream.setVersion(QDataStream::Qt_4_6);
+ stream >> *plain;
+ stream >> decryptedHash;
+
+ if (decryptedHash != hash(*plain, QCryptographicHash::Md5)) {
+ plain->clear();
+ return false;
+ }
+
+ return true;
+}
+
+
+QByteArray CryptographicEncryption::bytesToKey(QByteArray const & bytes)
+{
+#ifndef LYX_ENCRYPTION
+ (void) bytes;
+ return QByteArray();
+#else
+ const char* in = bytes.constData();
+ int iterations = 10000; // here we could adjust our paranoija
+ unsigned char out[64];
+ PKCS5_PBKDF2_HMAC_SHA1(in, bytes.size(), 0, 0, iterations, 32, out);
+
+ return QByteArray((const char*) out, 32);
+#endif
+}
+
+
+QByteArray CryptographicEncryption::stringToKey(QString const & str)
+{
+ QByteArray utf8 = str.toUtf8();
+ return bytesToKey(utf8);
+}
+
+
+
+
+
+}
+}
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file CryptographicEncryption.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Peter Kümmel
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef CRYPTOCRAPHIC_ENCYPTION_H
+#define CRYPTOCRAPHIC_ENCYPTION_H
+
+#include <QCryptographicHash>
+
+namespace lyx {
+namespace support {
+
+
+class CryptographicEncryption
+{
+public:
+ CryptographicEncryption();
+
+ enum Keytype {
+ Password = 0,
+ KeytypeCount
+ };
+
+ bool encyrpt(QByteArray const & plain, QByteArray * encrypted, QByteArray const & key);
+ bool decyrpt(QByteArray const & encrypted, QByteArray * plain, QByteArray const & key);
+
+ QByteArray bytesToKey(QByteArray const &);
+ QByteArray stringToKey(QString const &);
+
+private:
+ int blockAlign(int blockSize, QByteArray& bytes);
+ int blockDealign(QByteArray& bytes);
+ QByteArray hash(QByteArray const & bytes, QCryptographicHash::Algorithm);
+ bool aesEnryption(QByteArray const & in, QByteArray* out, QByteArray const & key, bool encrypt);
+};
+
+
+}
+}
+
+#endif
else if (contains(str, "BITPIX"))
format = "fits";
+
+ else if (contains(str, encryptionGuessString())) {
+ string ver = token(str, '-', 1);
+ string key = token(str, '-', 2);
+ format = encryptionGuessString() + "-" + ver + "-" + key;
+ }
}
// Dia knows also compressed form
}
+bool FileName::isEncryptedFile() const
+{
+ string const type = guessFormatFromContents();
+ string const guess = encryptionGuessString();
+ return toqstr(type).contains(toqstr(guess));
+}
+
+std::string FileName::encryptionGuessString()
+{
+ return "LyXEncrypted";
+}
+
+std::string FileName::encryptionPrefix(int version, int keytype)
+{
+ // A encrypted file starts with the bytes "LyXEncrypted-001-001-"
+ // the first number describes the encryption version which could
+ // change with the time. the second number describes how the key
+ // is generated, ATM only passwords are supported.
+ QString guess = toqstr(encryptionGuessString());
+ QString vstr = QString::number(version);
+ QString kstr = QString::number(keytype);
+ vstr = vstr.rightJustified(3, '0');
+ kstr = kstr.rightJustified(3, '0');
+ return fromqstr(guess + "-" + vstr + "-" + kstr + "-");
+}
+
+
+int FileName::encryptionVersion() const
+{
+ string const type = guessFormatFromContents();
+ string ver = token(type, '-', 1);
+ bool ok = false;
+ int version = toqstr(ver).toInt(&ok);
+ if (!ok)
+ return -1;
+ return version;
+}
+
+int FileName::encryptionKeytype() const
+{
+ string const type = guessFormatFromContents();
+ string ver = token(type, '-', 2);
+ bool ok = false;
+ int keytype = toqstr(ver).toInt(&ok);
+ if (!ok)
+ return -1;
+ return keytype;
+}
+
+
+
docstring const FileName::relPath(string const & path) const
{
// FIXME UNICODE
/// check for zipped file
bool isZippedFile() const;
+ /// check for zipped file
+ bool isEncryptedFile() const;
+ /// string which encypted LyX files starts
+ static std::string encryptionGuessString();
+ static std::string encryptionPrefix(int version, int keytype);
+ /// get version from guessbytes
+ int encryptionVersion() const;
+ /// get method how the key is generated
+ int encryptionKeytype() const;
+
static FileName fromFilesystemEncoding(std::string const & name);
/// (securely) create a temporary file with the given mask.
/// \p mask must be in filesystem encoding, if it contains a
convert.cpp \
convert.h \
copied_ptr.h \
+ CryptographicEncryption.h \
+ CryptographicEncryption.cpp \
debug.cpp \
debug.h \
docstream.cpp \