Refactor project structure
This commit is contained in:
423
core/anslicensing/generator.h
Normal file
423
core/anslicensing/generator.h
Normal file
@@ -0,0 +1,423 @@
|
||||
#pragma once
|
||||
|
||||
#include "bitstream.h"
|
||||
#include "base32.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#ifndef LICENSING_NO_NETWORKING
|
||||
#ifdef _WIN32
|
||||
#include <winhttp.h>
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
class KeyGeneratorImpl {
|
||||
public:
|
||||
KeyGeneratorImpl():
|
||||
m_signingServiceStatusCode(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KeyGeneratorImpl(const LicenseTemplateImpl * templ):
|
||||
KeyGeneratorImpl()
|
||||
{
|
||||
SetKeyTemplate(templ);
|
||||
}
|
||||
|
||||
void SetKeyTemplate(const LicenseTemplateImpl * templ)
|
||||
{
|
||||
m_keyTemplate = templ;
|
||||
|
||||
m_keyData.Create(m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_keyEncoding);
|
||||
m_keyData.GetBitStream().Clear();
|
||||
|
||||
for (const auto& field : m_keyTemplate->m_dataFields)
|
||||
m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
|
||||
|
||||
if (m_keyTemplate->m_validationDataSize)
|
||||
{
|
||||
m_validationData.Create(m_keyTemplate->m_validationDataSize);
|
||||
m_validationData.GetBitStream().Clear();
|
||||
|
||||
for (const auto& field : m_keyTemplate->m_validationFields)
|
||||
m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
|
||||
}
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_keyData.Set(fieldName, buf, len);
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_keyData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, int data)
|
||||
{
|
||||
m_keyData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetKeyData(const char * fieldName, int year, int month, int day)
|
||||
{
|
||||
m_keyData.Set(fieldName, year, month, day);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, const void * buf, int len)
|
||||
{
|
||||
m_validationData.Set(fieldName, buf, len);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, const char * data)
|
||||
{
|
||||
m_validationData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
void SetValidationData(const char * fieldName, int data)
|
||||
{
|
||||
m_validationData.Set(fieldName, data);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static size_t
|
||||
CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
KeyGeneratorImpl * pthis = (KeyGeneratorImpl *)userp;
|
||||
size_t realsize = size * nmemb;
|
||||
|
||||
if (realsize > 1024 || pthis->m_keyBuffer.length() > 1024)
|
||||
return realsize - 1; // signal error
|
||||
|
||||
if (realsize > 0)
|
||||
pthis->m_keyBuffer.append((char *)contents, realsize);
|
||||
|
||||
return realsize;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char * GenerateKey()
|
||||
{
|
||||
BitStream signedData;
|
||||
BitStream signature;
|
||||
ECC::Signer signer;
|
||||
int sigLen, sigLenBits;
|
||||
|
||||
#ifndef LICENSING_NO_NETWORKING
|
||||
if (m_keyTemplate->m_signingKey == NULL)
|
||||
{
|
||||
|
||||
|
||||
m_signingServiceStatusCode = -1;
|
||||
|
||||
string activationQuery("Activate.ashx?");
|
||||
|
||||
//if (activationQuery[m_keyTemplate->m_signingServiceUrl.length() - 1] != '/')
|
||||
// activationQuery.append(1, '/');
|
||||
//activationQuery.append("Activate.ashx?");
|
||||
|
||||
unsigned char * buf = (unsigned char *)_alloca(1 + ((m_validationData.GetSize() + 7) >> 3));
|
||||
|
||||
void * enumHandle = NULL;
|
||||
const char * name;
|
||||
BitStruct::FIELD_TYPE type;
|
||||
int size, offset;
|
||||
|
||||
while (m_keyTemplate->EnumValidationFields(&enumHandle, &name, (int*)&type, &size, &offset))
|
||||
{
|
||||
m_validationData.GetBitStream().Seek(offset);
|
||||
m_validationData.GetBitStream().Read(buf, size);
|
||||
|
||||
activationQuery.append(name);
|
||||
activationQuery.append("=");
|
||||
|
||||
if ((int)type == FIELD_TYPE_STRING)
|
||||
{
|
||||
buf[(size + 7) >> 3] = '\0';
|
||||
activationQuery.append((char *)buf);
|
||||
} else
|
||||
{
|
||||
BASE64 base64;
|
||||
|
||||
string base64Value = base64.encode(buf, (size + 7) >> 3, true);
|
||||
|
||||
replace_all(base64Value, "+", "%2B");
|
||||
replace_all(base64Value, "/", "%2F");
|
||||
replace_all(base64Value, "=", "%3D");
|
||||
|
||||
activationQuery.append(base64Value.c_str());
|
||||
}
|
||||
|
||||
activationQuery.append("&");
|
||||
}
|
||||
|
||||
if (m_keyTemplate->m_licensingServiceParameters.length() > 0)
|
||||
{
|
||||
activationQuery.append(m_keyTemplate->m_licensingServiceParameters);
|
||||
activationQuery.append("&");
|
||||
}
|
||||
|
||||
activationQuery.erase(activationQuery.length() - 1, 1);
|
||||
|
||||
m_keyBuffer.clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
URL_COMPONENTS urlComponents;
|
||||
|
||||
ZeroMemory(&urlComponents, sizeof(urlComponents));
|
||||
urlComponents.dwStructSize = sizeof(urlComponents);
|
||||
|
||||
urlComponents.dwHostNameLength = (DWORD)-1;
|
||||
urlComponents.dwUrlPathLength = (DWORD)-1;
|
||||
|
||||
auto licensingServiceUrl = s2w(m_keyTemplate->m_licensingServiceUrl);
|
||||
|
||||
if (!WinHttpCrackUrl(licensingServiceUrl.c_str(), m_keyTemplate->m_licensingServiceUrl.length(), 0L, &urlComponents))
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (1)"));
|
||||
|
||||
std::wstring hostName(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> internet_ptr(WinHttpOpen(L"ANSCENTER Licensing SDK 2.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0L), WinHttpCloseHandle);
|
||||
|
||||
if (!internet_ptr)
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (2)"));
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> connection_ptr(WinHttpConnect(internet_ptr.get(), hostName.c_str(), urlComponents.nPort, 0L), WinHttpCloseHandle);
|
||||
if (!connection_ptr)
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (3)"));
|
||||
|
||||
activationQuery.insert(0, w2s(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength));
|
||||
|
||||
DWORD requestFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
|
||||
if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
|
||||
requestFlags |= WINHTTP_FLAG_SECURE;
|
||||
|
||||
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> request_ptr(WinHttpOpenRequest(connection_ptr.get(), L"GET", s2w(activationQuery).c_str(), NULL, NULL, NULL, requestFlags), WinHttpCloseHandle);
|
||||
if (!request_ptr)
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (4)"));
|
||||
|
||||
if (!WinHttpSendRequest(request_ptr.get(), NULL, 0L, NULL, 0L, 0L, 0L))
|
||||
{
|
||||
DWORD result = GetLastError();
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (5)"));
|
||||
}
|
||||
|
||||
if (!WinHttpReceiveResponse(request_ptr.get(), NULL))
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (6)"));
|
||||
|
||||
DWORD status;
|
||||
DWORD statusSize = sizeof(DWORD);
|
||||
|
||||
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusSize, WINHTTP_NO_HEADER_INDEX))
|
||||
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (7)"));
|
||||
|
||||
m_signingServiceStatusCode = status;
|
||||
|
||||
if (status != HTTP_STATUS_OK && status != HTTP_STATUS_ACCEPTED && status != HTTP_STATUS_CREATED)
|
||||
{
|
||||
WCHAR buffer[1024];
|
||||
DWORD bufferSize = 1024;
|
||||
|
||||
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX, buffer, &bufferSize, WINHTTP_NO_HEADER_INDEX))
|
||||
throw new LicensingException(STATUS_NET_ERROR, "networking error (8)");
|
||||
|
||||
throw new LicensingException(STATUS_NET_ERROR, w2s(buffer).c_str());
|
||||
}
|
||||
|
||||
DWORD dataSize, count;
|
||||
char buffer[0x100];
|
||||
|
||||
do {
|
||||
if (!WinHttpQueryDataAvailable(request_ptr.get(), &dataSize))
|
||||
break;
|
||||
|
||||
if (size > 0x100)
|
||||
size = 0x100;
|
||||
|
||||
if (WinHttpReadData(request_ptr.get(), buffer, dataSize, &count))
|
||||
m_keyBuffer.append(buffer, count);
|
||||
|
||||
} while (dataSize > 0);
|
||||
#else
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
if ((curl = curl_easy_init()) == NULL)
|
||||
throw new LicensingException(STATUS_NET_ERROR, "cURL initalization failed");
|
||||
|
||||
if (*(m_keyTemplate->m_licensingServiceUrl.rbegin()) != '/')
|
||||
activationQuery.insert(0, "/");
|
||||
|
||||
activationQuery.insert(0, m_keyTemplate->m_licensingServiceUrl);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, activationQuery.c_str());
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
throw new LicensingException(STATUS_NET_ERROR, curl_easy_strerror(res));
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
#endif
|
||||
|
||||
m_key = m_keyBuffer.c_str();
|
||||
|
||||
return m_key.c_str();
|
||||
}
|
||||
#else
|
||||
if (m_keyTemplate->m_signingKey == NULL)
|
||||
{
|
||||
throw new LicensingException(STATUS_NET_ERROR, "private key not provided");
|
||||
}
|
||||
#endif
|
||||
|
||||
// signed data is license key data followed by validation data
|
||||
signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize);
|
||||
|
||||
if (m_keyTemplate->m_dataSize)
|
||||
signedData.Write(m_keyData.GetBuffer(), m_keyTemplate->m_dataSize);
|
||||
|
||||
if (m_keyTemplate->m_validationDataSize)
|
||||
signedData.Write(m_validationData.GetBuffer(), m_keyTemplate->m_validationDataSize);
|
||||
|
||||
signedData.ZeroPadToNextByte();
|
||||
|
||||
// create a bit stream to hold the signature
|
||||
signature.Create(m_keyTemplate->m_signatureSize);
|
||||
|
||||
// sign data
|
||||
|
||||
// we use a different algorithm than ECDSA when the signature size must be smaller than twice the key size
|
||||
if (m_keyTemplate->m_signatureSize < (m_keyTemplate->m_signatureKeySize << 1))
|
||||
signer.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize);
|
||||
else
|
||||
signer.SetHashSize(0);
|
||||
|
||||
signer.SetPrivateKey(m_keyTemplate->m_signingKey.get());
|
||||
|
||||
signer.Sign(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3,
|
||||
signature.GetBuffer(), &sigLen, &sigLenBits);
|
||||
|
||||
signature.ReleaseBuffer(sigLenBits);
|
||||
|
||||
// write the signature at the end of key data
|
||||
m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize);
|
||||
m_keyData.GetBitStream().Write(signature.GetBuffer(), m_keyTemplate->m_signatureSize);
|
||||
|
||||
// text-encode the license key
|
||||
EncodeKey();
|
||||
|
||||
// success
|
||||
return m_key.c_str();
|
||||
}
|
||||
|
||||
int GetSigningServiceStatusCode()
|
||||
{
|
||||
return m_signingServiceStatusCode;
|
||||
}
|
||||
|
||||
void EncodeKey()
|
||||
{
|
||||
|
||||
string buf;
|
||||
|
||||
// set all bits to 0 until the next byte boundary
|
||||
//m_rawKey.ZeroPadToNextByte();
|
||||
|
||||
// reverse last byte from the stream,
|
||||
// so that we will not lose significant bits in the padless, truncated BAS32/64 encoding
|
||||
unsigned char * lastBytePtr = (unsigned char *)m_keyData.GetBuffer() + ((m_keyData.GetSize() + 7) >> 3) - 1;
|
||||
*lastBytePtr = (unsigned char)(((*lastBytePtr * 0x0802LU & 0x22110LU) | (*lastBytePtr * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
|
||||
|
||||
switch (m_keyTemplate->m_keyEncoding)
|
||||
{
|
||||
case ENCODING_BASE32X:
|
||||
{
|
||||
BASE32 base32;
|
||||
buf = base32.encode((unsigned char *)m_keyData.GetBuffer(), (m_keyData.GetSize() + 7) >> 3, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case ENCODING_BASE64X:
|
||||
{
|
||||
BASE64 base64;
|
||||
buf = base64.encode((unsigned char *)m_keyData.GetBuffer(), (m_keyData.GetSize() + 7) >> 3, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new LicensingException(STATUS_INVALID_KEY_ENCODING);
|
||||
}
|
||||
|
||||
if (buf.empty())
|
||||
throw new LicensingException(STATUS_OUT_OF_MEMORY);
|
||||
|
||||
m_key = buf.c_str();
|
||||
|
||||
if ((int)m_key.length() > m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup)
|
||||
m_key.resize(m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup);
|
||||
|
||||
int i;
|
||||
int insertPos;
|
||||
// separate character groups
|
||||
for (i = 0, insertPos = m_keyTemplate->m_charsPerGroup; i < m_keyTemplate->m_numGroups - 1; i++)
|
||||
{
|
||||
m_key.insert(insertPos, m_keyTemplate->m_groupSeparator);
|
||||
insertPos += (unsigned)( m_keyTemplate->m_groupSeparator.length() + m_keyTemplate->m_charsPerGroup );
|
||||
}
|
||||
|
||||
// add header and footer (if any)
|
||||
if (!m_keyTemplate->m_header.empty())
|
||||
m_key.insert(0, m_keyTemplate->m_header + "\r\n");
|
||||
|
||||
if (!m_keyTemplate->m_footer.empty())
|
||||
m_key.append("\r\n" + m_keyTemplate->m_footer);
|
||||
}
|
||||
|
||||
std::size_t replace_all(std::string& inout, std::string_view what, std::string_view with)
|
||||
{
|
||||
std::size_t count{};
|
||||
|
||||
for (std::string::size_type pos{};
|
||||
inout.npos != (pos = inout.find(what.data(), pos, what.length()));
|
||||
pos += with.length(), ++count) {
|
||||
inout.replace(pos, what.length(), with.data(), with.length());
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = str.find(oldStr, pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(pos, oldStr.length(), newStr);
|
||||
pos += newStr.length();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const LicenseTemplateImpl* m_keyTemplate;
|
||||
|
||||
string m_keyBuffer;
|
||||
string m_key;
|
||||
|
||||
BitStruct m_keyData;
|
||||
BitStruct m_validationData;
|
||||
|
||||
int m_signingServiceStatusCode;
|
||||
};
|
||||
Reference in New Issue
Block a user