From a045f574309532b3d3359de26fde3dac33a2800d Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Mon, 25 May 2020 18:24:18 +0300 Subject: [PATCH] . --- .../3dParty/openssl/common/common_openssl.cpp | 486 ++++++++++++++++++ .../3dParty/openssl/common/common_openssl.h | 94 ++++ Common/3dParty/openssl/openssl.pri | 21 +- Common/3dParty/openssl/test/main.cpp | 94 ++++ Common/3dParty/openssl/test/test.pro | 28 + OfficeCryptReader/Test/Test.cpp | 16 +- OfficeCryptReader/ooxml_crypt/main.cpp | 314 +++++++++++ OfficeCryptReader/ooxml_crypt/ooxml_crypt.pro | 56 ++ OfficeCryptReader/source/ECMACryptFile.cpp | 53 ++ OfficeCryptReader/source/ECMACryptFile.h | 5 +- 10 files changed, 1149 insertions(+), 18 deletions(-) create mode 100644 Common/3dParty/openssl/common/common_openssl.cpp create mode 100644 Common/3dParty/openssl/common/common_openssl.h create mode 100644 Common/3dParty/openssl/test/main.cpp create mode 100644 Common/3dParty/openssl/test/test.pro create mode 100644 OfficeCryptReader/ooxml_crypt/main.cpp create mode 100644 OfficeCryptReader/ooxml_crypt/ooxml_crypt.pro diff --git a/Common/3dParty/openssl/common/common_openssl.cpp b/Common/3dParty/openssl/common/common_openssl.cpp new file mode 100644 index 0000000000..98573f78f1 --- /dev/null +++ b/Common/3dParty/openssl/common/common_openssl.cpp @@ -0,0 +1,486 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ + +#include "./common_openssl.h" +#include +#include +#include +#include +#include +#include + +namespace NSOpenSSL +{ + unsigned char* openssl_alloc(unsigned int len) + { + return (unsigned char*)malloc(len); + } + void openssl_free(unsigned char* data) + { + free(data); + } + + // hash + unsigned int GetHashSize(const int& alg) + { + switch (alg) + { + case OPENSSL_HASH_ALG_SHA1: + return 20; + case OPENSSL_HASH_ALG_SHA224: + return 28; + case OPENSSL_HASH_ALG_SHA256: + return 32; + case OPENSSL_HASH_ALG_SHA384: + return 48; + case OPENSSL_HASH_ALG_SHA512: + return 64; + default: + break; + } + return 0; + } + + unsigned char* GetHash(const unsigned char* data, const unsigned int& size, const int& alg, unsigned int& len) + { + len = GetHashSize(alg); + if (0 == len) + return NULL; + unsigned char* res = openssl_alloc(len); + switch (alg) + { + case OPENSSL_HASH_ALG_SHA1: + SHA1(data, (size_t)size, res); + break; + case OPENSSL_HASH_ALG_SHA224: + SHA224(data, (size_t)size, res); + break; + case OPENSSL_HASH_ALG_SHA256: + SHA256(data, (size_t)size, res); + break; + case OPENSSL_HASH_ALG_SHA384: + SHA384(data, (size_t)size, res); + break; + case OPENSSL_HASH_ALG_SHA512: + SHA512(data, (size_t)size, res); + break; + default: + break; + } + return res; + } + + // rsa + bool RSA_GenerateKeys(unsigned char*& publicKey, unsigned char*& privateKey) + { + publicKey = NULL; + privateKey = NULL; + + RSA* rsa = RSA_new(); + BIGNUM *exponent = BN_new(); + + BN_set_word(exponent, RSA_F4); + int result = RSA_generate_multi_prime_key(rsa, 2048, 2, exponent, NULL); + if (0 == result) + return false; + + if (true) + { + BIO* bio = BIO_new(BIO_s_mem()); + if (PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL)) + { + int key_length = BIO_pending(bio); + privateKey = openssl_alloc(key_length + 1); + if (key_length != BIO_read(bio, privateKey, key_length)) + { + openssl_free(privateKey); + privateKey = NULL; + } + else + { + privateKey[key_length] = '\0'; + } + } + BIO_free_all(bio); + } + if (true) + { + BIO* bio = BIO_new(BIO_s_mem()); + if (PEM_write_bio_RSA_PUBKEY(bio, rsa)) + { + int key_length = BIO_pending(bio); + publicKey = openssl_alloc(key_length + 1); + if (key_length != BIO_read(bio, publicKey, key_length)) + { + openssl_free(publicKey); + publicKey = NULL; + } + else + { + publicKey[key_length] = '\0'; + } + } + BIO_free_all(bio); + } + + BN_free(exponent); + RSA_free(rsa); + + return (NULL != publicKey && NULL != privateKey) ? true : false; + } + + //#define USE_DEPRECATED + bool RSA_EncryptPublic(const unsigned char* publicKey, const unsigned char* data, const unsigned int& size, unsigned char*& data_crypt, unsigned int& data_crypt_len) + { + BIO* bio = BIO_new_mem_buf(publicKey, (int)strlen((char*)publicKey)); + +#ifdef USE_DEPRECATED + RSA* rsa = RSA_new(); + RSA* resrsa = PEM_read_bio_RSA_PUBKEY(bio, &rsa, 0, NULL); + + unsigned int key_size = (unsigned int)RSA_size(rsa); + data_crypt = openssl_alloc(key_size); + + int res = RSA_public_encrypt((int)size, data, data_crypt, rsa, RSA_NO_PADDING); + data_crypt_len = key_size; + + BIO_free(bio); + RSA_free(rsa); + return (-1 != res) ? true : false; +#else + EVP_PKEY* publicKeyEngine = NULL; + PEM_read_bio_PUBKEY(bio, &publicKeyEngine, 0, NULL); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(publicKeyEngine, NULL); + EVP_PKEY_encrypt_init(ctx); + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING); + + size_t out_len = 0; + EVP_PKEY_encrypt(ctx, NULL, &out_len, data, (size_t)size); + + data_crypt = openssl_alloc((unsigned int)out_len); + + EVP_PKEY_encrypt(ctx, data_crypt, &out_len, data, (size_t)size); + data_crypt_len = (unsigned int)out_len; + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(publicKeyEngine); + BIO_free(bio); + + return (out_len > 0) ? true : false; +#endif + } + + bool RSA_DecryptPrivate(const unsigned char* privateKey, const unsigned char* data, const unsigned int& size, unsigned char*& data_decrypt, unsigned int& data_decrypt_len) + { + BIO* bio = BIO_new_mem_buf(privateKey, (int)strlen((char*)privateKey)); + +#ifdef USE_DEPRECATED + RSA* rsa = RSA_new(); + PEM_read_bio_RSAPrivateKey(bio, &rsa, 0, NULL); + + unsigned int key_size = (unsigned int)RSA_size(rsa); + data_decrypt = openssl_alloc(key_size); + + int res = RSA_private_decrypt((int)size, data, data_decrypt, rsa, RSA_NO_PADDING); + data_decrypt_len = key_size; + + BIO_free(bio); + RSA_free(rsa); + return (-1 != res) ? true : false; +#else + EVP_PKEY* privateKeyEngine = NULL; + PEM_read_bio_PrivateKey(bio, &privateKeyEngine, 0, NULL); + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(privateKeyEngine, NULL); + EVP_PKEY_decrypt_init(ctx); + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING); + + size_t out_len = 0; + EVP_PKEY_decrypt(ctx, NULL, &out_len, data, (size_t)size); + + data_decrypt = openssl_alloc((unsigned int)out_len); + + EVP_PKEY_decrypt(ctx, data_decrypt, &out_len, data, (size_t)size); + data_decrypt_len = (unsigned int)out_len; + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(privateKeyEngine); + BIO_free(bio); + + return (out_len > 0) ? true : false; +#endif + } + + bool RSA_EncryptPublic_desktop(const unsigned char* publicKey, const std::string& input, std::string& out) + { + unsigned char* out_ptr = NULL; + unsigned int out_ptr_len = 0; + + if (!RSA_EncryptPublic(publicKey, (unsigned char*)input.c_str(), (unsigned int)input.length(), out_ptr, out_ptr_len)) + return false; + + out = Serialize(out_ptr, out_ptr_len, OPENSSL_SERIALIZE_TYPE_BASE64); + openssl_free(out_ptr); + return true; + } + bool RSA_DecryptPrivate_desktop(const unsigned char* privateKey, const std::string& input, std::string& out) + { + unsigned char* input_ptr = NULL; + int input_ptr_len = 0; + bool bBase64 = NSFile::CBase64Converter::Decode(input.c_str(), (int)input.length(), input_ptr, input_ptr_len); + if (!bBase64) + return false; + + unsigned char* out_ptr = NULL; + unsigned int out_ptr_len = 0; + + if (!RSA_DecryptPrivate(privateKey, input_ptr, (unsigned int)input_ptr_len, out_ptr, out_ptr_len)) + { + openssl_free(input_ptr); + return false; + } + + //out = Serialize(out_ptr, out_ptr_len, OPENSSL_SERIALIZE_TYPE_ASCII); + out = std::string((char*)out_ptr, out_ptr_len); + openssl_free(input_ptr); + openssl_free(out_ptr); + return true; + } + + // pbkdf2 + const EVP_MD* Get_EVP_MD(int nAlg) + { + switch (nAlg) + { + case OPENSSL_HASH_ALG_SHA1: + { + return EVP_sha1(); + } + case OPENSSL_HASH_ALG_SHA224: + { + return EVP_sha224(); + } + case OPENSSL_HASH_ALG_SHA256: + { + return EVP_sha256(); + } + case OPENSSL_HASH_ALG_SHA384: + { + return EVP_sha384(); + } + case OPENSSL_HASH_ALG_SHA512: + { + return EVP_sha512(); + } + default: + break; + } + return EVP_sha1(); + } + unsigned char* PBKDF2(const char* pass, int passlen, const unsigned char* salt, int saltlen, int hash_alg, int key_len) + { + unsigned char* out = openssl_alloc(key_len); + if (0 == PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, 1000, Get_EVP_MD(hash_alg), key_len, out)) + { + openssl_free(out); + out = NULL; + } + return out; + } + unsigned char* PBKDF2_desktop(const std::string& pass, const std::string& salt) + { + unsigned char* key_iv = NULL; + if (salt.empty()) + { + unsigned int pass_salt_len = 0; + unsigned char* pass_salt = NSOpenSSL::GetHash((unsigned char*)pass.c_str(), (unsigned int)pass.length(), OPENSSL_HASH_ALG_SHA512, pass_salt_len); + key_iv = PBKDF2(pass.c_str(), (int)pass.length(), pass_salt, pass_salt_len, OPENSSL_HASH_ALG_SHA256, 32 + 16); + openssl_free(pass_salt); + } + else + { + key_iv = PBKDF2(pass.c_str(), (int)pass.length(), (const unsigned char*)salt.c_str(), (unsigned int)salt.length(), OPENSSL_HASH_ALG_SHA256, 32 + 16); + } + return key_iv; + } + + // aes + int AES_GetKeySize(int type) + { + switch (type) + { + case OPENSSL_AES_256_CBC: + return 32; + } + return 32; + } + int AES_GetIvSize(int type) + { + switch (type) + { + case OPENSSL_AES_256_CBC: + return 16; + } + return 16; + } + + const EVP_CIPHER* _get_cipher_aes(int type) + { + switch (type) + { + case OPENSSL_AES_256_CBC: + return EVP_aes_256_cbc(); + } + return NULL; + } + bool AES_Encrypt(int type, const unsigned char* key, const unsigned char* iv, const unsigned char* data, const unsigned int& size, unsigned char*& data_crypt, unsigned int& data_crypt_len) + { + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_init(ctx); + EVP_EncryptInit_ex(ctx, _get_cipher_aes(type), NULL, key, iv); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL); + int out_len1 = (int)size + AES_BLOCK_SIZE; + int out_len2 = 0; + data_crypt = openssl_alloc(out_len1); + EVP_EncryptUpdate(ctx, data_crypt, &out_len1, data, (int)size); + EVP_EncryptFinal_ex(ctx, data_crypt + out_len1, &out_len2); + data_crypt_len = out_len1 + out_len2; + EVP_CIPHER_CTX_free(ctx); + EVP_cleanup(); + return true; + } + bool AES_Decrypt(int type, const unsigned char* key, const unsigned char* iv, const unsigned char* data, const unsigned int& size, unsigned char*& data_decrypt, unsigned int& data_decrypt_len) + { + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_init(ctx); + EVP_DecryptInit_ex(ctx, _get_cipher_aes(type), NULL, key, iv); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL); + int out_len1 = (int)size; + int out_len2 = 0; + data_decrypt = openssl_alloc(out_len1); + EVP_DecryptUpdate(ctx, data_decrypt, &out_len1, data, (int)size); + EVP_DecryptFinal_ex(ctx, data_decrypt + out_len1, &out_len2); + data_decrypt_len = out_len1 + out_len2; + EVP_CIPHER_CTX_free(ctx); + EVP_cleanup(); + return true; + } + + bool AES_Encrypt_desktop(const std::string& pass, const std::string& input, std::string& output, const std::string& salt) + { + unsigned char* key_iv = PBKDF2_desktop(pass, salt); + bool bRes = AES_Encrypt_desktop(key_iv, input, output); + openssl_free(key_iv); + return bRes; + } + bool AES_Decrypt_desktop(const std::string& pass, const std::string& input, std::string& output, const std::string& salt) + { + unsigned char* key_iv = PBKDF2_desktop(pass, salt); + bool bRes = AES_Decrypt_desktop(key_iv, input, output); + openssl_free(key_iv); + return bRes; + } + bool AES_Encrypt_desktop(const unsigned char* key_iv, const std::string& input, std::string& output) + { + unsigned char* data_crypt = NULL; + unsigned int data_crypt_len = 0; + bool bRes = AES_Encrypt(OPENSSL_AES_256_CBC, key_iv, key_iv + 32, (unsigned char*)input.c_str(), (unsigned int)input.length(), data_crypt, data_crypt_len); + + if (!bRes) + return false; + + output = Serialize(data_crypt, data_crypt_len, OPENSSL_SERIALIZE_TYPE_BASE64); + openssl_free(data_crypt); + return true; + } + bool AES_Decrypt_desktop(const unsigned char* key_iv, const std::string& input, std::string& output) + { + unsigned char* input_ptr = NULL; + int input_ptr_len = 0; + bool bBase64 = NSFile::CBase64Converter::Decode(input.c_str(), (int)input.length(), input_ptr, input_ptr_len); + if (!bBase64) + return false; + + unsigned char* data_decrypt = NULL; + unsigned int data_decrypt_len = 0; + bool bRes = AES_Decrypt(OPENSSL_AES_256_CBC, key_iv, key_iv + 32, input_ptr, input_ptr_len, data_decrypt, data_decrypt_len); + + if (!bRes) + { + RELEASEARRAYOBJECTS(input_ptr); + return false; + } + + //output = Serialize(out_ptr, out_ptr_len, OPENSSL_SERIALIZE_TYPE_ASCII); + output = std::string((char*)data_decrypt, data_decrypt_len); + RELEASEARRAYOBJECTS(input_ptr); + openssl_free(data_decrypt); + return true; + } + + // serialize + std::string Serialize(const unsigned char* data, const unsigned int& size, const int& alg) + { + switch (alg) + { + case OPENSSL_SERIALIZE_TYPE_ASCII: + { + return std::string((char*)data, size); + } + case OPENSSL_SERIALIZE_TYPE_HEX: + { + std::string res; + res.reserve(2 * size + 1); + char tmp[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + for (unsigned int i = 0; i < size; ++i) + { + res.append(1, tmp[data[i] >> 4]); + res.append(1, tmp[data[i] & 0x0F]); + } + return res; + } + case OPENSSL_SERIALIZE_TYPE_BASE64: + { + char* pDataDst = NULL; + int nDataDst = 0; + NSFile::CBase64Converter::Encode((BYTE*)data, (int)size, pDataDst, nDataDst, NSBase64::B64_BASE64_FLAG_NOCRLF); + std::string sBase64((char*)pDataDst, nDataDst); + RELEASEARRAYOBJECTS(pDataDst); + return sBase64; + } + default: + break; + } + return ""; + } +} diff --git a/Common/3dParty/openssl/common/common_openssl.h b/Common/3dParty/openssl/common/common_openssl.h new file mode 100644 index 0000000000..a129fb8b86 --- /dev/null +++ b/Common/3dParty/openssl/common/common_openssl.h @@ -0,0 +1,94 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ + +#ifndef COMMON_OPENSSL_H +#define COMMON_OPENSSL_H + +#define OPENSSL_HASH_ALG_SHA1 0 +#define OPENSSL_HASH_ALG_INVALID 1 +#define OPENSSL_HASH_ALG_SHA256 2 +#define OPENSSL_HASH_ALG_SHA224 3 +#define OPENSSL_HASH_ALG_SHA384 4 +#define OPENSSL_HASH_ALG_SHA512 5 + +#define OPENSSL_SERIALIZE_TYPE_BASE64 0 +#define OPENSSL_SERIALIZE_TYPE_HEX 1 +#define OPENSSL_SERIALIZE_TYPE_ASCII 2 + +#define OPENSSL_AES_256_CBC 0 + +#include "../../../../DesktopEditor/common/File.h" + +#ifdef COMMON_OPENSSL_BUILDING +#define OPENSSL_DECL Q_DECL_EXPORT +#else +#define OPENSSL_DECL Q_DECL_IMPORT +#endif + +namespace NSOpenSSL +{ + // alloc + OPENSSL_DECL unsigned char* openssl_alloc(unsigned int len); + OPENSSL_DECL void openssl_free(unsigned char* data); + + // hash + OPENSSL_DECL unsigned int GetHashSize(const int& alg); + OPENSSL_DECL unsigned char* GetHash(const unsigned char* data, const unsigned int& size, const int& alg, unsigned int& len); + + // rsa + OPENSSL_DECL bool RSA_GenerateKeys(unsigned char*& publicKey, unsigned char*& privateKey); + OPENSSL_DECL bool RSA_EncryptPublic(const unsigned char* publicKey, const unsigned char* data, const unsigned int& size, unsigned char*& data_crypt, unsigned int& data_crypt_len); + OPENSSL_DECL bool RSA_DecryptPrivate(const unsigned char* privateKey, const unsigned char* data, const unsigned int& size, unsigned char*& data_decrypt, unsigned int& data_decrypt_len); + + OPENSSL_DECL bool RSA_EncryptPublic_desktop(const unsigned char* publicKey, const std::string& input, std::string& out); + OPENSSL_DECL bool RSA_DecryptPrivate_desktop(const unsigned char* privateKey, const std::string& input, std::string& out); + + // pbkdf2 + OPENSSL_DECL unsigned char* PBKDF2(const char* pass, int passlen, const unsigned char* salt, int saltlen, int hash_alg, int key_len); + OPENSSL_DECL unsigned char* PBKDF2_desktop(const std::string& pass, const std::string& salt = ""); + + // aes + OPENSSL_DECL int AES_GetKeySize(int type); + OPENSSL_DECL int AES_GetIvSize(int type); + OPENSSL_DECL bool AES_Encrypt(int type, const unsigned char* key, const unsigned char* iv, const unsigned char* data, const unsigned int& size, unsigned char*& data_crypt, unsigned int& data_crypt_len); + OPENSSL_DECL bool AES_Decrypt(int type, const unsigned char* key, const unsigned char* iv, const unsigned char* data, const unsigned int& size, unsigned char*& data_crypt, unsigned int& data_crypt_len); + + OPENSSL_DECL bool AES_Encrypt_desktop(const std::string& pass, const std::string& input, std::string& output, const std::string& salt = ""); + OPENSSL_DECL bool AES_Decrypt_desktop(const std::string& pass, const std::string& input, std::string& output, const std::string& salt = ""); + OPENSSL_DECL bool AES_Encrypt_desktop(const unsigned char* key_iv, const std::string& input, std::string& output); + OPENSSL_DECL bool AES_Decrypt_desktop(const unsigned char* key_iv, const std::string& input, std::string& output); + + // serialize + OPENSSL_DECL std::string Serialize(const unsigned char* data, const unsigned int& size, const int& alg); +} + +#endif // COMMON_OPENSSL_H diff --git a/Common/3dParty/openssl/openssl.pri b/Common/3dParty/openssl/openssl.pri index 4d0779a5ee..f7a6e3b5c5 100644 --- a/Common/3dParty/openssl/openssl.pri +++ b/Common/3dParty/openssl/openssl.pri @@ -1,18 +1,11 @@ -core_linux { +INCLUDEPATH += $$PWD/build/$$CORE_BUILDS_PLATFORM_PREFIX/include -INCLUDEPATH += $$PWD/openssl/include +core_windows:LIBS += -L$$PWD/build/$$CORE_BUILDS_PLATFORM_PREFIX/lib -llibcrypto -llibssl +!core_windows:LIBS += -L$$PWD/build/$$CORE_BUILDS_PLATFORM_PREFIX/lib -lcrypto -lssl -QMAKE_LFLAGS += -fvisibility=hidden -LIBS += $$PWD/openssl/libssl.a -LIBS += $$PWD/openssl/libcrypto.a - -} - -core_mac { - -INCLUDEPATH += $$PWD/openssl/include - -LIBS += $$PWD/openssl/libssl.a -LIBS += $$PWD/openssl/libcrypto.a +open_ssl_common { + DEFINES += COMMON_OPENSSL_BUILDING + HEADERS += $$PWD/common/common_openssl.h + SOURCES += $$PWD/common/common_openssl.cpp } diff --git a/Common/3dParty/openssl/test/main.cpp b/Common/3dParty/openssl/test/main.cpp new file mode 100644 index 0000000000..3c9c663dab --- /dev/null +++ b/Common/3dParty/openssl/test/main.cpp @@ -0,0 +1,94 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ + +#include "./../common/common_openssl.h" + +int main(int argc, char *argv[]) +{ + argc; + argv; + if (true) + { + std::string sTestHashString = "knoejnrgijwenrgiojwnergjiwnerigjnwerojgnweorigjn"; + unsigned int data_len = 0; + unsigned char* data = NSOpenSSL::GetHash((unsigned char*)sTestHashString.c_str(), (unsigned int)sTestHashString.length(), OPENSSL_HASH_ALG_SHA256, data_len); + std::string sResult = NSOpenSSL::Serialize(data, data_len, OPENSSL_SERIALIZE_TYPE_HEX); + NSOpenSSL::openssl_free(data); + } + + if (true) + { + unsigned char* publicKey = NULL; + unsigned char* privateKey = NULL; + bool bRes = NSOpenSSL::RSA_GenerateKeys(publicKey, privateKey); + bRes; + + std::string sPublic((char*)publicKey); + std::string sPrivate((char*)privateKey); + + NSOpenSSL::openssl_free(publicKey); + NSOpenSSL::openssl_free(privateKey); + + std::string sMessage = "Hello world"; + + unsigned char* message_crypt = NULL; + unsigned int message_crypt_len = 0; + bool bEncrypt = NSOpenSSL::RSA_EncryptPublic((unsigned char*)sPublic.c_str(), (unsigned char*)sMessage.c_str(), (unsigned int)sMessage.length(), message_crypt, message_crypt_len); + bEncrypt; + + unsigned char* message_decrypt = NULL; + unsigned int message_decrypt_len = 0; + + bool bDecrypt = NSOpenSSL::RSA_DecryptPrivate((unsigned char*)sPrivate.c_str(), message_crypt, message_crypt_len, message_decrypt, message_decrypt_len); + bDecrypt; + + std::string sMessageOut((char*)message_decrypt, message_decrypt_len); + + NSOpenSSL::openssl_free(message_crypt); + NSOpenSSL::openssl_free(message_decrypt); + } + + if (true) + { + std::string password = "{PASSWORD}"; + std::string message = "{MESSAGE}"; + std::string message_crypted = ""; + std::string message_decrypted = ""; + + NSOpenSSL::AES_Encrypt_desktop(password, message, message_crypted); + NSOpenSSL::AES_Decrypt_desktop(password, message_crypted, message_decrypted); + + message; + } + + return 0; +} diff --git a/Common/3dParty/openssl/test/test.pro b/Common/3dParty/openssl/test/test.pro new file mode 100644 index 0000000000..a49cc9158a --- /dev/null +++ b/Common/3dParty/openssl/test/test.pro @@ -0,0 +1,28 @@ +QT -= core +QT -= gui + +TARGET = test +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +CORE_ROOT_DIR = $$PWD/../../../../../core +PWD_ROOT_DIR = $$PWD +include($$CORE_ROOT_DIR/Common/base.pri) + +############### destination path ############### +DESTDIR = $$PWD_ROOT_DIR/build/$$CORE_BUILDS_PLATFORM_PREFIX +################################################ + +INCLUDEPATH += $$PWD_ROOT_DIR/../build/$$CORE_BUILDS_PLATFORM_PREFIX/include +LIBS += -L$$PWD_ROOT_DIR/../build/$$CORE_BUILDS_PLATFORM_PREFIX/lib -llibcrypto + +core_windows:LIBS += -lws2_32 -lAdvapi32 -lCrypt32 -lUser32 + +ADD_DEPENDENCY(kernel) + +HEADERS += $$PWD_ROOT_DIR/../common/common_openssl.h +SOURCES += $$PWD_ROOT_DIR/../common/common_openssl.cpp + +SOURCES += main.cpp diff --git a/OfficeCryptReader/Test/Test.cpp b/OfficeCryptReader/Test/Test.cpp index 2903b1f274..f30526b69f 100644 --- a/OfficeCryptReader/Test/Test.cpp +++ b/OfficeCryptReader/Test/Test.cpp @@ -3,6 +3,7 @@ #include "tchar.h" #include "../source/ECMACryptFile.h" #include "../../Common/OfficeFileFormatChecker.h" +#include "../../DesktopEditor/common/File.h" #if defined(_WIN64) #pragma comment(lib, "../../build/bin/icu/win_64/icuuc.lib") @@ -25,7 +26,7 @@ int _tmain(int argc, _TCHAR* argv[]) ECMACryptFile crypt_file; bool result = false, bDataIntegrity = false; - std::wstring srcFileName = L"D:\\test\\_crypted\\test-111.docx"; + std::wstring srcFileName = L"D:\\test\\_bad_86\\crypt_file_test.docx"; std::wstring dstFileName = srcFileName + L"-mycrypt.docx"; std::wstring dstFileName2 = dstFileName + L".oox"; @@ -39,8 +40,17 @@ int _tmain(int argc, _TCHAR* argv[]) //std::wstring dstFileName1 = srcFileName1 + L".oox"; //result = crypt_file.DecryptOfficeFile(srcFileName1, dstFileName1, password, bDataIntegrity); - result = crypt_file.EncryptOfficeFile(srcFileName, dstFileName, password, L"123456789"); - result = crypt_file.DecryptOfficeFile(dstFileName, dstFileName2, password, bDataIntegrity); + //result = crypt_file.EncryptOfficeFile(srcFileName, dstFileName, password, L"123456789"); + //result = crypt_file.DecryptOfficeFile(dstFileName, dstFileName2, password, bDataIntegrity); + + std::wstring addit_name = L"11111111111111111111111111111"; + std::string addit_info = crypt_file.ReadAdditional(srcFileName, addit_name); + + std::wstring temp = NSFile::CFileBinary::CreateTempFileWithUniqueName(L"", L"asd"); + + addit_info += std::string(temp.begin(), temp.end()); + + crypt_file.WriteAdditional(srcFileName, addit_name, addit_info); return 0; } diff --git a/OfficeCryptReader/ooxml_crypt/main.cpp b/OfficeCryptReader/ooxml_crypt/main.cpp new file mode 100644 index 0000000000..6478a2a54a --- /dev/null +++ b/OfficeCryptReader/ooxml_crypt/main.cpp @@ -0,0 +1,314 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ + +#include "./../source/ECMACryptFile.h" +#include "./../../DesktopEditor/common/File.h" +#include "./../../Common/3dParty/openssl/common/common_openssl.h" +#include + +// examples: +// ooxml_crypt --file=D:/cryptor/1.docx --password=111 +// ooxml_crypt --file=D:/cryptor/1.docx --add={user-id-1}\ndata1 +// ooxml_crypt --file=D:/cryptor/1.docx --remove={user-id-1} +// ooxml_crypt --file=D:/cryptor/1.docx --remove={user-id-1}\ndata1 +// ooxml_crypt --file=D:/cryptor/1.docx --add={user-id-1}\ndata11 +// ooxml_crypt --file=D:/cryptor/1.docx --info= + +void string_replace(std::wstring& text, const std::wstring& replaceFrom, const std::wstring& replaceTo) +{ + size_t posn = 0; + while (std::wstring::npos != (posn = text.find(replaceFrom, posn))) + { + text.replace(posn, replaceFrom.length(), replaceTo); + posn += replaceTo.length(); + } +} +void string_replaceA(std::string& text, const std::string& replaceFrom, const std::string& replaceTo) +{ + size_t posn = 0; + while (std::string::npos != (posn = text.find(replaceFrom, posn))) + { + text.replace(posn, replaceFrom.length(), replaceTo); + posn += replaceTo.length(); + } +} + +#ifdef WIN32 +int wmain(int argc, wchar_t** argv) +#else +int main(int argc, char** argv) +#endif +{ + if (argc <= 0) + return 0; + + std::wstring file_path; + std::wstring password; + bool is_print_info = false; + bool is_decrypt = false; + std::string user; + std::wstring user_key_file; + + std::vector add_records; + std::vector remove_records; + + for (int i = 0; i < argc; ++i) + { +#ifdef WIN32 + std::wstring param(argv[i]); +#else + std::string paramA(argv[i]); + std::wstring param = UTF8_TO_U(paramA); +#endif + + std::wstring::size_type len = param.length(); + if (2 > len) + continue; + + const wchar_t* param_str = param.c_str(); + if (param_str[0] != '-' || param_str[1] != '-') + continue; + + std::wstring::size_type pos = param.find('='); + if (std::wstring::npos == pos) + continue; + + std::wstring key = param.substr(2, pos - 2); + std::wstring value = param.substr(pos + 1); + + if (key == L"file") + { + file_path = value; + } + else if (key == L"add") + { + if (!value.empty()) + { + if (value.c_str()[value.length() - 1] == '\n') + value = value.substr(0, value.length() - 1); + + string_replace(value, L";;;", L"\n"); + add_records.push_back(U_TO_UTF8(value)); + } + } + else if (key == L"remove") + { + if (!value.empty()) + { + if (value.c_str()[value.length() - 1] == '\n') + value = value.substr(0, value.length() - 1); + string_replace(value, L";;;", L"\n"); + remove_records.push_back(U_TO_UTF8(value)); + } + } + else if (key == L"password") + { + password = value; + } + else if (key == L"info") + { + is_print_info = true; + } + else if (key == L"decrypt") + { + is_decrypt = true; + } + else if (key == L"user") + { + user = U_TO_UTF8(value); + } + else if (key == L"key") + { + user_key_file = value; + } + } + + if (file_path.empty() || !NSFile::CFileBinary::Exists(file_path)) + { + std::cout << "error: file not exist" << std::endl; + return 1; + } + + if (!password.empty()) + { + // encrypt file + ECMACryptFile file; + bool result = file.EncryptOfficeFile(file_path, file_path, password); + if (!result) + { + std::cout << "error: file is not encrypted" << std::endl; + return 0; + } + return 2; + } + + ECMACryptFile file; + std::string docinfo = file.ReadAdditional(file_path, L"DocumentID"); + + if (is_print_info) + { + std::cout << docinfo << std::endl; + return 0; + } + + const char* doc_info_str = docinfo.c_str(); + const char* doc_info_str_end = doc_info_str + docinfo.length(); + + if (is_decrypt) + { + std::string encrypted_password = ""; + + // находим нужную запись + while (doc_info_str < doc_info_str_end) + { + const char* rec_start = doc_info_str; + + // 1) ищем старт записи + while (doc_info_str < doc_info_str_end && *doc_info_str != '\n') + ++doc_info_str; + + if (user == std::string(rec_start, doc_info_str - rec_start)) + { + rec_start = doc_info_str; + + while (doc_info_str < doc_info_str_end && *doc_info_str != '\n') + ++doc_info_str; + + encrypted_password = std::string(rec_start, doc_info_str - rec_start); + } + + // идем в конец записи + while (doc_info_str < doc_info_str_end) + { + if (*doc_info_str++ == '\n') + { + if (*doc_info_str == '\n') + { + ++doc_info_str; + break; + } + } + } + } + + std::string private_key_content; + NSFile::CFileBinary::ReadAllTextUtf8A(user_key_file, private_key_content); + + std::string passwordA; + NSOpenSSL::RSA_DecryptPrivate_desktop((unsigned char*)private_key_content.c_str(), encrypted_password, passwordA); + std::wstring password = UTF8_TO_U(passwordA); + + // encrypt file + ECMACryptFile file; + bool bDataIntegrity; + bool result = file.DecryptOfficeFile(file_path, file_path, password, bDataIntegrity); + if (!result) + { + std::cout << "error: file is not decrypted" << std::endl; + return 0; + } + return 2; + } + + std::string sResult = ""; + sResult.reserve(1000); + + while (doc_info_str < doc_info_str_end) + { + const char* rec_start = doc_info_str; + + // 1) ищем старт записи + while (doc_info_str < doc_info_str_end && *doc_info_str != '\n') + ++doc_info_str; + + std::string::size_type len_first = doc_info_str - rec_start; + + // 2) ищем конец записи + while (doc_info_str < doc_info_str_end) + { + if (*doc_info_str++ == '\n') + { + if (*doc_info_str == '\n') + { + ++doc_info_str; + break; + } + } + } + + bool isAdd = true; + std::string sRec = std::string(rec_start, (doc_info_str - rec_start - 2)); + + // 3) проверяем запись на удаление + for (std::vector::iterator iter = remove_records.begin(); iter != remove_records.end(); iter++) + { + if (*iter == std::string(rec_start, len_first)) + { + isAdd = false; + } + else if (*iter == sRec) + { + isAdd = false; + } + } + + // 4) проверяем запись на удаление + for (std::vector::iterator iter = add_records.begin(); iter != add_records.end(); iter++) + { + if (*iter == sRec) + { + isAdd = false; + } + } + + if (isAdd) + { + sResult += sRec; + sResult += "\n\n"; + } + } + + for (std::vector::iterator iter = add_records.begin(); iter != add_records.end(); iter++) + { + sResult += *iter; + sResult += "\n\n"; + } + + bool result = file.WriteAdditional(file_path, L"DocumentID", sResult); + if (!result) + { + std::cout << "error: docinfo not writed" << std::endl; + return 3; + } + + return 0; +} diff --git a/OfficeCryptReader/ooxml_crypt/ooxml_crypt.pro b/OfficeCryptReader/ooxml_crypt/ooxml_crypt.pro new file mode 100644 index 0000000000..5f73e572f9 --- /dev/null +++ b/OfficeCryptReader/ooxml_crypt/ooxml_crypt.pro @@ -0,0 +1,56 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +TARGET = ooxml_crypt +CORE_ROOT_DIR = $$PWD/../.. +PWD_ROOT_DIR = $$PWD + +CONFIG += core_static_link_libstd +include($$CORE_ROOT_DIR/Common/base.pri) +include($$CORE_ROOT_DIR/Common/3dParty/boost/boost.pri) + +LIBS += -L$$CORE_BUILDS_LIBRARIES_PATH -lCryptoPPLib +ADD_DEPENDENCY(kernel) + +CONFIG += open_ssl_common +include($$CORE_ROOT_DIR/Common/3dParty/openssl/openssl.pri) + +DEFINES += CRYPTOPP_DISABLE_ASM +DESTDIR = $$CORE_BUILDS_BINARY_PATH + +HEADERS += \ + $$PWD/../source/ECMACryptFile.h \ + $$PWD/../source/CryptTransform.h \ + $$PWD/../source/simple_xml_writer.h + +SOURCES += \ + $$PWD/../source/ECMACryptFile.cpp \ + $$PWD/../source/CryptTransform.cpp + +SOURCES += \ + $$CORE_ROOT_DIR/Common/OfficeFileFormatChecker2.cpp \ + $$CORE_ROOT_DIR/Common/3dParty/pole/pole.cpp \ + $$CORE_ROOT_DIR/Common/DocxFormat/Source/Base/unicode_util.cpp + +SOURCES += \ + $$PWD/main.cpp + +core_windows { + DEFINES -= UNICODE + DEFINES -= _DEBUG + + LIBS += -lAdvapi32 + LIBS += -lShell32 + LIBS += -lGdi32 + LIBS += -lUser32 + LIBS += -lcrypt32 + LIBS += -lcryptui + LIBS += -lws2_32 +} + +core_linux { + LIBS += -lz -pthread + QMAKE_LFLAGS += -Wl,--rpath=./ +} diff --git a/OfficeCryptReader/source/ECMACryptFile.cpp b/OfficeCryptReader/source/ECMACryptFile.cpp index ef29f2247f..ecb99bb788 100644 --- a/OfficeCryptReader/source/ECMACryptFile.cpp +++ b/OfficeCryptReader/source/ECMACryptFile.cpp @@ -976,3 +976,56 @@ bool ECMACryptFile::DecryptOfficeFile(const std::wstring &file_name_inp, const s return result; } + +std::string ECMACryptFile::ReadAdditional(const std::wstring &file_name, const std::wstring &addit_name) +{ + POLE::Storage *pStorage = new POLE::Storage(file_name.c_str()); + + if (!pStorage->open(false, false)) + { + delete pStorage; + return ""; + } + std::string result; + POLE::Stream *pStream = new POLE::Stream(pStorage, addit_name); + if ((pStream) && (pStream->size() > 0)) + { + _UINT64 lengthData, size = pStream->size(); + + char* data = new char[size]; + + lengthData = pStream->read((unsigned char*)data, size); + + result = std::string(data, lengthData); + delete []data; + delete pStream; + } + delete pStorage; + + return result; +} +bool ECMACryptFile::WriteAdditional(const std::wstring &file_name, const std::wstring &addit_name, const std::string &addit_info) +{ + POLE::Storage *pStorage = new POLE::Storage(file_name.c_str()); + + if (!pStorage)return false; + + if (!pStorage->open(true, false)) + { + delete pStorage; + return false; + } + + POLE::Stream *pStream = new POLE::Stream(pStorage, addit_name, true, addit_info.size()); + + pStream->write((unsigned char*)addit_info.c_str(), addit_info.size()); + pStream->setSize(addit_info.size()); + + pStream->flush(); + delete pStream; + + pStorage->close(); + delete pStorage; + + return true; +} diff --git a/OfficeCryptReader/source/ECMACryptFile.h b/OfficeCryptReader/source/ECMACryptFile.h index e92a6b7023..d7a305382c 100644 --- a/OfficeCryptReader/source/ECMACryptFile.h +++ b/OfficeCryptReader/source/ECMACryptFile.h @@ -40,6 +40,9 @@ public: bool DecryptOfficeFile(const std::wstring &file_name_inp, const std::wstring &file_name_out, const std::wstring &password, bool & bDataIntegrity); bool EncryptOfficeFile(const std::wstring &file_name_inp, const std::wstring &file_name_out, const std::wstring &password, const std::wstring &documentID = L""); + std::string ReadAdditional(const std::wstring &file_name, const std::wstring &addit_name); + bool WriteAdditional(const std::wstring &file_name, const std::wstring &addit_name, const std::string &addit_info); + struct _refComponent { int type; @@ -50,5 +53,5 @@ public: std::vector<_refComponent> refComponents; std::wstring dataSpaceName; }; - std::vector<_mapEntry> mapEntries; + std::vector<_mapEntry> mapEntries; };