diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d4ca345
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+KEY_DIR=..\include
+
+######################################################################
+# Main targets
+######################################################################
+
+All :: \
+ GenRSAKeypair
+
+Clean ::
+# Ommited intentionally not to delete keys accidentaly.
+
+
+######################################################################
+# Folder creation
+######################################################################
+
+"$(KEY_DIR)" :
+ if not exist $@ md $@
+
+
+######################################################################
+# Building
+######################################################################
+
+GenRSAKeypair :: \
+ "$(KEY_DIR)" \
+ "$(KEY_DIR)\UpdaterKeyPrivate.bin" \
+ "$(KEY_DIR)\UpdaterKeyPublic.bin"
+
+"$(KEY_DIR)\UpdaterKeypair.txt" :
+ openssl.exe genrsa -out $@ 4096
+
+"$(KEY_DIR)\UpdaterKeyPrivate.bin" : "$(KEY_DIR)\UpdaterKeypair.txt"
+ if exist $@ del /f /q $@
+ if exist "$(@:"=).tmp" del /f /q "$(@:"=).tmp"
+ openssl.exe rsa -in $** -inform PEM -outform DER -out "$(@:"=).tmp"
+ move /y "$(@:"=).tmp" $@ > NUL
+
+"$(KEY_DIR)\UpdaterKeyPublic.bin" : "$(KEY_DIR)\UpdaterKeypair.txt"
+ if exist $@ del /f /q $@
+ if exist "$(@:"=).tmp" del /f /q "$(@:"=).tmp"
+ openssl.exe rsa -in $** -inform PEM -outform DER -out "$(@:"=).tmp" -pubout
+ move /y "$(@:"=).tmp" $@ > NUL
+
diff --git a/include/version.h b/UpdCheck/UpdCheck.h
similarity index 52%
rename from include/version.h
rename to UpdCheck/UpdCheck.h
index 1439fa9..26e727b 100644
--- a/include/version.h
+++ b/UpdCheck/UpdCheck.h
@@ -19,25 +19,7 @@
#pragma once
-//
-// Product version as a single DWORD
-// Note: Used for version comparison within C/C++ code.
-//
-#define UPDATER_VERSION 0x01000000
+#define IDR_KEY_PUBLIC 1
-//
-// Product version by components
-// Note: Resource Compiler has limited preprocessing capability,
-// thus we need to specify major, minor and other version components
-// separately.
-//
-#define UPDATER_VERSION_MAJ 1
-#define UPDATER_VERSION_MIN 0
-#define UPDATER_VERSION_REV 0
-#define UPDATER_VERSION_BUILD 0
-
-//
-// Human readable product version and build year for UI
-//
-#define UPDATER_VERSION_STR "2.0-alpha"
-#define UPDATER_BUILD_YEAR_STR "2016"
+#if !defined(RC_INVOKED) && !defined(MIDL_PASS)
+#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS)
diff --git a/UpdCheck/UpdCheck.props b/UpdCheck/UpdCheck.props
index 6e51ada..cc02624 100644
--- a/UpdCheck/UpdCheck.props
+++ b/UpdCheck/UpdCheck.props
@@ -9,6 +9,9 @@
..\..\lib\wxExtend\include;..\..\lib\stdex\include;%(AdditionalIncludeDirectories)
+
+ RequireAdministrator
+
\ No newline at end of file
diff --git a/UpdCheck/UpdCheck.rc b/UpdCheck/UpdCheck.rc
index 4a02bba..e654d0c 100644
Binary files a/UpdCheck/UpdCheck.rc and b/UpdCheck/UpdCheck.rc differ
diff --git a/UpdCheck/UpdCheck.vcxproj b/UpdCheck/UpdCheck.vcxproj
index f5e5ac8..55252be 100644
--- a/UpdCheck/UpdCheck.vcxproj
+++ b/UpdCheck/UpdCheck.vcxproj
@@ -85,6 +85,7 @@
+
diff --git a/UpdCheck/UpdCheck.vcxproj.filters b/UpdCheck/UpdCheck.vcxproj.filters
index 759f9d9..6bbb893 100644
--- a/UpdCheck/UpdCheck.vcxproj.filters
+++ b/UpdCheck/UpdCheck.vcxproj.filters
@@ -30,6 +30,9 @@
Header Files
+
+ Header Files
+
diff --git a/UpdCheck/main.cpp b/UpdCheck/main.cpp
index 7b52a4b..e6ae4d1 100644
--- a/UpdCheck/main.cpp
+++ b/UpdCheck/main.cpp
@@ -18,6 +18,73 @@
*/
#include "stdafx.h"
+#pragma comment(lib, "Crypt32.lib")
+
+
+///
+/// Reads package information from a stream
+///
+/// \param[in] stream Input stream
+/// \param[out] pkg Package information
+///
+/// \returns The stream \p stream
+///
+inline std::istream& operator >>(_In_ std::istream& stream, _Out_ Updater::package_info &pkg)
+{
+ // Read binary version.
+ stream.read((char*)&pkg.ver, sizeof(pkg.ver));
+ if (!stream.good()) return stream;
+
+ // Read human readable description (length prefixed).
+ unsigned __int32 count;
+ stream.read((char*)&count, sizeof(count));
+ if (!stream.good()) return stream;
+ pkg.desc.resize(count);
+ stream.read((char*)pkg.desc.data(), sizeof(wchar_t)*count);
+
+ // Read package language (length prefixed).
+ stream.read((char*)&count, sizeof(count));
+ if (!stream.good()) return stream;
+ pkg.lang.resize(count);
+ stream.read((char*)pkg.lang.data(), sizeof(char)*count);
+
+ // Read package download URL (length prefixed).
+ stream.read((char*)&count, sizeof(count));
+ if (!stream.good()) return stream;
+ pkg.url.resize(count);
+ stream.read((char*)pkg.url.data(), sizeof(char)*count);
+
+ return stream;
+}
+
+
+///
+/// Reads signature from a stream
+///
+/// \param[in] stream Input stream
+/// \param[out] sig Signature
+///
+/// \returns The stream \p stream
+///
+inline std::istream& operator >>(_In_ std::istream& stream, _Out_ Updater::signature &sig)
+{
+ // Read signature (length prefixed).
+ unsigned __int32 count;
+ stream.read((char*)&count, sizeof(count));
+ if (!stream.good()) return stream;
+
+ // Read, and reverse signature byte order (to be OpenSSL compatible).
+ std::vector sig_swap(count);
+ stream.read((char*)sig_swap.data(), sizeof(unsigned char)*count);
+ if (!stream.good()) return stream;
+ sig.resize(count);
+ for (unsigned __int32 i = 0, j = count - 1; i < count; i++, j--)
+ sig[i] = sig_swap[j];
+
+ return stream;
+}
+
+
///
@@ -29,12 +96,104 @@ int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In
// Inizialize wxWidgets.
wxInitializer initializer;
- if (!initializer) {
- _ftprintf(stderr, wxT("Failed to initialize the wxWidgets library, aborting.\n"));
+ if (!initializer)
return -1;
+
+ // Open data file.
+ std::ifstream dat(_T("..\\..\\output\\test.bin"), std::ios_base::in | std::ios_base::binary);
+ if (!dat.good()) {
+ wxFAIL_MSG(wxT("Error reading data file."));
+ return 1;
}
+ // Find the signature first.
+ if (stdex::idrec::find(dat, Updater::signature_rec::id)) {
+ // Signature found. Remember file position.
+ Updater::recordsize_t
+ sig_pos = (Updater::recordsize_t)dat.tellg(), // Position to return to to read the signature.
+ sig_start = sig_pos - sizeof(Updater::recordid_t); // Beginning of the signature block
+ // Create cryptographic context.
+ HCRYPTPROV cp = NULL;
+ wxVERIFY(::CryptAcquireContext(&cp, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT));
+
+ // Hash the file up to signature block start.
+ HCRYPTHASH ch = NULL;
+ wxVERIFY(::CryptCreateHash(cp, CALG_SHA1, 0, 0, &ch));
+ {
+ dat.seekg(0);
+ std::vector buf(8192);
+ for (Updater::recordsize_t data_left = sig_start; dat.good() && data_left;) {
+ dat.read((char*)buf.data(), std::min(buf.size(), data_left));
+ Updater::recordsize_t count = dat.gcount();
+ wxVERIFY(::CryptHashData(ch, buf.data(), count, 0));
+ data_left -= count;
+ }
+ }
+
+ // Read the signature.
+ dat.seekg(sig_pos);
+ Updater::signature sig;
+ dat >> Updater::signature_rec(sig);
+ if (dat.good()) {
+ // Import public key.
+ HCRYPTKEY ck = NULL;
+ {
+ HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(IDR_KEY_PUBLIC), RT_RCDATA);
+ wxASSERT_MSG(res, wxT("public key not found"));
+ HGLOBAL res_handle = ::LoadResource(NULL, res);
+ wxASSERT_MSG(res_handle, wxT("loading resource failed"));
+
+ CERT_PUBLIC_KEY_INFO *keyinfo_data = NULL;
+ DWORD keyinfo_size = 0;
+ wxVERIFY(::CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, (const BYTE*)::LockResource(res_handle), ::SizeofResource(NULL, res), CRYPT_DECODE_ALLOC_FLAG, NULL, &keyinfo_data, &keyinfo_size));
+
+ BYTE *key_data = NULL;
+ DWORD key_size = 0;
+ wxVERIFY(::CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, (const BYTE*)keyinfo_data->PublicKey.pbData, keyinfo_data->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &key_data, &key_size));
+
+ wxVERIFY(::CryptImportKey(cp, key_data, key_size, NULL, 0, &ck));
+ ::LocalFree(key_data);
+ ::LocalFree(keyinfo_data);
+ }
+
+ // We have the hash, we have the signature, we have the public key. Now verify.
+ if (::CryptVerifySignature(ch, (BYTE*)sig.data(), sig.size(), ck, NULL, 0)) {
+ // The signature is correct. Now parse the file.
+ dat.seekg(0);
+ if (stdex::idrec::find(dat, UPDATER_DB_ID, sizeof(Updater::recordid_t))) {
+ Updater::recordsize_t size;
+ dat.read((char*)&size, sizeof(Updater::recordsize_t));
+ if (dat.good()) {
+ if (size > sig_start) {
+ // Limit the size up to the file signature. Should have not get here.
+ wxFAIL_MSG(wxT("Updater file wrong record size."));
+ size = sig_start;
+ }
+ if (stdex::idrec::find(dat, Updater::package_info_rec::id, size)) {
+ // Read package information.
+ Updater::package_info pi;
+ dat >> Updater::package_info_rec(pi);
+ if (dat.good()) {
+
+ } else
+ wxFAIL_MSG(wxT("Error reading package information from Updater file."));
+ } else
+ wxFAIL_MSG(wxT("Updater file has no package information."));
+ } else
+ wxFAIL_MSG(wxT("Updater file read error."));
+ }
+ } else
+ wxFAIL_MSG(wxT("Updater file signature does not match file content."));
+
+ wxVERIFY(::CryptDestroyKey(ck));
+ } else
+ wxFAIL_MSG(wxT("Error reading signature from the Updater file."));
+
+ wxVERIFY(::CryptDestroyHash(ch));
+ wxVERIFY(::CryptReleaseContext(cp, 0));
+ } else
+ wxFAIL_MSG(wxT("Signature not found in the Updater file."));
return 0;
}
diff --git a/UpdCheck/stdafx.h b/UpdCheck/stdafx.h
index 4fe41c1..ad9ffcb 100644
--- a/UpdCheck/stdafx.h
+++ b/UpdCheck/stdafx.h
@@ -19,8 +19,13 @@
#pragma once
+#include "UpdCheck.h"
+#include "../include/Updater.h"
+
#include
#include
#include
+
+#include
diff --git a/UpdMkDesc/UpdMkDesc.h b/UpdMkDesc/UpdMkDesc.h
new file mode 100644
index 0000000..8606b89
--- /dev/null
+++ b/UpdMkDesc/UpdMkDesc.h
@@ -0,0 +1,25 @@
+/*
+ Copyright 2016 Amebis
+
+ This file is part of Updater.
+
+ Updater is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Updater is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Updater. If not, see .
+*/
+
+#pragma once
+
+#define IDR_KEY_PRIVATE 1
+
+#if !defined(RC_INVOKED) && !defined(MIDL_PASS)
+#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS)
diff --git a/UpdMkDesc/UpdMkDesc.rc b/UpdMkDesc/UpdMkDesc.rc
index 5f4db7a..fe544cd 100644
Binary files a/UpdMkDesc/UpdMkDesc.rc and b/UpdMkDesc/UpdMkDesc.rc differ
diff --git a/UpdMkDesc/UpdMkDesc.vcxproj b/UpdMkDesc/UpdMkDesc.vcxproj
index 09ec111..132dbed 100644
--- a/UpdMkDesc/UpdMkDesc.vcxproj
+++ b/UpdMkDesc/UpdMkDesc.vcxproj
@@ -88,6 +88,7 @@
+
diff --git a/UpdMkDesc/UpdMkDesc.vcxproj.filters b/UpdMkDesc/UpdMkDesc.vcxproj.filters
index 0514c72..de7c64b 100644
--- a/UpdMkDesc/UpdMkDesc.vcxproj.filters
+++ b/UpdMkDesc/UpdMkDesc.vcxproj.filters
@@ -30,6 +30,9 @@
Header Files
+
+ Header Files
+
diff --git a/UpdMkDesc/locale/sl_SI.po b/UpdMkDesc/locale/sl_SI.po
index 5e35145..b18e162 100644
--- a/UpdMkDesc/locale/sl_SI.po
+++ b/UpdMkDesc/locale/sl_SI.po
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: UpdMkDesc\n"
-"POT-Creation-Date: 2016-03-15 10:56+0100\n"
-"PO-Revision-Date: 2016-03-15 10:57+0100\n"
+"POT-Creation-Date: 2016-03-15 20:09+0100\n"
+"PO-Revision-Date: 2016-03-15 20:10+0100\n"
"Last-Translator: Simon Rozman \n"
"Language-Team: Amebis, d. o. o., Kamnik \n"
"Language: sl_SI\n"
@@ -17,14 +17,29 @@ msgstr ""
"X-Poedit-KeywordsList: _\n"
"X-Poedit-SearchPath-0: .\n"
-#: main.cpp:40
+#: main.cpp:138
msgid "Show this help message"
msgstr "Pokaži to sporočilo pomoči"
-#: main.cpp:41
-msgid "input file"
-msgstr "vhodna datoteka"
+#: main.cpp:139
+msgid "Hexadecimal version of the product"
+msgstr "Verzija izdelka šesnajstiško"
-#: main.cpp:42
+#: main.cpp:140
+msgid "String version of the product"
+msgstr "Verzija izdelka opisno"
+
+#: main.cpp:141
+msgid "Package language"
+msgstr "Jezik paketa"
+
+#: main.cpp:142
+msgid "Package download URL"
+msgstr "URL za prenos paketa"
+
+#: main.cpp:143
msgid "output file"
msgstr "izhodna datoteka"
+
+#~ msgid "Package URL in the form of platform;language;URL"
+#~ msgstr "Naslov URL paketa oblike platforma;jezik;URL"
diff --git a/UpdMkDesc/main.cpp b/UpdMkDesc/main.cpp
index a63bca9..5066062 100644
--- a/UpdMkDesc/main.cpp
+++ b/UpdMkDesc/main.cpp
@@ -18,6 +18,104 @@
*/
#include "stdafx.h"
+#pragma comment(lib, "Crypt32.lib")
+
+
+///
+/// Writes package information to a stream
+///
+/// \param[in] stream Output stream
+/// \param[in] pkg Package information
+///
+/// \returns The stream \p stream
+///
+inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const Updater::package_info &pkg)
+{
+ // Write binary version.
+ if (stream.fail()) return stream;
+ stream.write((const char*)&pkg.ver, sizeof(pkg.ver));
+
+ // Write human readable description (length prefixed).
+ std::wstring::size_type char_count = pkg.desc.length();
+#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
+ // 4G check
+ if (char_count > 0xffffffff) {
+ stream.setstate(std::ios_base::failbit);
+ return stream;
+ }
+#endif
+ if (stream.fail()) return stream;
+ unsigned __int32 count = (unsigned __int32)char_count;
+ stream.write((const char*)&count, sizeof(count));
+ if (stream.fail()) return stream;
+ stream.write((const char*)pkg.desc.c_str(), sizeof(wchar_t)*count);
+
+ // Write package language (length prefixed)
+ char_count = pkg.lang.length();
+#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
+ // 4G check
+ if (char_count > 0xffffffff) {
+ stream.setstate(std::ios_base::failbit);
+ return stream;
+ }
+#endif
+ if (stream.fail()) return stream;
+ count = (unsigned __int32)char_count;
+ stream.write((const char*)&count, sizeof(count));
+ if (stream.fail()) return stream;
+ stream.write(pkg.lang.c_str(), sizeof(char)*count);
+
+ // Write package download URL (length prefixed)
+ char_count = pkg.url.length();
+#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
+ // 4G check
+ if (char_count > 0xffffffff) {
+ stream.setstate(std::ios_base::failbit);
+ return stream;
+ }
+#endif
+ if (stream.fail()) return stream;
+ count = (unsigned __int32)char_count;
+ stream.write((const char*)&count, sizeof(count));
+ if (stream.fail()) return stream;
+ stream.write(pkg.url.c_str(), sizeof(char)*count);
+
+ return stream;
+}
+
+
+///
+/// Writes signature to a stream
+///
+/// \param[in] stream Output stream
+/// \param[in] sig Signature
+///
+/// \returns The stream \p stream
+///
+inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const Updater::signature &sig)
+{
+ // Write signature (length prefixed).
+ Updater::signature::size_type sig_count = sig.size();
+#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
+ // 4G check
+ if (sig_count > 0xffffffff) {
+ stream.setstate(std::ios_base::failbit);
+ return stream;
+ }
+#endif
+ if (stream.fail()) return stream;
+ unsigned __int32 count = (unsigned __int32)sig_count;
+ stream.write((const char*)&count, sizeof(count));
+
+ // Reverse signature byte order (to make OpenSSL compatible), and write.
+ if (stream.fail()) return stream;
+ std::vector sig_swap(count);
+ for (unsigned __int32 i = 0, j = count - 1; i < count; i++, j--)
+ sig_swap[j] = sig[i];
+ stream.write((const char*)sig_swap.data(), sizeof(unsigned char)*count);
+
+ return stream;
+}
///
@@ -38,7 +136,10 @@ int _tmain(int argc, _TCHAR *argv[])
static const wxCmdLineEntryDesc cmdLineDesc[] =
{
{ wxCMD_LINE_SWITCH, "h" , "help" , _("Show this help message" ), wxCMD_LINE_VAL_NONE , wxCMD_LINE_OPTION_HELP },
- { wxCMD_LINE_SWITCH, "vh" , "ver-hex", _("Hexadecimal version of the product"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
+ { wxCMD_LINE_OPTION, "x" , "ver-hex", _("Hexadecimal version of the product"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
+ { wxCMD_LINE_OPTION, "s" , "ver-str", _("String version of the product" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
+ { wxCMD_LINE_OPTION, "l" , "lang" , _("Package language" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
+ { wxCMD_LINE_OPTION, "u" , "url" , _("Package download URL" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
{ wxCMD_LINE_PARAM , NULL, NULL , _("output file" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
{ wxCMD_LINE_NONE }
@@ -58,5 +159,96 @@ int _tmain(int argc, _TCHAR *argv[])
return -1;
}
- return 0;
+ const wxString& filenameOut = parser.GetParam(0);
+ std::fstream dst((LPCTSTR)filenameOut, std::ios_base::out | std::ios_base::in | std::ios_base::trunc | std::ios_base::binary);
+ if (dst.fail()) {
+ _ftprintf(stderr, wxT("%s: error UMD0001: Error opening output file.\n"), filenameOut.fn_str());
+ return 1;
+ }
+
+ bool has_errors = false;
+
+ // Open file ID.
+ std::streamoff dst_start = stdex::idrec::open(dst, UPDATER_DB_ID);
+
+ Updater::package_info pi;
+ wxString val;
+
+ pi.ver = parser.Found(wxT("x"), &val) ? _tcstoul(val, NULL, 16) : 0;
+
+ if (parser.Found(wxT("s"), &val))
+ pi.desc = val;
+
+ if (parser.Found(wxT("l"), &val))
+ pi.lang = val.ToAscii();
+
+ if (parser.Found(wxT("u"), &val))
+ pi.url = val.ToUTF8();
+
+ dst << Updater::package_info_rec(pi);
+ if (dst.fail()) {
+ _ftprintf(stderr, wxT("%s: error UMD0002: Writing to output file failed.\n"), filenameOut.fn_str());
+ has_errors = true;
+ }
+
+ stdex::idrec::close(dst, dst_start);
+
+ // Create cryptographic context.
+ HCRYPTPROV cp = NULL;
+ wxVERIFY(::CryptAcquireContext(&cp, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT));
+
+ // Import private key.
+ {
+ HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(IDR_KEY_PRIVATE), RT_RCDATA);
+ wxASSERT_MSG(res, wxT("private key not found"));
+ HGLOBAL res_handle = ::LoadResource(NULL, res);
+ wxASSERT_MSG(res_handle, wxT("loading resource failed"));
+
+ PUBLICKEYSTRUC *key_data = NULL;
+ DWORD key_size = 0;
+ wxVERIFY(::CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, (const BYTE*)::LockResource(res_handle), ::SizeofResource(NULL, res), CRYPT_DECODE_ALLOC_FLAG, NULL, &key_data, &key_size));
+ // See: http://pumka.net/2009/12/16/rsa-encryption-cplusplus-delphi-cryptoapi-php-openssl-2/comment-page-1/#comment-429
+ key_data->aiKeyAlg = CALG_RSA_SIGN;
+
+ HCRYPTKEY ck = NULL;
+ wxVERIFY(::CryptImportKey(cp, (const BYTE*)key_data, key_size, NULL, 0, &ck));
+ wxVERIFY(::CryptDestroyKey(ck));
+ ::LocalFree(key_data);
+ }
+
+ // Hash the file.
+ HCRYPTHASH ch = NULL;
+ wxVERIFY(::CryptCreateHash(cp, CALG_SHA1, 0, 0, &ch));
+ {
+ std::vector buf(8192);
+ for (dst.seekg(0); !dst.eof();) {
+ dst.read((char*)buf.data(), buf.size());
+ wxVERIFY(::CryptHashData(ch, buf.data(), dst.gcount(), 0));
+ }
+ dst.clear();
+ }
+
+ // Sign the hash.
+ DWORD sig_size = 0;
+ if (!::CryptSignHash(ch, AT_SIGNATURE, NULL, 0, NULL, &sig_size)) {
+ _ftprintf(stderr, wxT("%s: error UMD0003: Signing output file failed (%i).\n"), filenameOut.fn_str(), ::GetLastError());
+ has_errors = true;
+ }
+ Updater::signature sig(sig_size);
+ if (!::CryptSignHash(ch, AT_SIGNATURE, NULL, 0, sig.data(), &sig_size)) {
+ _ftprintf(stderr, wxT("%s: error UMD0003: Signing output file failed (%i).\n"), filenameOut.fn_str(), ::GetLastError());
+ has_errors = true;
+ }
+ wxVERIFY(::CryptDestroyHash(ch));
+ wxVERIFY(::CryptReleaseContext(cp, 0));
+
+ // Append to the end of the file.
+ dst << Updater::signature_rec(sig);
+
+ if (has_errors) {
+ dst.close();
+ wxRemoveFile(filenameOut);
+ return 1;
+ } else
+ return 0;
}
diff --git a/UpdMkDesc/stdafx.h b/UpdMkDesc/stdafx.h
index 65d22a1..4aba235 100644
--- a/UpdMkDesc/stdafx.h
+++ b/UpdMkDesc/stdafx.h
@@ -19,9 +19,18 @@
#pragma once
+#include "UpdMkDesc.h"
+#include "../include/Updater.h"
+
#include
#include
#include
#include
+
+#include
+#include
+#include
+
+#include
diff --git a/Updater.sln b/Updater.sln
index 216fcef..a401120 100644
--- a/Updater.sln
+++ b/Updater.sln
@@ -5,7 +5,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ECE3F336-FFD2-41EE-AD8F-17BD7472BDCB}"
ProjectSection(SolutionItems) = preProject
- include\version.h = include\version.h
+ include\Updater.h = include\Updater.h
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdMkDesc", "UpdMkDesc\UpdMkDesc.vcxproj", "{516AFFF6-F1E7-4806-B2E2-5CD9911ED2FB}"
diff --git a/include/Updater.h b/include/Updater.h
new file mode 100644
index 0000000..a6aabc6
--- /dev/null
+++ b/include/Updater.h
@@ -0,0 +1,96 @@
+/*
+ Copyright 2016 Amebis
+
+ This file is part of Updater.
+
+ Updater is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Updater is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Updater. If not, see .
+*/
+
+#pragma once
+
+//
+// Product version as a single DWORD
+// Note: Used for version comparison within C/C++ code.
+//
+#define UPDATER_VERSION 0x01000000
+
+//
+// Product version by components
+// Note: Resource Compiler has limited preprocessing capability,
+// thus we need to specify major, minor and other version components
+// separately.
+//
+#define UPDATER_VERSION_MAJ 1
+#define UPDATER_VERSION_MIN 0
+#define UPDATER_VERSION_REV 0
+#define UPDATER_VERSION_BUILD 0
+
+//
+// Human readable product version and build year for UI
+//
+#define UPDATER_VERSION_STR "2.0-alpha"
+#define UPDATER_BUILD_YEAR_STR "2016"
+
+
+#if !defined(RC_INVOKED) && !defined(MIDL_PASS)
+
+#include
+
+#include
+#include
+
+
+///
+/// Data records alignment
+///
+#define UPDATER_RECORD_ALIGN 1
+
+
+///
+/// Database IDs
+///
+#define UPDATER_DB_ID (*(Updater::recordid_t*)"UPD")
+
+
+namespace Updater {
+ typedef unsigned __int32 recordid_t;
+ typedef unsigned __int32 recordsize_t;
+
+
+ ///
+ /// Package information
+ ///
+ struct package_info {
+ unsigned __int32 ver; ///< Binary Version
+ std::wstring desc; ///< Human Readable Description (i. e. "1.2")
+ std::string lang; ///< Package Language (ISO 639-1 language code followed by underscore and ISO 3166 country code)
+ std::string url; ///< Package download URL (UTF-8 encoded)
+ };
+
+ typedef stdex::idrec::record package_info_rec;
+
+
+ ///
+ /// Signature
+ ///
+ typedef std::vector signature;
+
+ typedef stdex::idrec::record signature_rec;
+};
+
+
+const Updater::recordid_t stdex::idrec::record::id = *(Updater::recordid_t*)"PKG";
+const Updater::recordid_t stdex::idrec::record::id = *(Updater::recordid_t*)"SGN";
+
+#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS)