Refactor project structure

This commit is contained in:
2026-03-28 19:56:39 +11:00
parent 1d267378b2
commit 8a2e721058
511 changed files with 59 additions and 48 deletions

View File

@@ -0,0 +1,17 @@
# anslicensing — Licensing SDK (shared library, built from source)
file(GLOB ANSLICENSING_SOURCES "*.cpp" "*.c")
file(GLOB ANSLICENSING_HEADERS "*.h")
add_library(anslicensing SHARED ${ANSLICENSING_SOURCES} ${ANSLICENSING_HEADERS})
target_include_directories(anslicensing PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_compile_definitions(anslicensing PRIVATE ANSLICENSING_EXPORTS LICENSING_EXPORTS _USRDLL)
if(WIN32)
target_link_libraries(anslicensing PRIVATE ${WIN_COMMON_LIBS} winhttp)
else()
target_link_libraries(anslicensing PRIVATE ${UNIX_COMMON_LIBS} curl ssl crypto)
endif()

View File

@@ -0,0 +1,395 @@
#include "precomp.h"
#include <cstdlib>
#include <string>
#include <cassert>
#include "base32.h"
const char BASE32::alphabet[] = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
const char BASE32::values[] = {
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -&gt; 09 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -&gt; 19 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -&gt; 29 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -&gt; 39 */
-1,-1,-1,-1,-1,-1,-1,-1, /* - 40 -&gt; 47 */
-1,-1,24,25,26,27,28,29,30,31, /* 0123456789 - 48 -&gt; 57 */
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;&lt;=&gt;?@ABC - 58 -&gt; 67 */
3, 4, 5, 6, 7,-1, 8, 9,10,11, /* DEFGHIJKLM - 68 -&gt; 77 */
12,-1,13,14,15,16,17,18,19,20, /* NOPQRSTUVW - 78 -&gt; 87 */
21,22,23, /* XYZ - 88 -&gt; 90 */
-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, /* abcd - 91 -&gt; 100 */
4, 5, 6, 7,-1, 8, 9,10,11,12, /* efghijklmn - 101 -&gt; 110 */
-1,13,14,15,16,17,18,19,20,21, /* opqrstuvwx - 111 -&gt; 120 */
22,23,-1,-1,-1,-1,-1,-1,-1,-1, /* yz - 121 -&gt; 130 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -&gt; 140 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -&gt; 150 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -&gt; 160 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -&gt; 170 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -&gt; 180 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -&gt; 190 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -&gt; 200 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -&gt; 210 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -&gt; 220 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -&gt; 230 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -&gt; 240 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -&gt; 250 */
-1,-1,-1,-1,-1, /* - 251 -&gt; 255 */
};
BASE32::BASE32()
{
}
BASE32::~BASE32()
{
}
string BASE32::encode(unsigned char * buf, int len, bool padding)
{
int pad;
int enclen = encode_pad_length(len, &pad);
string encbuf;
if (!padding)
pad = 0;
encbuf.resize(enclen + pad + 1); /* Allow for trailing NUL */
encode_exactly(buf, len, encbuf.data(), enclen);
if (pad)
memset(encbuf.data() + enclen, '=', pad);
encbuf[enclen + pad] = '\0';
return encbuf;
}
/*
* encode_exactly
*
* Encode `len' bytes from `buf' into `enclen' bytes starting from `encbuf'.
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
*/
void BASE32::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
unsigned char const *ip = buf + len; /* Input pointer, one byte off end */
char *op = encbuf + enclen; /* Output pointer, one byte off end */
assert(buf);
assert(encbuf);
assert(len > 0);
assert(enclen >= len * 8 / 5);
/*
* In the following picture, we represent how the 5 bytes of input
* are split into groups of 5 bits, each group being encoded as a
* single base32 digit.
*
* input byte 0 1 2 3 4
* +--------+--------+--------+--------+--------+
* |01234012|34012340|12340123|40123401|23401234|
* +--------+--------+--------+--------+--------+
* <---><----><---><----><----><---><----><--->
* output digit 0 1 2 3 4 5 6 7
*
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start encoding from the end. The encoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch (len % 5) {
case 0:
do {
assert(op - encbuf >= 8);
i = (unsigned char) *--ip; /* Input #4 */
*--op = alphabet[i & 0x1f]; /* Ouput #7 */
i >>= 5; /* upper <234>, input #4 */
/* FALLTHROUGH */
case 4:
i |= ((unsigned char) *--ip) << 3; /* had 3 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #6 */
i >>= 5; /* upper <401234>, input #3 */
*--op = alphabet[i & 0x1f]; /* Output #5 */
i >>= 5; /* upper <4>, input #3 */
/* FALLTHROUGH */
case 3:
i |= ((unsigned char) *--ip) << 1; /* had 1 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #4 */
i >>= 5; /* upper <1234>, input #2 */
/* FALLTHROUGH */
case 2:
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #3 */
i >>= 5; /* upper <3401234>, input #1 */
*--op = alphabet[i & 0x1f]; /* Output #2 */
i >>= 5; /* upper <34>, input #1 */
/* FALLTHROUGH */
case 1:
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #1 */
i >>= 5; /* upper <01234>, input #0 */
*--op = alphabet[i & 0x1f]; /* Output #0 */
i >>= 5; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= encbuf);
} while (op > encbuf);
}
}
/*
* encode_pad_length
*
* Compute the number of base32 digits and amount of padding necessary
* to encode `len' bytes.
*
* Returns the number of base32 digits necessary.
* Furthermore, if `pad' is a non-NULL pointer, it is filled with the amount
* of padding chars that would be necessary.
*/
int BASE32::encode_pad_length(int len, int *pad)
{
int ndigits; /* Base32 digits necessary */
int npad = 0; /* Final padding chars necessary */
int qcount; /* Amount of full quintets */
int remainder; /* Amount of input bytes in final quintet */
assert(len > 0);
qcount = len / 5;
remainder = len - (qcount * 5);
assert(remainder >= 0);
switch (remainder) {
case 0: npad = 0; break;
case 1: npad = 6; break;
case 2: npad = 4; break;
case 3: npad = 3; break;
case 4: npad = 1; break;
default: assert(0); /* Not possible */
}
ndigits = qcount * 8; /* Each full quintet encoded on 8 bytes */
if (npad != 0)
ndigits += (8 - npad);
if (pad)
*pad = npad;
return ndigits;
}
vector<unsigned char> BASE32::decode( const char * buf, int len, int * outlen )
{
int declen;
vector<unsigned char> decbuf;
int decoded;
if (len == 0 || (len & 0x7)) /* Empty, or padding bytes missing */
{
decbuf.clear();
return decbuf;
}
declen = (len >> 3) * 5;
decbuf.resize(declen);
decoded = decode_into(buf, len, decbuf.data(), declen);
if (decoded == 0)
decbuf.clear();
if (outlen != NULL)
*outlen = decoded;
return decbuf;
}
/*
* decode_into
*
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf',
* faking the necessary amount of padding if necessary.
* Caller must have ensured that there was sufficient room in decbuf.
*
* Returns the amount of bytes decoded (without trailing padding) if successful,
* 0 if the input was not valid base32.
*/
int BASE32::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
{
int padding = 0;
if (len & 0x7)
padding = 8 - (len & 0x7);
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
}
/*
* decode_alphabet
*
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf'.
* Caller must have ensured that there was sufficient room in decbuf.
* Uses the specified decoding alphabet.
*
* `padding', when non-zero, is the amount of padding that is missing from
* the input buffer and which we must assume.
*
* Return decoded bytes if successful, 0 if the input was not valid base32.
*/
int BASE32::decode_alphabet(const char valmap[],
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
char const *ip = buf + len; /* Input pointer, one byte off end */
int dlen = (len >> 3) * 5; /* Exact decoded length */
unsigned char *op; /* Output pointer, one byte off end */
int bytes; /* bytes decoded without padding */
char v;
assert(padding >= 0);
assert(buf);
assert(decbuf);
assert(len > 0);
assert((len & 0x7) == 0); /* `len' is a multiple of 8 bytes */
//assert(declen >= dlen);
/*
* If the last byte of input is '=', there is padding and we need to
* zero the tail of the decoding buffer.
*
* Likewise, when `padding' is non-zero, act as if the '=' were there.
*/
if (buf[len-1] == '=' || padding > 0) {
int pad = 0;
int n = 0; /* Amount of bytes to zero */
int s = 0; /* Amount of bytes to zero */
/*
* Remove and count trailing input padding bytes.
*/
if (padding == 0) {
while (*--ip == '=')
pad++;
ip++; /* Points one byte after real non-padding input */
} else {
pad = padding;
ip -= padding;
}
switch (pad) {
case 1: n = 1; s = 0; break;
case 3: n = 2; s = 1; break;
case 4: n = 3; s = 2; break;
case 6: n = 4; s = 3; break;
default:
return 0; /* Cannot be valid base32 */
}
memset(decbuf + (dlen - n), 0, n);
op = decbuf + (dlen - s);
bytes = dlen - n;
} else {
op = decbuf + dlen;
bytes = dlen;
}
/*
* In the following picture, we represent how the 8 bytes of input,
* each consisting of only 5 bits of information forming a base32 digit,
* are concatenated back into 5 bytes of binary information.
*
* input digit 0 1 2 3 4 5 6 7
* <---><----><---><----><----><---><----><--->
* +--------+--------+--------+--------+--------+
* |01234012|34012340|12340123|40123401|23401234|
* +--------+--------+--------+--------+--------+
* output byte 0 1 2 3 4
*
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start decoding from the end. The decoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch ((ip - buf) % 8) {
case 0:
do {
i = valmap[(unsigned char) *--ip]; /* Input #7 */
if (i < 0)
return 0;
/* FALLTHROUGH */
case 7:
v = valmap[(unsigned char) *--ip]; /* Input #6 */
if (v < 0)
return 0;
i |= v << 5; /* had 5 bits */
*--op = i & 0xff; /* Output #4 */
i >>= 8; /* lower <01> of output #3 */
/* FALLTHROUGH */
case 6:
v = valmap[(unsigned char) *--ip]; /* Input #5 */
if (v < 0)
return 0;
i |= v << 2; /* had 2 bits */
/* FALLTHROUGH */
case 5:
v = valmap[(unsigned char) *--ip]; /* Input #4 */
if (v < 0)
return 0;
i |= v << 7; /* had 7 bits */
*--op = i & 0xff; /* Output #3 */
i >>= 8; /* lower <0123> of output #2 */
/* FALLTHROUGH */
case 4:
v = valmap[(unsigned char) *--ip]; /* Input #3 */
if (v < 0)
return 0;
i |= v << 4; /* had 4 bits */
*--op = i & 0xff; /* Output #2 */
i >>= 8; /* lower <0> of output #1 */
/* FALLTHROUGH */
case 3:
v = valmap[(unsigned char) *--ip]; /* Input #2 */
if (v < 0)
return 0;
i |= v << 1; /* had 1 bit */
/* FALLTHROUGH */
case 2:
v = valmap[(unsigned char) *--ip]; /* Input #1 */
if (v < 0)
return 0;
i |= v << 6; /* had 6 bits */
*--op = i & 0xff; /* Output #1 */
i >>= 8; /* lower <012> of output #0 */
/* FALLTHROUGH */
case 1:
v = valmap[(unsigned char) *--ip]; /* Input #0 */
if (v < 0)
return 0;
i |= v << 3; /* had 3 bits */
*--op = i & 0xff; /* Output #0 */
i >>= 8; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= decbuf);
} while (op > decbuf);
}
return bytes;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
using namespace std;
class BASE32 {
public:
BASE32();
~BASE32();
string encode(unsigned char * input, int len, bool padding = false);
vector<unsigned char> decode(const char * input, int len, int * outlen);
int encode_pad_length(int len, int *pad);
private:
void encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen);
int decode_into(const char *buf, int len, unsigned char *decbuf, int declen);
int decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding);
static const char values[];
static const char alphabet[];
};

View File

@@ -0,0 +1,378 @@
#include "precomp.h"
#include <cstdlib>
#include <string>
#include <cassert>
#include "base64.h"
using namespace std;
/*
* The Base 64 Alphabet
*
* Value Encoding Value Encoding Value Encoding Value Encoding
* 0 A 17 R 34 i 51 z
* 1 B 18 S 35 j 52 0
* 2 C 19 T 36 k 53 1
* 3 D 20 U 37 l 54 2
* 4 E 21 V 38 m 55 3
* 5 F 22 W 39 n 56 4
* 6 G 23 X 40 o 57 5
* 7 H 24 Y 41 p 58 6
* 8 I 25 Z 42 q 59 7
* 9 J 26 a 43 r 60 8
* 10 K 27 b 44 s 61 9
* 11 L 28 c 45 t 62 +
* 12 M 29 d 46 u 63 /
* 13 N 30 e 47 v
* 14 O 31 f 48 w (pad) =
* 15 P 32 g 49 x
* 16 Q 33 h 50 y
*/
const char BASE64::alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char BASE64::values[] = {
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -> 09 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -> 19 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -> 29 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -> 39 */
-1,-1,-1,62,-1,-1,-1,63, /* ()*+'-./ - 40 -> 47 */
52,53,54,55,56,57,58,59,60,61, /* 0123456789 - 48 -> 57 */
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;<=>?@ABC - 58 -> 67 */
3, 4, 5, 6, 7, 8, 9,10,11,12, /* DEFGHIJKLM - 68 -> 77 */
13,14,15,16,17,18,19,20,21,22, /* NOPQRSTUVW - 78 -> 87 */
23,24,25,-1,-1,-1,-1,-1,-1,26, /* XYZ[\]^_`a - 88 -> 97 */
27,28,29,30,31,32,33,34,35,36, /* bcdefghijk - 98 -> 107 */
37,38,39,40,41,42,43,44,45,46, /* lmnopqrstu - 108 -> 117 */
47,48,49,50,51, /* vwxyz - 118 -> 122 */
-1,-1,-1,-1,-1,-1,-1,-1, /* - 123 -> 130 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -> 140 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -> 150 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -> 160 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -> 170 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -> 180 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -> 190 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -> 200 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -> 210 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -> 220 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -> 230 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -> 240 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -> 250 */
-1,-1,-1,-1,-1, /* - 251 -> 255 */
};
BASE64::BASE64()
{
}
BASE64::~BASE64()
{
}
string BASE64::encode(unsigned char * buf, int len, bool padding)
{
int pad;
int enclen = encode_pad_length(len, &pad);
string encbuf;
if (!padding)
pad = 0;
encbuf.resize(enclen + pad); /* Allow for trailing NUL */
encode_exactly(buf, len, encbuf.data(), enclen);
if (pad)
memset(encbuf.data() + enclen, '=', pad);
return encbuf;
}
/**
* encode_exactly
*
* Encode `len' bytes from `buf' unsignedo `enclen' bytes starting from `encbuf'.
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
*/
void BASE64::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
unsigned char const *ip = buf + len; /* Input pounsigneder, one byte off end */
char *op = encbuf + enclen; /* Output pounsigneder, one byte off end */
assert(buf);
assert(encbuf);
assert(len > 0);
assert(enclen >= len * 4 / 3);
/*
* In the following picture, we represent how the 3 bytes of input
* are split unsignedo groups of 6 bits, each group being encoded as a
* single base64 digit.
*
* input byte 0 1 2
* +--------+--------+--------+
* |01234501|23450123|45012345|
* +--------+--------+--------+
* <----><-----><-----><---->
* output digit 0 1 2 3
*
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start encoding from the end. The encoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch (len % 3) {
case 0:
do {
assert(op - encbuf >= 4);
i = (unsigned char) *--ip; /* Input #2 */
*--op = alphabet[i & 0x3f]; /* Ouput #3 */
i >>= 6; /* upper <45>, input #2 */
/* FALLTHROUGH */
case 2:
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
*--op = alphabet[i & 0x3f]; /* Output #2 */
i >>= 6; /* upper <2345>, input #1 */
/* FALLTHROUGH */
case 1:
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
*--op = alphabet[i & 0x3f]; /* Output #1 */
i >>= 6; /* upper <012345>, input #0 */
*--op = alphabet[i & 0x3f]; /* Output #0 */
i >>= 6; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= encbuf);
} while (op > encbuf);
}
}
/**
* encode_pad_length
*
* Compute the number of base64 digits and amount of padding necessary
* to encode `len' bytes.
*
* Returns the number of base64 digits necessary.
* Furthermore, if `pad' is a non-NULL pounsigneder, it is filled with the amount
* of padding chars that would be necessary.
*/
int BASE64::encode_pad_length(int len, int *pad)
{
int ndigits; /* Base64 digits necessary */
int npad = 0; /* Final padding chars necessary */
int tcount; /* Amount of full triplets */
int remainder; /* Amount of input bytes in final triplet */
assert(len > 0);
tcount = len / 3;
remainder = len - (tcount * 3);
assert((unsigned) remainder >= 0);
switch (remainder) {
case 0: npad = 0; break;
case 1: npad = 2; break;
case 2: npad = 1; break;
default: assert(0); /* Not possible */
}
ndigits = tcount * 4; /* Each full triplet encoded on 4 bytes */
if (npad != 0)
ndigits += (4 - npad);
if (pad)
*pad = npad;
return ndigits;
}
/**
* base64_decode
*
* Decode `len' bytes starting at `buf' unsignedo new allocated buffer.
*
* Returns the new decoded buffer, or NULL if the input was not valid base64
* encoding. The caller knows the length of the returned buffer: it's the
* size of the input divided by 4 and multiplied by 3. If `outlen' is non-NULL,
* it is filled with the amount of bytes decoded unsignedo the buffer (without
* trailing padding).
*/
vector<unsigned char> BASE64::decode(const char * buf, int len, int * outlen)
{
int declen;
vector<unsigned char> decbuf;
int decoded;
if (len == -1)
len = strlen(buf);
// if (len == 0 || (len & 0x3)) /* Empty, or padding bytes missing */
// return NULL;
declen = (len >> 2) * 3;
decbuf.resize(declen * sizeof(unsigned char));
decoded = decode_into(buf, len, decbuf.data(), declen);
if (decoded == 0)
decbuf.clear();
if (outlen)
*outlen = decoded;
return decbuf;
}
/**
* decode_into
*
* Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf',
* faking the necessary amount of padding if necessary.
* Caller must have ensured that there was sufficient room in decbuf.
*
* Returns the amount of bytes decoded (without trailing padding) if successful,
* 0 if the input was not valid base32.
*/
int BASE64::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
{
int padding = 0;
if (len & 0x3)
padding = 4 - (len & 0x3);
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
}
/*
* decode_alphabet
*
* Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf'.
* Caller must have ensured that there was sufficient room in decbuf.
* Uses the specified decoding alphabet.
*
* `padding', when non-zero, is the amount of padding that is missing from
* the input buffer and which we must assume.
*
* Return decoded bytes if successful, 0 if the input was not valid base32.
*/
int BASE64::decode_alphabet(const char valmap[],
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
char const *ip = buf + len; /* Input pounsigneder, one byte off end */
int dlen = (len >> 2) * 3; /* Exact decoded length */
unsigned char *op; /* Output pounsigneder, one byte off end */
int bytes; /* Bytes decoded without padding */
char v;
assert(buf);
assert(decbuf);
assert(len > 0);
assert((len & 0x3) == 0); /* `len' is a multiple of 4 bytes */
//assert(declen >= dlen);
/*
* If the last byte of input is '=', there is padding and we need to
* zero the tail of the decoding buffer.
*
* Likewise, when `padding' is non-zero, act as if the '=' were there.
*/
if (buf[len-1] == '=' || padding > 0) {
int pad = 0;
int n = 0; /* Amount of bytes to zero */
int s = 0; /* Amount of bytes to zero */
/*
* Remove and count trailing input padding bytes.
*/
if (padding == 0) {
while (*--ip == '=')
pad++;
ip++; /* Pounsigneds one byte after real non-padding input */
} else {
pad = padding;
ip -= padding;
}
switch (pad) {
case 1: n = 1; s = 0; break;
case 2: n = 2; s = 1; break;
default:
return 0; /* Cannot be valid base64 */
}
memset(decbuf + (dlen - n), 0, n);
op = decbuf + (dlen - s);
bytes = dlen - n;
} else {
op = decbuf + dlen;
bytes = dlen;
}
/*
* In the following picture, we represent how the 4 bytes of input,
* each consisting of only 6 bits of information forming a base64 digit,
* are concatenated back unsignedo 3 bytes of binary information.
*
* input digit 0 1 2 3
* <----><-----><-----><---->
* +--------+--------+--------+
* |01234501|23450123|45012345|
* +--------+--------+--------+
* output byte 0 1 2
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start decoding from the end. The decoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch ((ip - buf) % 4) {
case 0:
do {
v = valmap[(unsigned char) *--ip]; /* Input #3 */
if (v < 0) return 0;
i = v;
/* FALLTHROUGH */
case 3:
v = valmap[(unsigned char) *--ip]; /* Input #2 */
if (v < 0) return 0;
i |= v << 6; /* had 6 bits */
*--op = i & 0xff; /* Output #2 */
i >>= 8; /* lower <0123> of output #1 */
/* FALLTHROUGH */
case 2:
v = valmap[(unsigned char) *--ip]; /* Input #1 */
if (v < 0) return 0;
i |= v << 4; /* had 4 bits */
*--op = i & 0xff; /* Output #1 */
i >>= 8; /* lower <01> of output #0 */
/* FALLTHROUGH */
case 1:
v = valmap[(unsigned char) *--ip]; /* Input #0 */
if (v < 0) return 0;
i |= v << 2; /* had 2 bits */
*--op = i & 0xff; /* Output #0 */
i >>= 8; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= decbuf);
} while (op > decbuf);
}
return bytes;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
using namespace std;
class BASE64 {
public:
BASE64();
~BASE64();
string encode(unsigned char * input, int len, bool padding = false);
vector<unsigned char> decode(const char * input, int len = -1, int * outlen = nullptr);
int encode_pad_length(int len, int *pad);
private:
void encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen);
int decode_into(const char *buf, int len, unsigned char *decbuf, int declen);
int decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding);
static const char values[];
static const char alphabet[];
};

1000
core/anslicensing/bigint.cpp Normal file

File diff suppressed because it is too large Load Diff

130
core/anslicensing/bigint.h Normal file
View File

@@ -0,0 +1,130 @@
#ifndef __BIGINT_H
#define __BIGINT_H
class bigint;
class bigint_value;
class bigint_unit // Provides storage allocation and index checking
{
friend class bigint_value;
friend class bigint;
public:
bigint_unit();
~bigint_unit();
public:
void clear(); // set n to zero
unsigned get( unsigned i ) const; // get ith unsigned
void set( unsigned i, unsigned x ); // set ith unsigned
void reserve( unsigned x ); // storage hint
void fast_mul( bigint_unit & x, bigint_unit & y, unsigned n ); // Time critical routine
private:
unsigned n; // used units (read-only)
unsigned * a; // array of units
unsigned z; // units allocated
};
class bigint_value : public bigint_unit
{
friend class bigint;
public:
bigint_value();
public:
int is_zero() const;
unsigned bit( unsigned i ) const;
void setbit( unsigned i );
void clearbit( unsigned i );
unsigned bits() const;
int cf( bigint_value& x ) const;
int product( bigint_value &x ) const;
void shl();
int shr(); // result is carry
void shr( unsigned n );
void add( bigint_value& x );
void _xor( bigint_value& x );
void _and( bigint_value& x );
void subtract( bigint_value& x );
void init( unsigned x );
void copy( bigint_value& x );
unsigned to_unsigned(); // Unsafe conversion to unsigned
void mul( bigint_value& x, bigint_value& y );
void divide( bigint_value& x, bigint_value& y, bigint_value& rem );
private:
unsigned share; // share count, used by bigint to delay physical copying
};
class bigint // very long integer - can be used like long
{
public:
// Construction and
bigint ( unsigned x = 0 );
bigint ( const bigint & x );
~bigint();
public:
// Standard arithmetic operators
friend bigint operator +( const bigint& x, const bigint& y );
friend bigint operator -( const bigint& x, const bigint& y );
friend bigint operator *( const bigint& x, const bigint& y );
friend bigint operator /( const bigint& x, const bigint& y );
friend bigint operator %( const bigint& x, const bigint& y );
friend bigint operator ^( const bigint& x, const bigint& y );
friend bigint pow2( unsigned n );
friend bigint operator &( const bigint& x, const bigint& y );
friend bigint operator <<( const bigint& x, unsigned n );
bigint & operator +=( const bigint& x );
bigint & operator -=( const bigint& x );
bigint & operator >>=( unsigned n );
// Standard comparison operators
friend int operator !=( const bigint& x, const bigint& y );
friend int operator ==( const bigint& x, const bigint& y );
friend int operator >=( const bigint& x, const bigint& y );
friend int operator <=( const bigint& x, const bigint& y );
friend int operator > ( const bigint& x, const bigint& y );
friend int operator < ( const bigint& x, const bigint& y );
// Absolute value
friend bigint abs( const bigint & x );
// conversion operations
friend unsigned to_unsigned( const bigint &x );
bigint & operator =(const bigint& x);
// Bit operations
unsigned bits() const;
unsigned bit(unsigned i) const;
void setbit(unsigned i);
void clearbit(unsigned i);
bigint & operator ^=( const bigint& x );
bigint & operator &=( const bigint& x );
bigint & ror( unsigned n ); // single bit rotate
bigint & rol( unsigned n ); // single bit rotate
friend int product( const bigint & x, const bigint & y ); // parity of x&y
void load( const unsigned * a, unsigned n ); // load value, a[0] is lsw
void store( unsigned * a, unsigned n ) const; // low level save, a[0] is lsw
private:
bigint_value * value;
int negative;
int cf( const bigint & x ) const;
void docopy();
friend class monty;
};
bigint modexp( const bigint & x, const bigint & e, const bigint & m ); // m must be odd
bigint gcd( const bigint & X, const bigint & Y ); // greatest common denominator
bigint modinv( const bigint & a, const bigint & m ); // modular inverse
bigint lucas ( const bigint & P, const bigint & Z, const bigint & k, const bigint & p ); // P^2 - 4Z != 0
bigint sqrt( const bigint & g, const bigint & p ); // square root mod p
bigint pow2( unsigned n );
#endif

View File

@@ -0,0 +1,232 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <tchar.h>
#endif
#include "bitstream.h"
using namespace std;
BitStream::BitStream(int bitSize)
{
Create(bitSize);
}
BitStream::BitStream(vector<unsigned char>& buf, int bufBits)
{
Attach(buf, bufBits);
}
bool BitStream::Create(int bitCount)
{
m_bufBits = bitCount;
m_currentBitIndex = 0;
if (!bitCount)
{
m_buf.clear();
return true;
}
m_buf.resize((bitCount + 7) >> 3);
Clear();
return true;
}
void BitStream::Attach(vector<unsigned char>& buf, int bufBits)
{
m_buf = std::move(buf);
m_bufBits = bufBits;
m_currentBitIndex = 0;
}
int BitStream::Read(void *bitPtr, int bitCount)
{
if(bitCount + m_currentBitIndex > m_bufBits)
{
bitCount = m_bufBits - m_currentBitIndex;
}
if(!bitCount)
{
return 0;
}
int readBitCount = bitCount;
unsigned char lastByteMask = (unsigned char)((1 << (readBitCount & 7)) - 1);
unsigned char * sourcePtr = m_buf.data() + (m_currentBitIndex >> 3);
int byteCount = (bitCount + 7) >> 3;
unsigned char * destPtr = (unsigned char *)bitPtr;
int downShift = m_currentBitIndex & 0x7;
int upShift = 8 - downShift;
if (!downShift)
{
while(byteCount--)
*destPtr++ = *sourcePtr++;
m_currentBitIndex += bitCount;
if (lastByteMask > 0)
((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask;
return readBitCount;
}
unsigned char sourceByte = *sourcePtr >> downShift;
m_currentBitIndex += bitCount;
for (; bitCount > 8; bitCount -= 8)
{
unsigned char nextByte = *++sourcePtr;
*destPtr++ = sourceByte | (nextByte << upShift);
sourceByte = nextByte >> downShift;
}
if (bitCount)
{
if (bitCount <= upShift)
{
*destPtr = sourceByte;
return readBitCount;
}
*destPtr = sourceByte | ( (*++sourcePtr) << upShift);
}
if (lastByteMask > 0)
((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask;
return readBitCount;
}
int BitStream::Write(const void * bitPtr, int bitCount)
{
int maxBits = ((m_bufBits + 7) >> 3) << 3;
if (bitCount + m_currentBitIndex > maxBits)
{
bitCount = maxBits - m_currentBitIndex;
}
if(!bitCount)
return 0;
int writeBitCount = bitCount;
int upShift = m_currentBitIndex & 0x7;
int downShift = 8 - upShift;
const unsigned char * sourcePtr = (unsigned char *)bitPtr;
unsigned char * destPtr = m_buf.data() + (m_currentBitIndex >> 3);
// if this write is for <= 1 byte, and it will all fit in the
// first dest byte, then do some special masking.
if (downShift >= bitCount)
{
unsigned char mask = (unsigned char)(((1 << bitCount) - 1) << upShift);
*destPtr = (*destPtr & ~mask) | ((*sourcePtr << upShift) & mask);
m_currentBitIndex += bitCount;
return writeBitCount;
}
// check for byte aligned writes -- this will be
// much faster than the shifting writes.
if(!upShift)
{
m_currentBitIndex += bitCount;
for(; bitCount >= 8; bitCount -= 8)
*destPtr++ = *sourcePtr++;
if(bitCount)
{
unsigned char mask = (unsigned char)((1 << bitCount) - 1);
*destPtr = (*sourcePtr & mask) | (*destPtr & ~mask);
}
return writeBitCount;
}
// the write destination is not byte aligned.
unsigned char sourceByte;
unsigned char destByte = *destPtr & (0xFF >> downShift);
unsigned char lastMask = (unsigned char)(0xFF >> (7 - ((m_currentBitIndex + bitCount - 1) & 0x7)));
m_currentBitIndex += bitCount;
for(;bitCount >= 8; bitCount -= 8)
{
sourceByte = *sourcePtr++;
*destPtr++ = destByte | (sourceByte << upShift);
destByte = sourceByte >> downShift;
}
if(bitCount == 0)
{
*destPtr = (*destPtr & ~lastMask) | (destByte & lastMask);
return writeBitCount;
}
if(bitCount <= downShift)
{
*destPtr = (*destPtr & ~lastMask) | ((destByte | (*sourcePtr << upShift)) & lastMask);
return writeBitCount;
}
sourceByte = *sourcePtr;
*destPtr++ = destByte | (sourceByte << upShift);
*destPtr = (*destPtr & ~lastMask) | ((sourceByte >> downShift) & lastMask);
return writeBitCount;
}
void BitStream::ZeroPadToNextByte()
{
unsigned char zero = 0;
if(m_currentBitIndex & 0x7)
Write(&zero, 8 - (m_currentBitIndex & 0x7));
}
int BitStream::Seek(int offset, bool relative)
{
unsigned oldIndex = m_currentBitIndex;
m_currentBitIndex = (relative) ? m_currentBitIndex + offset : offset;
return oldIndex;
}
int BitStream::GetSize()
{
return m_bufBits;
}
void * BitStream::GetBuffer(int * sizeInBits)
{
if (sizeInBits != NULL)
*sizeInBits = m_bufBits;
return m_buf.data();
}
void BitStream::ReleaseBuffer(int bitCount)
{
m_currentBitIndex = bitCount;
}
void BitStream::Clear()
{
memset(m_buf.data(), 0, m_buf.size());
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <vector>
using namespace std;
class BitStream
{
public:
BitStream(int bitSize = 0);
BitStream(vector<unsigned char>& buf, int bitSize);
bool Create(int sizeInBits);
void Attach(vector<unsigned char>& buf, int sizeInBits);
int Read(void *bitPtr, int countInBits);
int Write(const void * bitPtr, int countInBits);
int Seek(int offset, bool relative = false);
int GetSize();
void ZeroPadToNextByte();
void * GetBuffer(int * sizeInBits = NULL);
void ReleaseBuffer(int bitCount);
void Clear();
protected:
vector<unsigned char> m_buf;
int m_bufBits;
int m_currentBitIndex;
};

View File

@@ -0,0 +1,125 @@
#include "precomp.h"
#include <stdlib.h>
#include <string.h>
#include "bitstream2.h"
const unsigned char BitStream2::hiMask[] = { 0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
BitStream2::BitStream2() :
ownMemory(false),
currentBit(0),
currentByte(0),
buffer(NULL)
{
}
BitStream2::BitStream2(int bitCount)
{
currentBit = 0;
currentByte = 0;
Create(bitCount);
}
BitStream2::~BitStream2()
{
if (ownMemory)
delete buffer;
}
void BitStream2::Create(int bitCount)
{
bufSize = (bitCount + 7) >> 3;
buffer = new unsigned char[(bitCount + 7) >> 3];
ownMemory = true;
memset(buffer, 0, bufSize);
}
void BitStream2::Attach(void * buf, int bitCount)
{
buffer = (unsigned char *)buf;
}
int BitStream2::Write(const unsigned char * buf, int bitCount)
{
unsigned char destByte;
int leftBits = currentBit & 7;
int rightBits = 8 - leftBits;
int i = 0;
int count = bitCount;
while (count > 0)
{
destByte = (unsigned char)((buffer[currentByte] & hiMask[leftBits]) | (buf[i] >> leftBits));
buffer[currentByte] = destByte;
count = (count > rightBits) ? count - rightBits : 0;
if (count > 0)
{
currentByte++;
buffer[currentByte] = (unsigned char)(buf[i] << rightBits);
count = (count > leftBits) ? count - leftBits : 0;
}
i++;
}
currentBit += bitCount;
return bitCount;
}
int BitStream2::WriteUInt16(unsigned short val)
{
unsigned char split[2]; split[0] = (unsigned char)(val >> 8); split[1] = (unsigned char)(val & 0xFF);
return Write(split, 16);
}
int BitStream2::Read(unsigned char * buf, int bitCount)
{
unsigned char destByte;
int rightBits = 8 - (currentBit & 7);
int leftBits = 8 - rightBits;
int count = bitCount;
int i = 0;
while (count > 0)
{
buf[i] = (unsigned char)(buffer[currentByte] << leftBits);
count = (count > rightBits) ? count - rightBits : 0;
if (count > 0)
{
currentByte++;
destByte = buf[i];
destByte = (unsigned char)(destByte | (buffer[currentByte] >> rightBits));
buf[i] = destByte;
count = (count > leftBits) ? count - leftBits : 0;
}
i++;
}
currentBit += bitCount;
return bitCount;
}
int BitStream2::ReadUInt16(unsigned short * val)
{
unsigned char split[2];
int result = Read(split, 16);
*val = (unsigned short)(((unsigned short)split[0] << 8) | (unsigned short)split[1]);
return result;
}
unsigned char * BitStream2::GetBuffer()
{
return buffer;
}

View File

@@ -0,0 +1,24 @@
#pragma once
class BitStream2
{
public:
BitStream2();
BitStream2(int bitCount);
~BitStream2();
void Create(int bitCount);
void Attach(void * buf, int bitCount);
int Write(const unsigned char * buf, int bitCount);
int WriteUInt16(unsigned short val);
int Read(unsigned char * buf, int bitCount);
int ReadUInt16(unsigned short * val);
unsigned char * GetBuffer();
protected:
bool ownMemory;
unsigned char * buffer;
int bufSize;
int currentBit, currentByte;
static const unsigned char hiMask[];
};

View File

@@ -0,0 +1,144 @@
#include "precomp.h"
#include <stdlib.h>
#include <string.h>
#include "bitstream3.h"
const unsigned char BitStream3::hiMask[] = { 0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
BitStream3::BitStream3() :
ownMemory(false),
currentBit(0),
currentByte(0),
buffer(NULL)
{
}
BitStream3::BitStream3(int bitCount)
{
currentBit = 0;
currentByte = 0;
Create(bitCount);
}
BitStream3::~BitStream3()
{
if (ownMemory)
free(buffer);
}
void BitStream3::Create(int bitCount)
{
bufSize = (bitCount + 7) >> 3;
bitSize = bitCount;
buffer = (unsigned char*)malloc((bitCount + 7) >> 3);
ownMemory = true;
memset(buffer, 0, bufSize);
}
void BitStream3::Attach(void * buf, int bitCount)
{
buffer = (unsigned char *)buf;
bitSize = bitCount;
currentBit = 0;
currentByte = 0;
}
int BitStream3::Write(const unsigned char * buf, int bitCount)
{
int i = 0, gap = 8 - (currentBit & 7);
if (bitCount >= gap)
{
if ((gap & 7) != 0)
{
buffer[currentByte] = (unsigned char)((buffer[currentByte] << gap) | (buf[0] >> (bitCount < 8 ? bitCount - gap : 8 - gap)));
currentBit += gap; bitCount -= gap; currentByte++;
for (; bitCount >= 8; i++, currentByte++, currentBit += 8, bitCount -= 8)
buffer[currentByte] = (unsigned char)((buf[i] << gap) | (buf[i + 1] >> (8 - gap)));
}
else
for (; bitCount >= 8; currentByte++, i++, currentBit += 8, bitCount -= 8)
buffer[currentByte] = buf[i];
}
if (bitCount > 0)
{
buffer[currentByte] = (unsigned char)((buffer[currentByte] << bitCount) | (buf[i] & ((1 << bitCount) - 1)));
currentBit += bitCount;
}
return bitCount;
}
int BitStream3::WriteUInt16(unsigned short val)
{
unsigned char split[2]; split[0] = (unsigned char)(val >> 8); split[1] = (unsigned char)(val & 0xFF);
return Write(split, 16);
}
int BitStream3::Read(unsigned char * readBuf, int bitCount)
{
int i = 0, gap = currentBit & 7;
if ((gap & 7) != 0)
{
for (; bitCount >= 8 + 8 - gap; bitCount -= 8, currentByte++, currentBit += 8, i++)
readBuf[i] = (unsigned char)((buffer[currentByte] << gap) | (buffer[currentByte + 1] >> (8 - gap)));
// byte align
if (bitCount > 0)
{
if (bitCount < 8 - gap)
{
readBuf[i] = (unsigned char)((buffer[currentByte] >> (8 - gap - bitCount)) & ((1 << bitCount) - 1));
currentBit += bitCount;
bitCount = 0;
}
else
{
readBuf[i] = (unsigned char)(buffer[currentByte] & ((1 << (8 - gap)) - 1));
bitCount -= (8 - gap);
currentBit += (8 - gap);
currentByte++;
readBuf[i] <<= (bitCount < gap ? bitCount : gap);
}
}
}
else
for (; bitCount >= 8; bitCount -= 8, currentByte++, currentBit += 8, i++)
readBuf[i] = buffer[currentByte];
// already aligned
if (bitCount > 0)
{
if (currentBit + 8 <= bitSize) // not last byte
readBuf[i] |= (unsigned char)((buffer[currentByte] >> (8 - bitCount)) & ((1 << bitCount) - 1));
else // last byte
readBuf[i] = (unsigned char)((buffer[currentByte] >> ((bitSize & 7) - bitCount)) & ((1 << bitCount) - 1));
currentBit += bitCount;
}
return bitCount;
}
int BitStream3::ReadUInt16(unsigned short * val)
{
unsigned char split[2];
int result = Read(split, 16);
*val = (unsigned short)(((unsigned short)split[0] << 8) | (unsigned short)split[1]);
return result;
}
unsigned char * BitStream3::GetBuffer()
{
return buffer;
}

View File

@@ -0,0 +1,24 @@
#pragma once
class BitStream3
{
public:
BitStream3();
BitStream3(int bitCount);
~BitStream3();
void Create(int bitCount);
void Attach(void * buf, int bitCount);
int Write(const unsigned char * buf, int bitCount);
int WriteUInt16(unsigned short val);
int Read(unsigned char * buf, int bitCount);
int ReadUInt16(unsigned short * val);
unsigned char * GetBuffer();
protected:
bool ownMemory;
unsigned char * buffer;
int bufSize, bitSize;
int currentBit, currentByte;
static const unsigned char hiMask[];
};

View File

@@ -0,0 +1,4 @@
#include "precomp.h"
#include "bitstruct.h"

View File

@@ -0,0 +1,378 @@
#pragma once
#include <memory>
#include <map>
#include "bitstream.h"
#include "uniconv.h"
#include "except.h"
#ifndef _WIN32
#include <alloca.h>
#else
#include <malloc.h>
#endif
using namespace std;
class BitStruct {
public:
enum FIELD_TYPE
{
RAW,
INTEGER,
STRING,
DATE14,
DATE13,
DATE16,
};
private:
class Field {
public:
Field():
m_fieldType(FIELD_TYPE::INTEGER),
m_offset(0),
m_size(0)
{
}
Field(FIELD_TYPE fieldType, int offset, int size)
{
m_fieldType = fieldType;
m_offset = offset;
m_size = size;
}
public:
FIELD_TYPE m_fieldType;
int m_offset;
int m_size;
};
typedef std::map<string, Field> FieldMap;
public:
BitStruct(int bitSize = 0) :
m_bits(bitSize)
{
}
BitStruct(vector<unsigned char>& buf, int bitSize):
m_bits(buf, bitSize)
{
}
void Create(int bitSize = 0)
{
m_bits.Create(bitSize);
}
void Attach(vector<unsigned char>& buf, int bitSize)
{
m_bits.Attach(buf, bitSize);
}
void AddField(const char * fieldName, FIELD_TYPE fieldType, int fieldBitSize, int offset = -1 )
{
if (offset == -1)
offset = currentFieldOffset;
m_fieldMap.insert(FieldMap::value_type(fieldName, Field(fieldType, offset, fieldBitSize)));
currentFieldOffset = offset + fieldBitSize;
}
bool GetField(const char * fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * fieldOffset) const
{
FieldMap::const_iterator iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end())
return false;
*fieldType = iter->second.m_fieldType;
*fieldSize = iter->second.m_size;
*fieldOffset = iter->second.m_offset;
return true;
}
bool EnumFields(void **enumHandle, const char **fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * offset)
{
FieldMap::iterator * pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new FieldMap::iterator(m_fieldMap.begin());
if (!pIter)
return false;
}
else
pIter = (FieldMap::iterator *)(*enumHandle);
if (*pIter == m_fieldMap.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.m_fieldType;
*fieldSize = (*pIter)->second.m_size;
*offset = (*pIter)->second.m_offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void Set(const char * fieldName, const void * buf, unsigned len)
{
int offset = 0, size = m_bits.GetSize();
if (fieldName)
{
FieldMap::iterator iter;
iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end())
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
offset = iter->second.m_offset;
size = iter->second.m_size;
}
m_bits.Seek(offset);
int bitlen = len << 3;
if (bitlen >= size)
m_bits.Write(buf, size);
else
{
int bits = size - bitlen;
unsigned char * zeroes = (unsigned char *)_alloca((bits + 7) >> 3);
memset(zeroes, 0, (bits + 7) >> 3);
m_bits.Write(buf, bitlen);
m_bits.Write(zeroes, bits);
}
}
void Set(const char * fieldName, const char * data)
{
Set(fieldName, data, (unsigned)strlen(data));
}
void Set(const char * fieldName, int data)
{
#ifndef LICENSING_BIG_ENDIAN
Set(fieldName, &data, sizeof(data));
#else
unsigned char buf[sizeof(int)] = { 0, 0, 0, 0 };
buf[0] = (unsigned char)(data & 0xFF);
buf[1] = (unsigned char)((data >> 8) & 0xFF);
buf[2] = (unsigned char)((data >> 16) & 0xFF);
buf[3] = (unsigned char)((data >> 24) & 0xFF);
Set(fieldName, buf, sizeof(data));
#endif
}
void Set(const char * fieldName, int year, int month, int day)
{
FieldMap::iterator iter;
iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
int date;
switch (iter->second.m_fieldType)
{
case FIELD_TYPE_DATE13:
date = PackDate13(year, month, day);
break;
case FIELD_TYPE_DATE14:
date = PackDate14(year, month, day);
break;
case FIELD_TYPE_DATE16:
date = PackDate16(year, month, day);
break;
default:
throw new LicensingException(STATUS_INVALID_PARAM, "A data value is being set to a non-date field");
}
Set(fieldName, date);
}
void Get(const char * dataField, void * buf, int * len)
{
if (dataField)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
if ( *len < ( iter->second.m_size + 7 ) >> 3 )
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
m_bits.Seek(iter->second.m_offset);
m_bits.Read(buf, iter->second.m_size);
*len = (iter->second.m_size + 7) >> 3;
} else
{
int validationDataLen = (m_bits.GetSize() + 7) >> 3;
if (*len < validationDataLen)
{
*len = validationDataLen;
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
}
memcpy(buf, m_bits.GetBuffer(), validationDataLen);
*len = validationDataLen;
}
}
int GetInt(const char * dataField)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
unsigned char buf[sizeof(int)] = {0, 0, 0, 0};
if ( sizeof(buf) < ( iter->second.m_size + 7 ) >> 3 )
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
m_bits.Seek(iter->second.m_offset);
m_bits.Read(buf, iter->second.m_size);
#ifndef LICENSING_BIG_ENDIAN
return *(int *)buf;
#else
return ((int)buf[3] << 24) | ((int)buf[2] << 16) | ((int)buf[1] << 8) | (int)buf[0];
#endif
}
void GetDate(const char * dataField, int * year, int * month, int * day)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
unsigned short packedDate = (unsigned short)GetInt(dataField);
switch (iter->second.m_fieldType)
{
case FIELD_TYPE_DATE13:
UnpackDate13(packedDate, year, month, day);
break;
case FIELD_TYPE_DATE14:
UnpackDate14(packedDate, year, month, day);
break;
case FIELD_TYPE_DATE16:
UnpackDate16(packedDate, year, month, day);
break;
default:
throw new LicensingException(STATUS_INVALID_PARAM, "An attempt was made to query a date from a non-date field");
}
}
void * GetBuffer(int * sizeInBits = NULL)
{
return m_bits.GetBuffer(sizeInBits);
}
BitStream& GetBitStream()
{
return m_bits;
}
int GetCurrentFieldOffset()
{
return currentFieldOffset;
}
void ResetFieldOffset()
{
currentFieldOffset = 0;
}
int GetSize()
{
return m_bits.GetSize();
}
private:
unsigned short PackDate13(int year, int month, int day)
{
if (year < 2012 || year > 2027)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 13-bit date. Allowed values are 2012-2027");
return (unsigned short)(((month - 1) << 9) | ((day - 1) << 4) | (year - 2012));
}
void UnpackDate13(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2012 + (packedDate & 0x0F);
*month = 1 + (packedDate >> 9);
*day = 1 + ((packedDate >> 4) & 0x1F);
}
unsigned short PackDate14(int year, int month, int day)
{
if (year < 2010 || year > 2041)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 14-bit date. Allowed values are 2010-2041");
return (unsigned short)(((month - 1) << 10) | ((day - 1) << 5) | (year - 2010));
}
void UnpackDate14(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2010 + (packedDate & 0x1F);
*month = 1 + (packedDate >> 10);
*day = 1 + ((packedDate >> 5) & 0x1F);
}
unsigned short PackDate16(int year, int month, int day)
{
if (year < 2000 || year > 2127)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 16-bit date. Allowed values are 2010-2127");
return (unsigned short)(((year - 2000) << 9) | (month << 5) | day);
}
void UnpackDate16(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2000 + (packedDate >> 9);
*month = (packedDate & 0x01FF) >> 5;
*day = packedDate & 0x001F;
}
FieldMap m_fieldMap;
BitStream m_bits;
int currentFieldOffset;
};

View File

@@ -0,0 +1,2 @@
#include "precomp.h"
#include "certificate.h"

View File

@@ -0,0 +1,451 @@
#ifndef __CERTIFICATE_H
#define __CERTIFICATE_H
#include "ecc.h"
#include "bitstruct.h"
#include "except.h"
#include "base64.h"
#include "sdkregistration.h"
#include "download.h"
#include <time.h>
using namespace ECC;
class Certificate
{
public:
Certificate()
{
}
Certificate(const char * base64Certificate)
{
BASE64 base64;
int len;
auto buf = base64.decode(base64Certificate, strlen(base64Certificate), &len);
if (buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 encoding for certificate");
Attach(buf, len);
}
Certificate(vector<unsigned char>& buf, int len)
{
Attach(buf, len);
}
void* GetBuffer(int * len)
{
int size;
void * buf = m_certBits.GetBuffer(&size);
size = (size + 7) >> 3;
*len = size;
return buf;
}
const char * ToString()
{
BASE64 base64;
int len;
static string base64cert;
unsigned char * buf = (unsigned char *)m_certBits.GetBuffer(&len);
len = (len + 7) >> 3;
auto base64Buf = base64.encode(buf, len, true);
if (base64Buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
base64cert = base64Buf.c_str();
return base64cert.c_str();
}
/*
static Certificate * Generate(int signatureSize, time_t expirationDate = 0)
{
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, NULL, expirationDate);
}
static Certificate * Generate(int signatureSize, Certificate * signingCertificate, time_t expirationDate = 0)
{
return Generate(signatureSize, NULL, NULL, signingCertificate, NULL, expirationDate);
}
static Certificate * Generate(int signatureSize, const char * certificateAuthorityUrl, time_t expirationDate = 0)
{
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, certificateAuthorityUrl, expirationDate);
}
*/
static bool VerifySignature(Certificate * cert, Certificate * validationCert)
{
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
if (validationCert == NULL || cert->m_certBits.GetInt("IsSelfSigned") != 0)
cert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
else
validationCert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
Key key(rawPublicKey, rawPublicKeyLen);
Verifier verifier;
verifier.SetPublicKey(&key);
unsigned char * certBuffer = (unsigned char *)cert->m_certBits.GetBuffer();
int signedPartLen = 4 + cert->m_certBits.GetInt("PublicKeyLen"),
signatureOffset = 2 + signedPartLen,
signatureBitLen = cert->m_certBits.GetInt("SignatureSizeBits");
if (!verifier.Verify(certBuffer, signedPartLen, certBuffer + signatureOffset, (signatureBitLen + 7) >> 3, signatureBitLen))
return false;
return true;
}
void GetPublicKey(void * buf, int * len)
{
m_certBits.Get("PublicKey", buf, len);
}
static Certificate * Generate(int signatureSize, const char * base64PrivateKey, const char * base64PublicKey, const char * base64SigningPrivateKey, const char * base64SigningCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
{
Key * privateKey = NULL,
* publicKey = NULL,
* privateSigningKey;
Certificate * signingCertificate = NULL;
Certificate * result;
try {
if (base64PublicKey != NULL)
publicKey = new Key(base64PublicKey);
if (base64PrivateKey != NULL)
privateKey = new Key(base64PrivateKey);
if (base64SigningPrivateKey != NULL)
privateSigningKey = new Key(base64SigningPrivateKey);
if (base64SigningCertificate != NULL)
signingCertificate = new Certificate(base64SigningCertificate);
result = Generate(signatureSize, privateKey, publicKey, privateSigningKey, signingCertificate, certificateAuthorityUrl, expirationDate);
} catch (...)
{
if (privateKey) delete privateKey;
if (publicKey) delete publicKey;
if (privateSigningKey) delete privateSigningKey;
if (signingCertificate) delete signingCertificate;
throw;
}
if (privateKey) delete privateKey;
if (publicKey) delete publicKey;
if (privateSigningKey) delete privateSigningKey;
if (signingCertificate) delete signingCertificate;
return result;
}
static Certificate * Generate(int signatureSize, Key * privateKey, Key * publicKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
{
if (publicKey == NULL)
{
throw new LicensingException(STATUS_GENERIC_ERROR, "public key must be provided for the certificate");
}
Key * signingKey = NULL;
bool selfSigned;
if (signingPrivateKey == NULL && certificateAuthorityUrl == NULL)
{
selfSigned = true;
signingKey = privateKey;
}
else
{
selfSigned = false;
if (signingPrivateKey != NULL)
signingKey = signingPrivateKey;
// else use certificate authority url for signing
}
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
publicKey->Store(rawPublicKey, &rawPublicKeyLen);
// unsigned char rawPrivateKey[256]; int rawPrivateKeyLen = 256;
// signingKey->Store(rawPrivateKey, &rawPrivateKeyLen);
int certBitsLen = 4 * 8 + rawPublicKeyLen * 8;
BitStruct certBits(certBitsLen);
certBits.ResetFieldOffset();
certBits.AddField("Version", BitStruct::INTEGER, 4);
certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
certBits.AddField("PublicKey", BitStruct::RAW, rawPublicKeyLen * 8);
certBits.Set("Version", 0);
certBits.Set("IsSelfSigned", (selfSigned) ? 1 : 0);
certBits.Set("ReservedFlags", 0);
expirationDate = time(NULL);
struct tm * t = gmtime(&expirationDate);
certBits.Set("ExpirationDate", t->tm_year + 1900, t->tm_mon, t->tm_mday);
certBits.Set("PublicKeyLen", rawPublicKeyLen);
certBits.Set("PublicKey", rawPublicKey, rawPublicKeyLen);
unsigned char certSignature[256];
int sigSizeBytes = 256;
int sigSizeBits;
if (signingKey != NULL)
{
Signer signer;
signer.SetPrivateKey(signingKey);
signer.Sign(certBits.GetBuffer(), (certBitsLen + 7) >> 3, certSignature, &sigSizeBytes, &sigSizeBits);
}
else
{
#ifndef LICENSING_NO_NETWORKING
if (!certificateAuthorityUrl)
throw new LicensingException(STATUS_GENERIC_ERROR, "no means for certificate signing were provided");
string certificateAuthorityRequest(certificateAuthorityUrl);
certificateAuthorityRequest.append("?csr=");
BASE64 base64;
int len = 4096;
char buffer[4096];
auto base64csr = base64.encode((unsigned char *)certBits.GetBuffer(), (certBits.GetSize() + 7) >> 3, true);
string escapedBase64csr(base64csr.c_str());
StrReplace(escapedBase64csr, "+", "%2B");
StrReplace(escapedBase64csr, "/", "%2F");
StrReplace(escapedBase64csr, "=", "%3D");
certificateAuthorityRequest.append(escapedBase64csr);
const char * sdkLicenseKey = SDKRegistrationImpl::GetLicenseKey();
if (sdkLicenseKey && strlen(sdkLicenseKey) > 0)
{
certificateAuthorityRequest.append("&sdklicensekey=");
certificateAuthorityRequest.append(sdkLicenseKey);
}
UrlDownloadToString(certificateAuthorityRequest.c_str(), buffer, &len);
auto rawBuffer = base64.decode(buffer, len, &len);
if (rawBuffer.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 string");
auto certBuffer = rawBuffer;
unique_ptr<Certificate> issuedCert = std::make_unique<Certificate>(certBuffer, len);
sigSizeBits = issuedCert->m_certBits.GetInt("SignatureSizeBits");
sigSizeBytes = (sigSizeBits + 7) >> 3;
issuedCert->m_certBits.Get("Signature", certSignature, &sigSizeBytes);
memcpy(certBits.GetBuffer(), rawBuffer.data(), 4 + rawPublicKeyLen);
#else
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signing private key not provided");
#endif
}
int certBufLen = ((certBitsLen + 7) >> 3) // header + public key
+ 2 // signature size in bits
+ ((sigSizeBits + 7) >> 3); // signature
vector<unsigned char> certBuf;
certBuf.resize(certBufLen);
memcpy(certBuf.data(), certBits.GetBuffer(), (certBitsLen + 7) >> 3);
certBits.Attach(certBuf, certBufLen * 8);
certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
certBits.AddField("Signature", BitStruct::RAW, ((sigSizeBits + 7) >> 3) << 3);
certBits.Set("SignatureSizeBits", sigSizeBits);
certBits.Set("Signature", certSignature, (sigSizeBits + 7) >> 3);
Certificate * cert = new Certificate();
cert->m_certBits = std::move(certBits);
return cert;
}
static const char * Sign(const char * csr, const char * privateKey, const char * signingPrivateKey, const char * signingCertificate, const char * certificateAuthorityUrl, int expYear, int expMonth, int expDay)
{
Certificate * _csr = new Certificate(csr);
Key * _privateKey = (privateKey) ? new Key(privateKey) : NULL;
Key * _signingPrivateKey = (signingPrivateKey) ? new Key(signingPrivateKey) : NULL;
Certificate * _signingCertificate = (signingCertificate) ? new Certificate(signingCertificate) : NULL;
struct tm _expTm;
time_t _expTime = 0;
if (expYear >= 1900 && expMonth >= 1 && expMonth <= 12 && expDay >= 1 && expDay <= 31)
{
memset(&_expTm, 0, sizeof(_expTm));
_expTm.tm_year = expYear - 1900;
_expTm.tm_mon = expMonth - 1;
_expTm.tm_mday = expDay;
_expTime = mktime(&_expTm);
}
else
if (expYear != 0 || expMonth != 0 || expDay != 0)
throw new LicensingException(STATUS_GENERIC_ERROR, "Invalid certificate expiration date");
Certificate * _signedCert = Sign(_csr, _privateKey, _signingPrivateKey, _signingCertificate, certificateAuthorityUrl, 0);
if (_csr) delete _csr;
if (_privateKey) delete _privateKey;
if (_signingPrivateKey) delete _signingPrivateKey;
if (_signingCertificate) delete _signingCertificate;
const char * signedCert = _signedCert->ToString();
delete _signedCert;
return signedCert;
}
static Certificate * Sign(Certificate * csr, Key * privateKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
{
unsigned char buf[1024];
int len = 1024;
Key * publicKey;
csr->GetPublicKey(buf, &len);
publicKey = new Key(buf, len);
Certificate * cert = Certificate::Generate(0, privateKey, publicKey, signingPrivateKey, signingCertificate, certificateAuthorityUrl, expirationDate);
delete publicKey;
return cert;
}
private:
void Attach(vector<unsigned char>& buf, int len)
{
m_certBits.Attach(buf, len << 3);
m_certBits.ResetFieldOffset();
m_certBits.AddField("Version", BitStruct::INTEGER, 4);
m_certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
m_certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
m_certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
m_certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
m_certBits.AddField("PublicKey", BitStruct::RAW, m_certBits.GetInt("PublicKeyLen") * 8);
int signedPartLen = (m_certBits.GetCurrentFieldOffset() + 7) >> 3;
if (len <= signedPartLen)
return;
m_certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
int signatureBitLen = m_certBits.GetInt("SignatureSizeBits");
int signatureLen = (signatureBitLen + 7) >> 3;
int signatureOffset = m_certBits.GetCurrentFieldOffset() >> 3;
m_certBits.AddField("Signature", BitStruct::RAW, signatureLen << 3);
}
static ECC::KEY_TYPE GetKeyType(int sigSize)
{
if (sigSize < 76 || sigSize > 322)
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
ECC::KEY_TYPE keyType;
int keySize;
if (sigSize <= 108)
{
keyType = ECC::ECC_54;
keySize = 54;
} else
if (sigSize <= 146)
{
keyType = ECC::ECC_73;
keySize = 73;
} else
if (sigSize <= 158)
{
keyType = ECC::ECC_79;
keySize = 79;
} else
if (sigSize <= 182)
{
keyType = ECC::ECC_91;
keySize = 91;
} else
if (sigSize <= 200)
{
keyType = ECC::ECC_100;
keySize = 100;
} else
if (sigSize <= 240)
{
keyType = ECC::ECC_120;
keySize = 120;
} else
if (sigSize <= 262)
{
keyType = ECC::ECC_131;
keySize = 131;
} else
if (sigSize <= 282)
{
keyType = ECC::ECC_141;
keySize = 141;
} else
{
keyType = ECC::ECC_161;
keySize = 161;
}
return keyType;
}
static void StrReplace(string& str, const string& oldStr, const string& newStr)
{
size_t pos = 0;
while((pos = str.find(oldStr, pos)) != std::string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
BitStruct m_certBits;
};
#endif

View File

@@ -0,0 +1,69 @@
#include "precomp.h"
#include "crc32.h"
const unsigned int Crc32::crcTable[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
0x2D02EF8D
};
unsigned int Crc32::Compute(const unsigned char * buffer, int count)
{
unsigned int crc = 0xFFFFFFFF;
while (count--)
crc = (crc >> 8) ^ crcTable[(crc ^ *buffer++) & 0xFF];
return crc ^ 0xFFFFFFFF;
}

10
core/anslicensing/crc32.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
class Crc32
{
public:
static unsigned int Compute(const unsigned char * buffer, int count);
private:
static const unsigned int crcTable[256];
};

2616
core/anslicensing/cwrap.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,211 @@
#include "precomp.h"
#include <iostream>
#include <string>
#include "download.h"
#include "uniconv.h"
#include "except.h"
#ifdef _WIN32
#include <winhttp.h>
#include <malloc.h>
#else
#include <curl/curl.h>
#endif
#ifndef _WIN32
class CurlWriteBuffer
{
public:
CurlWriteBuffer(void * buffer, size_t size)
{
this->buffer = (char *)buffer;
this->size = size;
offset = 0;
}
int Append(void * buffer, size_t size)
{
if (this->offset + size > this->size)
size = this->size - offset;
if (size > 0)
{
memcpy(this->buffer + offset, buffer, size);
offset += size;
}
return size;
}
static size_t
Callback(void *contents, size_t size, size_t nmemb, void *userp)
{
return ((CurlWriteBuffer *)userp)->Append(contents, size * nmemb);
}
size_t offset;
size_t size;
char * buffer;
};
#endif
void UrlDownloadToString(const char * url, char * buffer, int * len)
{
#ifndef LICENSING_NO_NETWORKING
#ifdef _WIN32
HRESULT result = ERROR_SUCCESS;
URL_COMPONENTS urlComponents;
do {
ZeroMemory(&urlComponents, sizeof(urlComponents));
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.dwHostNameLength = (DWORD)-1;
urlComponents.dwUrlPathLength = (DWORD)-1;
auto urlw = s2w(url);
if (!WinHttpCrackUrl(urlw.c_str(), urlw.size(), 0L, &urlComponents))
{
result = GetLastError();
break;
}
wstring hostName(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> internet_ptr(WinHttpOpen(L"ANSCENTER Licensing SDK", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0L), WinHttpCloseHandle);
if (!internet_ptr)
{
result = GetLastError();
break;
}
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> connection_ptr(WinHttpConnect(internet_ptr.get(), hostName.c_str(), urlComponents.nPort, 0L), WinHttpCloseHandle);
if (connection_ptr == NULL)
{
result = GetLastError();
break;
}
wstring objectPath(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", objectPath.c_str(), NULL, NULL, NULL, requestFlags), WinHttpCloseHandle);
if (!request_ptr)
{
result = GetLastError();
break;
}
if (!WinHttpSendRequest(request_ptr.get(), NULL, 0L, NULL, 0, 0L, NULL))
{
result = GetLastError();
break;
}
if (!WinHttpReceiveResponse(request_ptr.get(), NULL))
{
result = GetLastError();
break;
}
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))
{
result = GetLastError();
break;
}
if (status != HTTP_STATUS_OK)
{
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))
{
result = GetLastError();
break;
}
result = ERROR_WINHTTP_INVALID_URL;
break;
}
if (status != HTTP_STATUS_OK)
{
result = GetLastError();
break;
}
DWORD offset = 0, count;
char lbuf[0x100];
do {
if (WinHttpReadData(request_ptr.get(), lbuf, 0x100, &count))
{
if (count == 0)
{
*len = offset;
break;
}
if (offset + count > *len)
{
result = ERROR_INSUFFICIENT_BUFFER;
break;
}
memcpy(buffer + offset, lbuf, count);
offset += count;
} else
{
result = GetLastError();
break;
}
} while (true);
} while (false);
if (result != ERROR_SUCCESS)
throw new LicensingException(result, "networking error while downloading url contents");
#else
CURL *curl;
CURLcode res;
if ((curl = curl_easy_init()) == NULL)
throw new LicensingException(STATUS_NET_ERROR, "cURL initalization failed");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
CurlWriteBuffer curlBuffer(buffer, *len);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteBuffer::Callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curlBuffer);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
{
curl_easy_cleanup(curl);
throw new LicensingException(STATUS_NET_ERROR, curl_easy_strerror(res));
}
*len = curlBuffer.offset;
curl_easy_cleanup(curl);
#endif
#else // !LICENSING_NO_NETWORKING
throw new LicensingException(STATUS_GENERIC_ERROR, "networking support not built in");
#endif
}

View File

@@ -0,0 +1,6 @@
#ifndef __DOWNLOAD_H
#define __DOWNLOAD_H
void UrlDownloadToString(const char * url, char * buffer, int * len);
#endif

1473
core/anslicensing/ec2m.cpp Normal file

File diff suppressed because it is too large Load Diff

256
core/anslicensing/ec2m.h Normal file
View File

@@ -0,0 +1,256 @@
// elliptic curves over GF(2^(L*K))
#pragma once
#define MAXL 16
#define MAXK 193
class field;
class field_element;
class curve;
class full_curve_parameter;
class small_field
{
friend class field;
#if MAXL > 16 // assumes that unsigned short is at least 16 bits
typedef unsigned lunit;
#else
#if MAXL > 8
typedef unsigned short lunit;
#else
typedef unsigned char lunit;
#endif
#endif
// construction
public:
small_field( unsigned L, unsigned root );
~small_field();
// methods
public:
unsigned * curve_order();
// properties
public:
lunit * const alog; // index range is [0..(BASE-2)]
lunit * const log; // index range is [1..(BASE-1)], but log[0] is set to (BASE-1)
const unsigned L, BASE, BASE_M1;
};
// elements are polynomials with coefficients in small_field
class field : public small_field
{
friend class curve;
friend class field_element;
friend class full_curve_parameter;
// construction
public:
field( class full_curve_parameter & a );
virtual unsigned rand( unsigned base );
// methods
private:
typedef unsigned poly[ 2 * MAXK ];
static void add( const poly a, const poly b, poly c );
static void copy ( const poly a, poly b );
static int equal( const poly a, const poly b );
void div( poly a, unsigned b );
void set_random( poly a );
int set_K( unsigned K, unsigned T );
void reduce( poly a );
void mul( const poly a, const poly b, poly c );
void square( const poly a, poly b );
void inverse( const poly a, poly b );
int trace( const poly a );
int slow_trace( const poly a );
void quad_solve( const poly a, poly b );
void sqrt( const poly a, poly b );
void addmul( poly a, unsigned alpha, unsigned j, const poly b );
friend field_element sqrt( const field_element x );
void unpack( const bigint & x, poly a );
bigint pack( const poly a );
// properties
private:
const unsigned M, K, T;
unsigned prng;
poly nzt; // element with non-zero trace
poly tm; // trace mask ( trace(x) is number of bits in x & tm )
};
class field_element
{
friend class field;
friend class curve;
friend class point;
friend field_element sqrt( const field_element x );
// construction
public:
field_element( const field_element & x );
field_element( field * F );
field_element();
// methods
public:
int operator == ( const field_element & x ) const;
int operator == ( unsigned x ) const;
field_element operator + ( const field_element & x ) const;
field_element operator * ( const field_element & x ) const;
field_element operator / ( const field_element & x ) const;
field_element & operator = ( const field_element & x );
// properties
private:
field * f;
field::poly v;
};
class point
{
friend class curve;
friend class ec_crypt;
friend point operator * ( const bigint & k, const point & P );
// construction
public:
point();
point( const point & P );
point( curve * C );
// methods
public:
point & operator = ( const point & P );
point operator + ( const point & P ) const;
point operator - ( const point & P ) const;
// properties
private:
curve * c;
field_element x, y;
};
struct curve_parameter
{
unsigned L;
unsigned K;
unsigned T;
unsigned root;
unsigned b;
unsigned nso;
unsigned ntf;
};
class full_curve_parameter : public curve_parameter
{
// construction
public:
full_curve_parameter( const curve_parameter & bp );
// properties
public:
bigint tm, p0, P0;
};
class curve : public field
{
friend class curve_factory;
friend class point;
friend point operator * ( const bigint & k, const point & P );
// construction
public:
curve( full_curve_parameter & a );
// methods
public:
point random_point();
static bigint pack( const point & P );
point unpack( const bigint & X );
static bigint to_vlong( const point & P );
// methods
private:
void add( const point & P, const point & Q, point & R );
void sub( const point & P, const point & Q, point & R );
void mul( const point & P, const bigint & x, point & Q );
int calc_y( point & R, unsigned ybit=0 );
static int MOV( unsigned B, const bigint & q, const bigint & r );
static bigint small_lucas( bigint P, bigint Z, unsigned ik );
static unsigned ybit( const field_element & x );
static field_element sq( const field_element & x );
// properties
public:
point PP; // point with prime order
bigint p; // prime order of P
// properties
private:
field_element b;
};
class curve_factory // Used for calculating curve_parameter but in practice
// use pre-calculated table ncdata.hpp or equivalent
{
// construction
public:
curve_factory( unsigned L ); // can take a long time
~curve_factory();
// methods
public:
int find( unsigned K, curve_parameter & result );
// properties
private:
unsigned L;
unsigned root;
unsigned so_min;
unsigned so_max;
unsigned *so_set;
bigint comp;
};
struct bigint_pair
{
bigint r;
bigint s;
};
class ECC_BASE : private curve
{
// construction
public:
ECC_BASE( full_curve_parameter & a );
~ECC_BASE();
// methods
public:
virtual unsigned rand( unsigned base );
bigint create_private_key();
bigint create_public_key( const bigint & private_key );
bigint encrypt( const bigint & public_key, bigint & message );
bigint decrypt( const bigint & private_key, const bigint & message );
bigint_pair schnorr_sign( const bigint & msg, const bigint & private_key, bigint (*hash)(const bigint &, const bigint &) = 0, unsigned hashbits = 1 );
bool schnorr_verify( const bigint & msg, const bigint_pair & sig, const bigint & public_key, bigint (*hash)(const bigint &, const bigint &) = 0, unsigned hashbits = 1 );
bigint_pair dsa_sign( const bigint & msg, const bigint & private_key, bigint (*hash)(const bigint &, const bigint &));
bool dsa_verify( const bigint & msg, const bigint_pair & sig, const bigint & public_key, bigint (*hash)(const bigint &, const bigint &));
// properties
public:
const unsigned bits; // number of bits in prime order
#ifdef WIN32
HCRYPTPROV m_cryptProv;
#endif
};

596
core/anslicensing/ecc.cpp Normal file
View File

@@ -0,0 +1,596 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "ecc.h"
#include "bigint.h"
#include "ec2m.h"
#include "sha1.h"
#include "except.h"
#include "base64.h"
#include "uniconv.h"
#ifndef _WIN32
#include <alloca.h>
#else
#include <malloc.h>
#endif
namespace ECC {
#if 0
void biPrint( bigint & data )
{
int n;
unsigned * u;
n = ( data.bits() + 31 ) / 32;
u = new unsigned[ n ];
data.store( u, n );
printf( "%d ", data.bits() );
for ( int i = n - 1; i >= 0; i-- )
{
printf( "%08X ", u[i] );
}
printf("\n");
delete [] u;
}
#endif
static const curve_parameter eccCurveTable[ 10 ] = { { 9, 7, 1, 17, 43, 48, 1},
{ 12, 7, 1, 83, 2049, 10, 1 },
{ 13, 7, 1, 27, 124, 52, 1},
{ 15, 7, 1, 3, 977, 110, 1},
{ 16, 7, 1, 45, 2902, 6, 1},
{ 10, 11, 2, 9, 139, 34, 1},
{ 12, 11, 2, 83, 2083, 66, 1},
{ 13, 11, 2, 27, 773, 48, 1},
{ 14, 11, 2, 43, 146, 40, 1},
{ 10, 17, 3, 9, 48, 28, 1} };
static void UintArrayToByteArray(unsigned * srcArray, int bitCount, unsigned char * dstArray)
{
int dstLength = ((int)bitCount + 7) >> 3;
int srcLength = (dstLength + 3) >> 2;
int i = 0;
int j = 0;
unsigned currentUint;
if (dstLength > 3)
{
while (i < dstLength - 3)
{
currentUint = (j < srcLength) ? srcArray[j] : 0;
dstArray[i + 3] = (unsigned char)(currentUint >> 24);
dstArray[i + 2] = (unsigned char)((currentUint >> 16) & 0xFF);
dstArray[i + 1] = (unsigned char)((currentUint >> 8) & 0xFF);
dstArray[i] = (unsigned char)(currentUint & 0xFF);
i += 4;
j += 1;
}
}
currentUint = (j < srcLength) ? srcArray[j] : 0;
if (i < dstLength) dstArray[i] = (unsigned char)(currentUint & 0xFF); i++;
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 8) & 0xFF); i++;
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 16) & 0xFF);
}
static void ByteArrayToUintArray(unsigned char * srcArray, int srcLength, unsigned * dstArray)
{
int roundedLen = (srcLength + sizeof(unsigned) - 1) / sizeof(unsigned);
int i = 0;
int j = 0;
while (i < roundedLen - 1)
{
dstArray[i] = (unsigned)(((unsigned)srcArray[j + 3] << 24) | ((unsigned)srcArray[j + 2] << 16) | ((unsigned)srcArray[j + 1] << 8) | (unsigned)srcArray[j]);
i += 1;
j += 4;
}
dstArray[roundedLen - 1] = 0;
if (j < srcLength) dstArray[roundedLen - 1] = (unsigned)(srcArray[j]); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 8); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 16); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 24);
}
class KeyImpl {
friend class Key;
friend class SignerImpl;
friend class VerifierImpl;
friend void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
private:
KeyImpl()
{
}
KeyImpl(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
{
Load(keyBuf, bufLen, keyType);
}
KeyImpl(const char * base64Key, KEY_TYPE keyType = ECC)
{
BASE64 base64;
int len;
auto buf = base64.decode(base64Key, strlen(base64Key), &len);
if (buf.empty())
throw new LicensingException(STATUS_INVALID_PARAM, "invalid base64 key");
Load(buf.data(), len, keyType);
}
void Load(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
{
if (keyType == ECC)
{
unsigned char * keyBytes = (unsigned char *)keyBuf;
if ((keyBytes[0] >> 5) != 0)
throw new LicensingException(STATUS_INVALID_PARAM, "unsupported key version");
if (keyBytes[1] + 2 != bufLen)
throw new LicensingException(STATUS_INVALID_PARAM, "invalid key size");
isPrivate = ((keyBytes[0] & 0x10) != 0);
SetKeyType((KEY_TYPE)(keyBytes[0] & 0x0F));
int roundedLen = sizeof(unsigned) * ((bufLen - 2 + sizeof(unsigned) - 1) / sizeof(unsigned));
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
if (!buf) return;
ByteArrayToUintArray(keyBytes + 2, bufLen - 2, buf);
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
free(buf);
} else
{
SetKeyType(keyType);
int roundedLen = sizeof(unsigned) * ((bufLen + sizeof(unsigned) - 1) / sizeof(unsigned));
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
if (!buf) return;
ByteArrayToUintArray((unsigned char *)keyBuf, bufLen, buf);
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
free(buf);
}
}
bool Store(void * buf, int * bufLen)
{
unsigned char * keyBytes = (unsigned char *)buf;
int numBits = m_key.bits();
int numBytes = (numBits + 7) >> 3;
if (*bufLen < 2 + numBytes)
return false;
keyBytes[0] &= 0x1F; // set first 3 bits to 0 - version 1
if (isPrivate) keyBytes[0] |= 0x10; else keyBytes[0] &= 0xEF; // the 4th bit is 1 if it's a private key
keyBytes[0] = (keyBytes[0] & 0xF0) | (((unsigned char)m_keyType) & 0x0F); // the next 4 bits from 1st byte are the key type
keyBytes[1] = numBytes; // the second byte specifies the key size
int numUints = (numBytes + sizeof(unsigned) - 1) / sizeof(unsigned);
unsigned * temp = (unsigned int *)_alloca(numUints * sizeof(unsigned));
m_key.store(temp, numUints);
UintArrayToByteArray(temp, numBits, keyBytes + 2);
*bufLen = numBytes + 2;
return true;
}
void SetKeyType(KEY_TYPE keyType)
{
m_keyType = keyType;
switch (keyType)
{
case ECC_54: m_keySize = 54;break;
case ECC_73: m_keySize = 73;break;
case ECC_79: m_keySize = 79;break;
case ECC_91: m_keySize = 91;break;
case ECC_97: m_keySize = 97;break;
case ECC_100: m_keySize = 100;break;
case ECC_120: m_keySize = 120;break;
case ECC_131: m_keySize = 131;break;
case ECC_141: m_keySize = 141;break;
case ECC_161: m_keySize = 161;break;
}
}
KEY_TYPE GetKeyType()
{
return m_keyType;
}
KEY_TYPE m_keyType;
int m_keySize;
bigint m_key;
bool isPrivate;
};
class SignerImpl {
public:
SignerImpl()
{
m_hashBits = 0; // thus select ECDSA as the signing algorithm
}
~SignerImpl()
{
}
static bigint Hash(const bigint & x, const bigint & p)
{
unsigned int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
unsigned int h[ 5 ];
x.store(a, n);
SHA1 sha;
#ifndef LICENSING_BIG_ENDIAN
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
#else
int nb = (x.bits() + 7) >> 3;
unsigned char * buf = (unsigned char *)_alloca(nb);
UintArrayToByteArray(a, x.bits(), buf);
sha.Update(buf, nb);
#endif
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)h);
#else
unsigned char bh[20];
sha.GetHash(bh);
ByteArrayToUintArray(bh, 20, h);
#endif
bigint r;
r.load( h, 5 );
return r % p;
}
void SetHashSize(int hashBits)
{
m_hashBits = hashBits;
}
void SetPrivateKey(const KeyImpl & privKey)
{
m_privateKey = privKey;
}
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
{
full_curve_parameter param(eccCurveTable[ m_privateKey.m_keyType ]);
ECC_BASE ecc(param);
bigint message;
bigint temp;
bigint_pair signature;
*sigLenBits = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? m_hashBits + m_privateKey.m_keySize : m_privateKey.m_keySize << 1;
*sigLen = (*sigLenBits + 7) >> 3;
unsigned * buf = (unsigned *)_alloca(msgLen + *sigLen + sizeof(unsigned) - 1);
// take care of endianess here, do not do just a memcpy()
memcpy(buf, msg, msgLen);
memset((char *)buf + msgLen, 0, sizeof(unsigned) - 1);
unsigned msgHash[5];
SHA1 sha;
sha.Update((unsigned char *)msg, msgLen);
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)msgHash);
#else
unsigned char msgHashBuf[20];
sha.GetHash(msgHashBuf);
ByteArrayToUintArray(msgHashBuf, 20, msgHash);
#endif
message.load(msgHash, 5);
signature = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? ecc.schnorr_sign(message, m_privateKey.m_key, Hash, m_hashBits) : ecc.dsa_sign(message, m_privateKey.m_key, Hash);
temp = (signature.r << m_privateKey.m_keySize); temp += signature.s;
unsigned int n = (unsigned)((*sigLen + sizeof(unsigned) - 1) / sizeof(unsigned));
temp.store(buf, n);
#ifndef LICENSING_BIG_ENDIAN
// take care of endianess here
memcpy(sigBuf, buf, *sigLen);
#else
UintArrayToByteArray(buf, *sigLenBits, (unsigned char *)sigBuf);
#endif
}
private:
KeyImpl m_privateKey;
int m_hashBits;
};
class VerifierImpl {
public:
VerifierImpl()
{
m_hashBits = 0;
}
~VerifierImpl()
{
}
static bigint Hash(const bigint & x, const bigint & p)
{
int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
unsigned int h[ 5 ];
x.store(a, n);
SHA1 sha;
#ifndef LICENSING_BIG_ENDIAN
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
#else
int nb = (x.bits() + 7) >> 3;
unsigned char * buf = (unsigned char *)_alloca(nb);
UintArrayToByteArray(a, x.bits(), buf);
sha.Update(buf, nb);
#endif
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)h);
#else
unsigned char bh[20];
sha.GetHash(bh);
ByteArrayToUintArray(bh, 20, h);
#endif
bigint r;
r.load( h, 5 );
return r % p;
}
void SetHashSize(int hashBits)
{
m_hashBits = hashBits;
}
void SetPublicKey(const KeyImpl & pubKey)
{
m_publicKey = pubKey;
}
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
{
full_curve_parameter param(eccCurveTable[ m_publicKey.m_keyType ]);
ECC_BASE ecc(param);
bigint message;
bigint_pair signature;
int msgBufLen = (msgLen + sizeof(unsigned) - 1) / sizeof(unsigned);
int sigBufLen = (sigLen + sizeof(unsigned) - 1) / sizeof(unsigned);
unsigned * msgBuf = (unsigned *)_alloca(msgBufLen * sizeof(unsigned));
unsigned * sigBuf = (unsigned *)_alloca(sigBufLen * sizeof(unsigned));
#ifndef LICENSING_BIG_ENDIAN
memset(msgBuf, 0, msgBufLen * sizeof(unsigned));
memcpy(msgBuf, msg, msgLen);
memset(sigBuf, 0, sigBufLen * sizeof(unsigned));
memcpy(sigBuf, sig, sigLen);
#else
ByteArrayToUintArray((unsigned char *)msg, msgLen, msgBuf);
ByteArrayToUintArray((unsigned char *)sig, sigLen, sigBuf);
#endif
unsigned int msgHash[5];
SHA1 sha;
sha.Update((unsigned char *)msg, msgLen);
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)msgHash);
#else
unsigned char byteHash[20];
sha.GetHash(byteHash);
ByteArrayToUintArray(byteHash, 20, msgHash);
#endif
message.load(msgHash, 5);
signature.r.load(sigBuf, sigBufLen);
signature.r >>= m_publicKey.m_keySize; signature.r &= (pow2((unsigned)(sigLenBits - m_publicKey.m_keySize)) - 1);
signature.s.load(sigBuf, sigBufLen);
signature.s &= (pow2(m_publicKey.m_keySize) - 1);
return (m_hashBits && m_hashBits < m_publicKey.m_keySize) ? ecc.schnorr_verify(message, signature, m_publicKey.m_key, Hash, m_hashBits) : ecc.dsa_verify(message, signature, m_publicKey.m_key, Hash);
}
private:
int m_hashBits;
KeyImpl m_publicKey;
};
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey)
{
full_curve_parameter param(eccCurveTable[ keyType ]);
ECC_BASE ecc(param);
Key * privateKey = new Key(),
* publicKey = new Key();
privateKey->m_Impl.m_key = ecc.create_private_key();
privateKey->m_Impl.SetKeyType(keyType);
privateKey->m_Impl.isPrivate = true;
publicKey->m_Impl.m_key = ecc.create_public_key(privateKey->m_Impl.m_key);
publicKey->m_Impl.SetKeyType(keyType);
*privKey = privateKey;
*pubKey = publicKey;
}
Key::Key():
m_Impl( *new KeyImpl() )
{
}
Key::Key(const void * keyBuf, int bufLen, KEY_TYPE keyType):
m_Impl( *new KeyImpl(keyBuf, bufLen, keyType) )
{
}
Key::Key(const char * base64Key, KEY_TYPE keyType):
m_Impl( *new KeyImpl(base64Key, keyType))
{
}
Key::~Key()
{
delete & m_Impl;
}
void Key::Load(const void * keyData, int keyLen, KEY_TYPE keyType)
{
m_Impl.Load(keyData, keyLen, keyType);
}
bool Key::Store(void * buf, int * bufLen) const
{
return m_Impl.Store(buf, bufLen);
}
const char * Key::ToString()
{
static string base64key;
int len = 2 + ((m_Impl.m_key.bits() + 7) >> 3);
unsigned char * buf = (unsigned char *)_alloca(len);
Store(buf, &len);
BASE64 base64;
auto base64Buf = base64.encode(buf, len, true);
if (base64Buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
base64key = base64Buf.c_str();
return base64key.c_str();
}
KEY_TYPE Key::GetKeyType()
{
return m_Impl.GetKeyType();
}
const Key & Key::operator = (const Key & key)
{
m_Impl = key.m_Impl;
return (const Key &)(*this);
}
Signer::Signer():
m_Impl(*new SignerImpl())
{
}
Signer::~Signer()
{
delete & m_Impl;
}
void Signer::SetHashSize(int hashBits)
{
m_Impl.SetHashSize(hashBits);
}
void Signer::SetPrivateKey(const Key * privKey)
{
m_Impl.SetPrivateKey(privKey->m_Impl);
}
void Signer::Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
{
m_Impl.Sign(msg, msgLen, sigBuf, sigLen, sigLenBits);
}
Verifier::Verifier():
m_Impl( *new VerifierImpl() )
{
}
Verifier::~Verifier()
{
delete & m_Impl;
}
void Verifier::SetHashSize(int hashBits)
{
m_Impl.SetHashSize(hashBits);
}
void Verifier::SetPublicKey(const Key * pubKey)
{
m_Impl.SetPublicKey(pubKey->m_Impl);
}
bool Verifier::Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
{
return m_Impl.Verify(msg, msgLen, sig, sigLen, sigLenBits);
}
}

80
core/anslicensing/ecc.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef __ECC_H
#define __ECC_H
namespace ECC {
enum KEY_TYPE {
ECC_54,
ECC_73,
ECC_79,
ECC_91,
ECC_97,
ECC_100,
ECC_120,
ECC_131,
ECC_141,
ECC_161,
ECC
};
class KeyImpl;
class Key {
public:
Key();
Key(const void * keyData, int keyLen, KEY_TYPE keyType = ECC);
Key(const char * base64Key, KEY_TYPE keyType = ECC);
~Key();
void Load(const void * keyData, int keyLen, KEY_TYPE keyType = ECC);
bool Store(void * buf, int * bufLen) const;
const char * ToString();
KEY_TYPE GetKeyType();
const Key & operator = (const Key & key);
public:
KeyImpl & m_Impl;
};
typedef unsigned (*HashFunction)(const void *, int, void *, unsigned *);
class SignerImpl;
class Signer
{
public:
Signer();
~Signer();
void SetPrivateKey(const Key * privKey);
void SetHashSize(int hashBits);
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int *sigLenInBits = (int *)0);
private:
SignerImpl & m_Impl;
};
class VerifierImpl;
class Verifier {
public:
Verifier();
~Verifier();
void SetPublicKey(const Key * pubKey);
void SetHashSize(int hashBits);
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenInBits = 0);
private:
VerifierImpl & m_Impl;
};
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
};
#endif

View File

@@ -0,0 +1,3 @@
#include "precomp.h"
#include "except.h"

View File

@@ -0,0 +1,31 @@
#ifndef __EXCEPT_H
#define __EXCEPT_H
#include <string>
#include "anslicensing.h"
using namespace std;
class LicensingException : public ANSCENTER::Licensing::Exception {
public:
LicensingException( int code, const char * message = NULL)
{
SetCode(code);
if (message)
SetMessage(message);
}
virtual ~LicensingException() {}
virtual int GetCode() { return m_code; }
virtual const char * GetExceptionMessage() { return m_message.c_str(); }
virtual void Destroy() { delete this; }
void SetCode(int code) { m_code = code; }
void SetMessage(const char * message) { m_message = message; }
protected:
int m_code;
string m_message;
};
#endif

View File

@@ -0,0 +1,207 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "anslicensing.h"
#include "template.h"
#include "base32.h"
#include "base64.h"
#include "sha1.h"
#include "except.h"
#include "bitstream.h"
#include "uniconv.h"
#include "generator.h"
namespace ANSCENTER {
namespace Licensing {
template<>
KeyGeneratorT<char>::KeyGeneratorT():
m_Impl( *new KeyGeneratorImpl())
{
}
template<>
KeyGeneratorT<wchar_t>::KeyGeneratorT():
m_Impl( *new KeyGeneratorImpl())
{
}
template<>
KeyGeneratorT<char>::KeyGeneratorT(const LicenseTemplateT<char> * templ):
m_Impl( *new KeyGeneratorImpl(&templ->m_Impl) )
{
}
template<>
KeyGeneratorT<wchar_t>::KeyGeneratorT(const LicenseTemplateT<wchar_t> * templ):
m_Impl( *new KeyGeneratorImpl(&templ->m_Impl) )
{
}
template<>
KeyGeneratorT<char>::~KeyGeneratorT()
{
delete & m_Impl;
}
template<>
KeyGeneratorT<wchar_t>::~KeyGeneratorT()
{
delete & m_Impl;
}
template<>
KeyGeneratorT<char> * KeyGeneratorT<char>::Create()
{
return new KeyGeneratorT<char>();
}
template<>
KeyGeneratorT<wchar_t> * KeyGeneratorT<wchar_t>::Create()
{
return new KeyGeneratorT<wchar_t>();
}
template<>
void KeyGeneratorT<char>::Destroy(KeyGeneratorT<char> * obj)
{
delete obj;
}
template<>
void KeyGeneratorT<wchar_t>::Destroy(KeyGeneratorT<wchar_t> * obj)
{
delete obj;
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, const void * buf, int len)
{
m_Impl.KeyGeneratorImpl::SetKeyData(fieldName, buf, len);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, const void * buf, int len)
{
m_Impl.KeyGeneratorImpl::SetKeyData(w2s(fieldName).c_str(), buf, len);
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, int data)
{
m_Impl.SetKeyData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, int data)
{
m_Impl.SetKeyData(w2s(fieldName).c_str(), data);
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, const char * data)
{
m_Impl.SetKeyData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, const wchar_t * data)
{
m_Impl.SetKeyData(w2s(fieldName).c_str(), w2s(data).c_str());
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, int year, int month, int day)
{
m_Impl.SetKeyData(fieldName, year, month, day);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, int year, int month, int day)
{
m_Impl.SetKeyData(w2s(fieldName).c_str(), year, month, day);
}
template<>
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(fieldName, buf, len);
}
template<>
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), buf, len);
}
template<>
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, int data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, int data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), data);
}
template<>
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, const char * data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const wchar_t * data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), w2s(data).c_str());
}
template<>
void KeyGeneratorT<char>::SetKeyTemplate(const LicenseTemplateT<char> & templ)
{
m_Impl.SetKeyTemplate(&templ.m_Impl);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> & templ)
{
m_Impl.SetKeyTemplate(&templ.m_Impl);
}
template<>
void KeyGeneratorT<char>::SetKeyTemplate(const LicenseTemplateT<char> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
const char * KeyGeneratorT<char>::GenerateKey()
{
return m_Impl.GenerateKey();
}
template<>
const wchar_t * KeyGeneratorT<wchar_t>::GenerateKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GenerateKey());
return wstr1.c_str();
}
};
};

View 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;
};

View File

@@ -0,0 +1,169 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include <list>
#include <string>
#ifdef _WIN32
#include "wmihelper.h"
#endif
#include "anslicensing.h"
#include "uniconv.h"
#include "except.h"
#include "hwid.h"
#include "base64.h"
class KeyHelperImpl {
friend class KeyHelperT<char>;
friend class KeyHelperT<wchar_t>;
private:
static const char * GetCurrentHardwareId()
{
return HardwareId::GetCurrentHardwareId();
}
static bool MatchCurrentHardwareId(const char * hwid)
{
return HardwareId::MatchCurrentHardwareId(hwid);
}
static bool DetectClockManipulation(int year, int month, int day)
{
#ifdef _WIN32
FILETIME thresholdTime;
SYSTEMTIME st;
TCHAR path[MAX_PATH];
ZeroMemory(&st, sizeof(st));
st.wYear = year;
st.wMonth = month;
st.wDay = day;
st.wHour = 23;
st.wMinute = 59;
st.wSecond = 59;
if (!SystemTimeToFileTime(&st, &thresholdTime))
return false;
if (GetTempPath(MAX_PATH, path) > 0)
{
_tcsncat_s<MAX_PATH>(path, "*.*", _TRUNCATE);
WIN32_FIND_DATA findData;
HANDLE findHandle = FindFirstFile(path, &findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
while (FindNextFile(findHandle, &findData))
{
if (CompareFileTime(&findData.ftLastWriteTime, &thresholdTime) > 0)
return true;
}
FindClose(findHandle);
}
}
WmiHelper wmi;
list<string> propList;
char dmtfTime[100];
char query[MAX_PATH];
_snprintf_s(query, MAX_PATH, _TRUNCATE, "SELECT EventIdentifier FROM Win32_NTLogEvent WHERE LogFile='system' AND TimeGenerated > '%04d%02d%02d000000.000000-000'", st.wYear, st.wMonth, st.wDay);
wmi.GetPropertyList(query, "EventIdentifier", &propList);
if (propList.size() > 0)
return true;
#endif
return false;
}
};
namespace ANSCENTER
{
namespace Licensing
{
template<>
const char * KeyHelperT<char>::GetCurrentHardwareId()
{
return KeyHelperImpl::GetCurrentHardwareId();
}
template<>
const wchar_t * KeyHelperT<wchar_t>::GetCurrentHardwareId()
{
static wstring wstr1;
wstr1 = s2w(KeyHelperImpl::GetCurrentHardwareId());
return wstr1.c_str();
}
template<>
bool KeyHelperT<char>::MatchCurrentHardwareId(const char * hwid)
{
return KeyHelperImpl::MatchCurrentHardwareId(hwid);
}
template<>
bool KeyHelperT<wchar_t>::MatchCurrentHardwareId(const wchar_t * hwid)
{
return KeyHelperImpl::MatchCurrentHardwareId(w2s(hwid).c_str());
}
template<>
bool KeyHelperT<char>::DetectClockManipulation(int thresholdYear, int thresholdMonth, int thresholdDay)
{
return KeyHelperImpl::DetectClockManipulation(thresholdYear, thresholdMonth, thresholdDay);
}
template<>
bool KeyHelperT<wchar_t>::DetectClockManipulation(int thresholdYear, int thresholdMonth, int thresholdDay)
{
return KeyHelperImpl::DetectClockManipulation(thresholdYear, thresholdMonth, thresholdDay);
}
};
};
namespace ANSCENTER
{
namespace Licensing
{
const char* ANSUtility::WString2String(const wchar_t * inputString) {
string result = w2s(inputString);
return result.c_str();
}
const wchar_t* ANSUtility::String2WString(const char* inputString) {
wstring result = s2w(inputString);
return result.c_str();
}
const char* ANSUtility::EncodeBase64Utility(unsigned char* buf, int len, bool padding) {
BASE64 base64;
string result= base64.encode(buf, len,padding);
return result.c_str();
}
const char* ANSUtility::DecodeBase64Utility(const char* input, int len, int* outlen) {
BASE64 base64;
vector<unsigned char> result = base64.decode(input, len, nullptr);
string str(result.begin(), result.end());
return str.c_str();
}
}
}

562
core/anslicensing/hwid.cpp Normal file
View File

@@ -0,0 +1,562 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#ifdef _WIN32
#include "wmihelper.h"
#else // !_WIN32
#if defined(__i386__) || defined(__amd64__)
#include <cpuid.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <net/if.h>
#ifdef __linux__
# include <sys/ioctl.h>
# include <netinet/in.h>
# include <unistd.h>
# include <string.h>
// Match Linux to FreeBSD
# define AF_LINK AF_PACKET
#else
# include <net/if_dl.h>
#endif
#endif
#include <list>
#include <string>
#include <functional>
#include <algorithm>
#include <cctype>
#include <stdio.h>
#include <set>
#include "bitstream2.h"
#include "bitstream3.h"
#include "base32.h"
#include "crc32.h"
#include "hwid.h"
#include "except.h"
#include "uniconv.h"
using namespace std;
string HardwareId::hardwareId;
#ifndef _WIN32
const sockaddr_in* castToIP4(const sockaddr* addr) {
if (addr == NULL) {
return NULL;
}
else if (addr->sa_family == AF_INET) {
// An IPv4 address
return reinterpret_cast<const sockaddr_in*>(addr);
}
else {
// Not an IPv4 address
return NULL;
}
}
void GetCPUIDPropertyList(std::list<std::string>* propList)
{
unsigned int level = 1, eax = 0, ebx, ecx, edx = 0;
#if defined(__i386__) || defined(__amd64__)
__get_cpuid(level, &eax, &ebx, &ecx, &edx);
#endif
char buf[17];
sprintf(buf, "%08X%08X", edx, eax);
propList->push_back(buf);
}
void GetMACPropertyList(std::list<std::string>* propList, int maxCount)
{
// Head of the interface address linked list
ifaddrs* ifap = NULL;
int r = getifaddrs(&ifap);
if (r != 0) {
return;
}
ifaddrs* current = ifap;
if (current == NULL) {
return;
}
while (current != NULL && maxCount > 0) {
const sockaddr_in* interfaceAddress = castToIP4(current->ifa_addr);
const sockaddr_in* broadcastAddress = castToIP4(current->ifa_dstaddr);
const sockaddr_in* subnetMask = castToIP4(current->ifa_netmask);
if ((current->ifa_addr != NULL) && (current->ifa_addr->sa_family == AF_LINK)) {
#ifdef __linux__
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strcpy(ifr.ifr_name, current->ifa_name);
ioctl(fd, SIOCGIFHWADDR, &ifr);
close(fd);
uint8_t* MAC = reinterpret_cast<uint8_t*>(ifr.ifr_hwaddr.sa_data);
#else // Posix/FreeBSD/Mac OS
sockaddr_dl* sdl = (struct sockaddr_dl*)current->ifa_addr;
uint8_t* MAC = reinterpret_cast<uint8_t*>(LLADDR(sdl));
#endif
if (MAC[0] != 0 || MAC[1] != 0 || MAC[2] != 0 || MAC[3] != 0 || MAC[4] != 0 || MAC[5] != 0)
{
char buf[18];
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
propList->push_back(buf);
maxCount--;
}
}
current = current->ifa_next;
}
freeifaddrs(ifap);
ifap = NULL;
}
void GetHDDPropertyList(std::list<std::string>* propList, int maxCount)
{
}
#endif
unsigned short HardwareId::HashString(const char* str)
{
unsigned int crc = Crc32::Compute((const unsigned char*)str, strlen(str));
return (unsigned short)(crc >> 16);
}
unsigned short HardwareId::HashInt(int val)
{
unsigned char buf[4] = { (unsigned char)(val >> 24), (unsigned char)(val >> 16), (unsigned char)(val >> 8), (unsigned char)(val & 0xFF) };
unsigned int crc = Crc32::Compute(buf, 4);
return (unsigned short)(crc >> 16);
}
// LOCALE-INDEPENDENT trim from start (in place)
static inline void ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != 0xA0;
}));
}
// LOCALE-INDEPENDENT trim from end (in place)
static inline void rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != 0xA0;
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string& s) {
ltrim(s);
rtrim(s);
}
// LOCALE-INDEPENDENT uppercase conversion
static inline void toUpperInvariant(std::string& s) {
for (char& c : s) {
if (c >= 'a' && c <= 'z') {
c = c - 32;
}
}
}
// Normalize hardware string for consistent hashing
static std::string NormalizeHardwareString(const std::string& input) {
std::string s = input;
// Trim all types of whitespace
trim(s);
// Remove all remaining whitespace characters
s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char c) {
return c <= 32 || c == 0xA0; // Remove control chars and non-breaking space
}), s.end());
// Locale-independent uppercase for ASCII
toUpperInvariant(s);
// Remove non-ASCII characters (Korean text, etc.)
s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char c) {
return c > 127;
}), s.end());
return s;
}
const char* HardwareId::GetCurrentHardwareId()
{
#ifdef _WIN32
WmiHelper wmi;
#endif
BitStream3 bits(125);
list<string> propList;
unsigned char version = 1;
unsigned short hash1, hash2, hash3, hash4;
unsigned short h0 = HashInt(0);
bits.Write(&version, 3);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT * FROM Win32_ComputerSystemProduct", "UUID", &propList);
hash1 = h0;
string s;
for (list<string>::iterator iter = propList.begin(); iter != propList.end(); iter++)
{
s = NormalizeHardwareString(*iter);
if ((s.length() > 1)
&& (s != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
&& (s != "00000000000000000000000000000000"))
{
hash1 = HashString(s.c_str());
}
}
#else
propList.push_back("4294967296");
#endif
bits.WriteUInt16(hash1);
// CPU IDs - get up to 4 for better resilience
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT ProcessorId FROM Win32_Processor", "ProcessorId", &propList, 4);
#else
GetCPUIDPropertyList(&propList);
#endif
// Normalize CPU IDs
for (auto& cpu : propList) {
cpu = NormalizeHardwareString(cpu);
}
hash1 = (propList.size() > 0) ? HashString(propList.front().c_str()) : h0;
hash2 = (propList.size() > 1) ? HashString(propList.back().c_str()) : h0;
bits.WriteUInt16(hash1);
bits.WriteUInt16(hash2);
// MAC Addresses - get MORE adapters and sort for consistency
propList.clear();
#ifdef _WIN32
// Try physical PCI adapters first
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%PCI%\"", "MACAddress", &propList, 6);
// Fallback to VMBUS for VMs
if (propList.size() == 0)
{
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%VMBUS%\"", "MACAddress", &propList, 6);
}
#else
GetMACPropertyList(&propList, 6);
#endif
// Normalize and sort MAC addresses for consistent ordering
for (auto& mac : propList) {
mac = NormalizeHardwareString(mac);
}
propList.sort();
// Store up to 4 MAC hashes
auto macIter = propList.begin();
hash1 = (propList.size() > 0 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
hash2 = (propList.size() > 1 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
hash3 = (propList.size() > 2 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
hash4 = (propList.size() > 3 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
bits.WriteUInt16(hash1);
bits.WriteUInt16(hash2);
bits.WriteUInt16(hash3);
bits.WriteUInt16(hash4);
// HDD Serial Numbers - get more drives and sort
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT SerialNumber FROM Win32_PhysicalMedia WHERE SerialNumber IS NOT NULL", "SerialNumber", &propList, 4);
#else
GetHDDPropertyList(&propList, 4);
#endif
// Normalize and sort HDD serials
for (auto& serial : propList) {
serial = NormalizeHardwareString(serial);
}
propList.sort();
auto hddIter = propList.begin();
hash1 = (propList.size() > 0 && hddIter != propList.end()) ? HashString((hddIter++)->c_str()) : h0;
hash2 = (propList.size() > 1 && hddIter != propList.end()) ? HashString((hddIter++)->c_str()) : h0;
bits.WriteUInt16(hash1);
bits.WriteUInt16(hash2);
unsigned char* rawHwid = bits.GetBuffer();
BASE32 base32;
auto encHwid = base32.encode(rawHwid, 16);
hardwareId = encHwid.c_str();
hardwareId.erase(hardwareId.length() - 1);
unsigned i;
unsigned insertPos;
// separate character groups
for (i = 0, insertPos = 5; i < 4; i++)
{
hardwareId.insert(insertPos, "-");
insertPos += 6;
}
return hardwareId.c_str();
}
bool HardwareId::MatchCurrentHardwareId(const char* hwid)
{
#ifdef _WIN32
WmiHelper wmi;
#endif
unsigned short h0 = HashInt(0);
string hardwareId((char*)hwid);
for (int i = 0, erasePos = 0; i < 4; i++)
{
erasePos += 5;
hardwareId.erase(erasePos, 1);
}
BASE32 base32;
int bufLen;
int padLen;
int len = base32.encode_pad_length(((int)hardwareId.length() * 5 + 7) >> 3, &padLen);
if (len > (int)hardwareId.length())
hardwareId.append(len - hardwareId.length(), 'A');
if (padLen)
hardwareId.append(padLen, '=');
auto buf = base32.decode(hardwareId.c_str(), hardwareId.length(), &bufLen);
BitStream3 bits;
bits.Attach(buf.data(), 125);
unsigned char version = 0;
bits.Read(&version, 3);
if ((version & 0x7) > 1)
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid hardware id version");
list<string> propList;
set<unsigned short> storedHashes; // Store all hashes from license
unsigned short hash1, hash2, hash3, hash4;
// Use a points-based matching system for resilience
int matchPoints = 0;
const int REQUIRED_POINTS = 2; // Need at least 2 components to match
// Read UUID hash
bits.ReadUInt16(&hash1);
if (version == 0)
{
// Legacy version 0 support (memory size based)
if (hash1 != h0)
{
unsigned long long memSize = 0;
#ifdef _WIN32
wmi.GetPropertyList("SELECT Capacity FROM Win32_PhysicalMemory", "Capacity", &propList);
#else
propList.push_back("4294967296");
#endif
if (propList.size() > 0)
{
for (list<string>::iterator iter = propList.begin(); iter != propList.end(); iter++)
{
memSize += _atoi64(iter->c_str());
}
memSize = memSize / (1024 * 1024);
if (hash1 != HashInt((int)memSize))
return false;
}
}
matchPoints += 2; // UUID/Memory match gives 2 points
}
else
{
// Version 1+ - UUID based
#ifdef _WIN32
wmi.GetPropertyList("SELECT * FROM Win32_ComputerSystemProduct", "UUID", &propList);
#endif
if (propList.size() > 0)
{
string s = NormalizeHardwareString(propList.front());
if ((s.length() > 1)
&& (s != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
&& (s != "00000000000000000000000000000000"))
{
if (hash1 != h0 && hash1 == HashString(s.c_str()))
{
matchPoints += 2; // UUID match is worth 2 points (most stable)
}
}
}
}
// Read CPU hashes
bits.ReadUInt16(&hash1);
bits.ReadUInt16(&hash2);
storedHashes.clear();
if (hash1 != h0) storedHashes.insert(hash1);
if (hash2 != h0) storedHashes.insert(hash2);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT ProcessorId FROM Win32_Processor", "ProcessorId", &propList, 4);
#else
GetCPUIDPropertyList(&propList);
#endif
// Check if ANY current CPU matches stored hashes
int cpuMatches = 0;
for (auto& cpu : propList) {
string s = NormalizeHardwareString(cpu);
unsigned short currentHash = HashString(s.c_str());
if (storedHashes.find(currentHash) != storedHashes.end()) {
cpuMatches++;
}
}
if (cpuMatches > 0) {
matchPoints += 1; // CPU match is worth 1 point
}
// Read MAC hashes (now 4 hashes for better resilience)
bits.ReadUInt16(&hash1);
bits.ReadUInt16(&hash2);
bits.ReadUInt16(&hash3);
bits.ReadUInt16(&hash4);
storedHashes.clear();
if (hash1 != h0) storedHashes.insert(hash1);
if (hash2 != h0) storedHashes.insert(hash2);
if (hash3 != h0) storedHashes.insert(hash3);
if (hash4 != h0) storedHashes.insert(hash4);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%PCI%\"", "MACAddress", &propList, 10);
if (propList.size() == 0)
{
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%VMBUS%\"", "MACAddress", &propList, 10);
}
#else
GetMACPropertyList(&propList, 10);
#endif
// Check if ANY current MAC address matches stored hashes
int macMatches = 0;
for (auto& mac : propList) {
string s = NormalizeHardwareString(mac);
unsigned short currentHash = HashString(s.c_str());
if (storedHashes.find(currentHash) != storedHashes.end()) {
macMatches++;
}
}
if (macMatches > 0) {
matchPoints += 1; // MAC match is worth 1 point
}
// Read HDD hashes
bits.ReadUInt16(&hash1);
bits.ReadUInt16(&hash2);
storedHashes.clear();
if (hash1 != h0) storedHashes.insert(hash1);
if (hash2 != h0) storedHashes.insert(hash2);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT SerialNumber FROM Win32_PhysicalMedia WHERE SerialNumber IS NOT NULL", "SerialNumber", &propList, 10);
#else
GetHDDPropertyList(&propList, 10);
#endif
// Check if ANY current HDD serial matches stored hashes
int hddMatches = 0;
for (auto& serial : propList) {
string s = NormalizeHardwareString(serial);
unsigned short currentHash = HashString(s.c_str());
if (storedHashes.find(currentHash) != storedHashes.end()) {
hddMatches++;
}
}
if (hddMatches > 0) {
matchPoints += 1; // HDD match is worth 1 point
}
// Validation passes if we have enough matching points
// Typical valid scenarios:
// - UUID (2) + CPU (1) = 3 points ✓
// - UUID (2) + MAC (1) = 3 points ✓
// - UUID (2) + HDD (1) = 3 points ✓
// - CPU (1) + MAC (1) + HDD (1) = 3 points ✓ (if UUID changed but hardware same)
return matchPoints >= REQUIRED_POINTS;
}

16
core/anslicensing/hwid.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __HARDWARE_ID_H
#define __HARDWARE_ID_H
class HardwareId
{
public:
static const char * GetCurrentHardwareId();
static bool MatchCurrentHardwareId(const char * hwid);
private:
static unsigned short HashString(const char * str);
static unsigned short HashInt(int val);
static string hardwareId;
};
#endif

View File

@@ -0,0 +1,360 @@
#include "precomp.h"
#include "anslicensing.h"
#include "license.h"
#include "uniconv.h"
#include "except.h"
#include "tinyxml2.h"
#include "picojson.h"
#include "base64.h"
void LicenseImpl::LoadXml(const char * xmlTemplate)
{
tinyxml2::XMLDocument xml;
tinyxml2::XMLElement * rootElement, *element;
const char * attr;
int version = 1;
if (xml.Parse(xmlTemplate) != tinyxml2::XML_NO_ERROR)
throw new LicensingException(STATUS_INVALID_XML);
if ((element = rootElement = xml.FirstChildElement()) == NULL)
throw new LicensingException(STATUS_INVALID_XML);
if ((attr = element->Attribute("version")) != NULL)
version = atoi(attr);
if (version > 1)
throw new LicensingException(STATUS_GENERIC_ERROR, "unsupported license version");
bool isLease = false;
if ((attr = element->Attribute("isLease")) != NULL)
isLease = (_stricmp(attr, "1") == 0 || _stricmp(attr, "true") == 0);
m_isLease = isLease;
if ((element = rootElement->FirstChildElement("LicenseKey")) == NULL)
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
m_licenseKey = element->GetText();
if ((element = rootElement->FirstChildElement("LicenseKeyValidationData")) != NULL)
{
BASE64 base64;
m_licenseKeyValidationData = base64.decode(element->GetText(), strlen(element->GetText()), nullptr);
if (!m_licenseKeyValidationData.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid BASE64 string");
}
if ((element = rootElement->FirstChildElement("ActivationKey")) == NULL)
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
m_activationKey = element->GetText();
if ((element = rootElement->FirstChildElement("HardwareId")) == NULL)
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
m_hardwareId = element->GetText();
}
#ifndef MAX_XML_BUFFER_SIZE
#define MAX_XML_BUFFER_SIZE 4096
#endif
const char * LicenseImpl::SaveXml()
{
BASE64 base64;
char buffer[MAX_XML_BUFFER_SIZE];
m_xmlLicense.resize(0);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "<License version=\"%d\" isLease=\"%d\">\n", m_version, (m_isLease) ? 1 : 0); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<LicenseKey>%s</LicenseKey>\n", m_licenseKey.c_str()); m_xmlLicense.append(buffer);
if (!m_licenseKeyValidationData.empty())
{
BASE64 base64;
auto enc = base64.encode(m_licenseKeyValidationData.data(), m_licenseKeyValidationData.size(), true);
if (!enc.empty())
{
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<LicenseKeyValidationData>"); m_xmlLicense.append(buffer);
m_xmlLicense.append(enc);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "</LicenseKeyValidationData>\n"); m_xmlLicense.append(buffer);
}
else
throw new LicensingException(STATUS_OUT_OF_MEMORY);
}
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<ActivationKey>%s</ActivationKey>\n", m_activationKey.c_str()); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<HardwareId>%s</HardwareId>\n", m_hardwareId.c_str()); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "</License>"); m_xmlLicense.append(buffer);
return m_xmlLicense.c_str();
}
void LicenseImpl::LoadJson(const char * jsonLicense)
{
picojson::value json;
auto err = picojson::parse(json, jsonLicense);
if (!err.empty())
throw new LicensingException(STATUS_INVALID_PARAM);
picojson::object license = json.get<picojson::object>();
auto version = license["version"].get<double>();
if (version > 1)
throw new LicensingException(STATUS_GENERIC_ERROR, "unsupported license version");
m_isLease = license.count("is_lease") ? license["is_lease"].get<bool>() : false;
m_licenseKey = license["license_key"].get<string>();
if (license.count("license_key_validation_data"))
{
BASE64 base64;
m_licenseKeyValidationData = base64.decode(license["license_key_validation_data"].get<string>().c_str());
}
m_activationKey = license["activation_key"].get<string>();
m_hardwareId = license["hardware_id"].get<string>();
}
#ifndef MAX_JSON_BUFFER_SIZE
#define MAX_JSON_BUFFER_SIZE 4096
#endif
const char * LicenseImpl::SaveJson()
{
picojson::object license;
BASE64 base64;
license["version"] = picojson::value((double)1);
license["is_lease"] = picojson::value(m_isLease);
license["license_key"] = picojson::value(m_licenseKey);
license["hardware_id"] = picojson::value(m_hardwareId);
license["activation_key"] = picojson::value(m_activationKey);
if (!m_licenseKeyValidationData.empty())
license["license_key_validation_data"] = picojson::value(base64.encode(m_licenseKeyValidationData.data(), m_licenseKeyValidationData.size(), true));
m_jsonLicense = picojson::value(license).serialize(true);
return m_jsonLicense.c_str();
}
namespace ANSCENTER {
namespace Licensing {
template<>
LicenseT<char>::LicenseT() :
m_Impl(*new LicenseImpl())
{
}
template<>
LicenseT<wchar_t>::LicenseT() :
m_Impl(*new LicenseImpl())
{
}
template<>
LicenseT<char>::~LicenseT()
{
delete& m_Impl;
}
template<>
LicenseT<wchar_t>::~LicenseT()
{
delete& m_Impl;
}
template<>
const char* LicenseT<char>::SaveXml()
{
return m_Impl.SaveXml();
}
template<>
const char* LicenseT<wchar_t>::SaveXml()
{
return m_Impl.SaveXml();
}
template<>
void LicenseT<char>::LoadXml(const char* xml)
{
m_Impl.LoadXml(xml);
}
template<>
void LicenseT<wchar_t>::LoadXml(const char* xml)
{
m_Impl.LoadXml(xml);
}
template<>
const char* LicenseT<char>::SaveJson()
{
return m_Impl.SaveJson();
}
template<>
const char* LicenseT<wchar_t>::SaveJson()
{
return m_Impl.SaveJson();
}
template<>
void LicenseT<char>::LoadJson(const char* xml)
{
m_Impl.LoadJson(xml);
}
template<>
void LicenseT<wchar_t>::LoadJson(const char* xml)
{
m_Impl.LoadJson(xml);
}
template<>
void LicenseT<char>::SetLicenseKey(const char* licenseKey)
{
m_Impl.SetLicenseKey(licenseKey);
}
template<>
void LicenseT<wchar_t>::SetLicenseKey(const wchar_t* licenseKey)
{
m_Impl.SetLicenseKey(w2s(licenseKey).c_str());
}
template<>
void LicenseT<char>::SetLicenseKeyValidationData(void* validationData, int validationDataLen)
{
m_Impl.SetLicenseKeyValidationData((const unsigned char*)validationData, validationDataLen);
}
template<>
void LicenseT<wchar_t>::SetLicenseKeyValidationData(void* validationData, int validationDataLen)
{
m_Impl.SetLicenseKeyValidationData((const unsigned char*)validationData, validationDataLen);
}
template<>
void LicenseT<char>::GetLicenseKeyValidationData(void** buf, int* len)
{
m_Impl.GetLicenseKeyValidationData((const void**)buf, len);
}
template<>
void LicenseT<wchar_t>::GetLicenseKeyValidationData(void** buf, int* len)
{
m_Impl.GetLicenseKeyValidationData((const void**)buf, len);
}
template<>
const char* LicenseT<char>::GetLicenseKey()
{
return m_Impl.GetLicenseKey();
}
template<>
const wchar_t* LicenseT<wchar_t>::GetLicenseKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetLicenseKey());
return wstr1.c_str();
}
template<>
void LicenseT<char>::SetActivationKey(const char* activationKey)
{
m_Impl.SetActivationKey(activationKey);
}
template<>
void LicenseT<wchar_t>::SetActivationKey(const wchar_t* activationKey)
{
m_Impl.SetActivationKey(w2s(activationKey).c_str());
}
template<>
const char* LicenseT<char>::GetActivationKey()
{
return m_Impl.GetActivationKey();
}
template<>
const wchar_t* LicenseT<wchar_t>::GetActivationKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetActivationKey());
return wstr1.c_str();
}
template<>
void LicenseT<char>::SetHardwareId(const char* hardwareId)
{
m_Impl.SetHardwareId(hardwareId);
}
template<>
void LicenseT<wchar_t>::SetHardwareId(const wchar_t* hardwareId)
{
m_Impl.SetHardwareId(w2s(hardwareId).c_str());
}
template<>
const char* LicenseT<char>::GetHardwareId()
{
return m_Impl.GetHardwareId();
}
template<>
const wchar_t* LicenseT<wchar_t>::GetHardwareId()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetHardwareId());
return wstr1.c_str();
}
template<>
void LicenseT<char>::SetLease(bool isLease)
{
m_Impl.SetLease(isLease);
}
template<>
void LicenseT<wchar_t>::SetLease(bool isLease)
{
m_Impl.SetLease(isLease);
}
template<>
bool LicenseT<char>::IsLease()
{
return m_Impl.IsLease();
}
template<>
bool LicenseT<wchar_t>::IsLease()
{
return m_Impl.IsLease();
}
};
}

104
core/anslicensing/license.h Normal file
View File

@@ -0,0 +1,104 @@
#pragma once
#include <vector>
#include "except.h"
using namespace std;
class LicenseImpl {
friend class LicenseValidationResultT<char>;
friend class LicenseValidationResultT<wchar_t>;
public:
LicenseImpl():
m_isLease(false)
{
}
void CopyFrom(const LicenseImpl * src)
{
m_activationKey = src->m_activationKey;
m_hardwareId = src->m_hardwareId;
m_isLease = src->m_isLease;
m_licenseKey = src->m_licenseKey;
m_xmlLicense = src->m_xmlLicense;
SetLicenseKeyValidationData(src->m_licenseKeyValidationData.data(), src->m_licenseKeyValidationData.size());
}
void LoadXml(const char * xml);
const char * SaveXml();
void LoadJson(const char * json);
const char * SaveJson();
const char * GetLicenseKey() const
{
return m_licenseKey.c_str();
}
void SetLicenseKey(const char * licenseKey)
{
m_licenseKey = licenseKey;
}
void GetLicenseKeyValidationData(const void ** buf, int * len) const
{
*buf = m_licenseKeyValidationData.data();
*len = m_licenseKeyValidationData.size();
}
void SetLicenseKeyValidationData(const void* buf, int len)
{
if (buf && len > 0)
{
m_licenseKeyValidationData.resize(len);
memcpy(m_licenseKeyValidationData.data(), buf, len);
}
else
{
m_licenseKeyValidationData.clear();
}
}
const char * GetActivationKey() const
{
return m_activationKey.c_str();
}
void SetActivationKey(const char * activationKey)
{
m_activationKey = activationKey;
}
const char * GetHardwareId() const
{
return m_hardwareId.c_str();
}
void SetHardwareId(const char * hardwareId)
{
m_hardwareId = hardwareId;
}
bool IsLease() const
{
return m_isLease;
}
void SetLease(bool isLease)
{
m_isLease = isLease;
}
private:
string m_licenseKey;
string m_activationKey;
string m_hardwareId;
vector<unsigned char> m_licenseKeyValidationData;
bool m_isLease;
string m_xmlLicense;
string m_jsonLicense;
static const int m_version = 1;
};

View File

@@ -0,0 +1,108 @@
#include "precomp.h"
#include "anslicensing.h"
#include "license.h"
#include "uniconv.h"
#include "licensevalidationargs.h"
namespace ANSCENTER {
namespace Licensing {
template<>
LicenseValidationArgsT<char>::LicenseValidationArgsT():
m_Impl(*new LicenseValidationArgsImpl())
{
}
template<>
LicenseValidationArgsT<wchar_t>::LicenseValidationArgsT() :
m_Impl(*new LicenseValidationArgsImpl())
{
}
template<>
LicenseValidationArgsT<char>::~LicenseValidationArgsT()
{
delete & m_Impl;
}
template<>
LicenseValidationArgsT<wchar_t>::~LicenseValidationArgsT()
{
delete & m_Impl;
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKey(const char * licenseKey)
{
m_Impl.SetLicenseKey(licenseKey);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKey(const wchar_t * licenseKey)
{
m_Impl.SetLicenseKey(w2s(licenseKey).c_str());
}
template<>
void LicenseValidationArgsT<char>::SetLicense(const LicenseT<char> * license)
{
m_Impl.SetLicense(&license->m_Impl);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicense(const LicenseT<wchar_t> * license)
{
m_Impl.SetLicense(&license->m_Impl);
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, int fieldValue)
{
m_Impl.SetLicenseKeyValidationData(fieldName, fieldValue);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, int fieldValue)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), fieldValue);
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, const char * fieldValue)
{
m_Impl.SetLicenseKeyValidationData(fieldName, fieldValue);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, const wchar_t * fieldValue)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), w2s(fieldValue).c_str());
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, int year, int month, int day)
{
m_Impl.SetLicenseKeyValidationData(fieldName, year, month, day);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, int year, int month, int day)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), year, month, day);
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, void * data, int len)
{
m_Impl.SetLicenseKeyValidationData(fieldName, data, len);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, void * data, int len)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), data, len);
}
};
};

View File

@@ -0,0 +1,109 @@
#pragma once
#include "license.h"
#include <string>
#include <vector>
#include <list>
using namespace std;
struct NameValuePair {
public:
NameValuePair(const char* _name, const char* _value):
name(_name),
stringValue(_value)
{
}
NameValuePair(const char* _name, int _value):
name(_name),
intValue(_value)
{
}
NameValuePair(const char* _name, int _year, int _month, int _day):
name(_name),
dateValue { _year, _month, _day }
{
}
NameValuePair(const char* _name, const unsigned char* _value, int _len):
name(_name),
binaryValue(_value, _value + _len)
{
}
string name;
int intValue;
string stringValue;
struct {
int year, month, day;
} dateValue;
vector<unsigned char> binaryValue;
};
class LicenseValidationArgsImpl
{
friend LicensingClient;
public:
LicenseValidationArgsImpl():
m_license(nullptr)
{
}
void SetLicense(LicenseImpl * license)
{
m_license = license;
}
const LicenseImpl * GetLicense()
{
return m_license;
}
void SetLicenseKey(const char * licenseKey, int validationDataSize = 0)
{
m_licenseKey = licenseKey;
}
void SetLicenseKeyValidationData(const char * fieldName, const char * fieldValue)
{
m_licenseKeyValidationData.emplace_back(fieldName, fieldValue);
}
void SetLicenseKeyValidationData(const char * fieldName, int fieldValue)
{
m_licenseKeyValidationData.emplace_back(fieldName, fieldValue);
}
void SetLicenseKeyValidationData(const char * fieldName, int year, int month, int day)
{
m_licenseKeyValidationData.emplace_back(fieldName, year, month, day);
}
void SetLicenseKeyValidationData(const char * fieldName, void * data, int len)
{
m_licenseKeyValidationData.emplace_back(fieldName, (unsigned char*)data, len);
}
const char * GetLicenseKey()
{
return m_licenseKey.c_str();
}
public:
const LicenseImpl* m_license;
int m_validationDataSize;
string m_licenseKey;
list<NameValuePair> m_licenseKeyValidationData;
};

View File

@@ -0,0 +1,111 @@
#include "precomp.h"
#include "anslicensing.h"
#include "uniconv.h"
#include "licensevalidationresult.h"
namespace ANSCENTER {
namespace Licensing {
template<>
LicenseValidationResultT<char>::LicenseValidationResultT() :
m_Impl(*new LicenseValidationResultImpl())
{
}
template<>
LicenseValidationResultT<wchar_t>::LicenseValidationResultT() :
m_Impl(*new LicenseValidationResultImpl())
{
}
template<>
LicenseValidationResultT<char>::~LicenseValidationResultT()
{
delete & m_Impl;
}
template<>
LicenseValidationResultT<wchar_t>::~LicenseValidationResultT()
{
delete & m_Impl;
}
template<>
LicenseT<char> * LicenseValidationResultT<char>::GetLicense()
{
static LicenseT<char> result;
LicenseImpl * resultImpl = m_Impl.GetLicense();
if (!resultImpl) return NULL;
result.m_Impl.CopyFrom(resultImpl);
return &result;
}
template<>
LicenseT<wchar_t> * LicenseValidationResultT<wchar_t>::GetLicense()
{
static LicenseT<wchar_t> result;
LicenseImpl * resultImpl = m_Impl.GetLicense();
if (!resultImpl) return NULL;
result.m_Impl.CopyFrom(resultImpl);
return &result;
}
template<>
bool LicenseValidationResultT<char>::IsLicenseExpired()
{
return m_Impl.IsLicenseExpired();
}
template<>
bool LicenseValidationResultT<wchar_t>::IsLicenseExpired()
{
return m_Impl.IsLicenseExpired();
}
template<>
bool LicenseValidationResultT<char>::IsPaymentRequired()
{
return m_Impl.IsPaymentRequired();
}
template<>
bool LicenseValidationResultT<wchar_t>::IsPaymentRequired()
{
return m_Impl.IsPaymentRequired();
}
template<>
int LicenseValidationResultT<char>::GetLicenseValidityDays()
{
return m_Impl.GetLicenseValidityDays();
}
template<>
int LicenseValidationResultT<wchar_t>::GetLicenseValidityDays()
{
return m_Impl.GetLicenseValidityDays();
}
template<>
void LicenseValidationResultT<char>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
template<>
void LicenseValidationResultT<wchar_t>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
};
};

View File

@@ -0,0 +1,118 @@
#ifndef __LICENSEVALIDATIONRESULT_H
#define __LICENSEVALIDATIONRESULT_H
#include <memory>
#include "license.h"
using namespace std;
class LicensingClientImpl;
class LicenseValidationResultImpl
{
//friend class LicensingClientT<char>;
//friend class LicensingClientT<wchar_t>;
friend class LicensingClientImpl;
friend class LicenseValidationResultT<char>;
friend class LicenseValidationResultT<wchar_t>;
public:
LicenseValidationResultImpl()
{
m_isLicenseExpired = false;
m_isPaymentRequired = false;
m_licenseValidityDays = 0;
m_licenseExpirationYear = m_licenseExpirationMonth = m_licenseExpirationDay = 0;
}
~LicenseValidationResultImpl()
{
}
void MoveFrom(LicenseValidationResultImpl& src)
{
m_isLicenseExpired = src.m_isLicenseExpired;
m_isLicenseValid = src.m_isLicenseValid;
m_isPaymentRequired = src.m_isPaymentRequired;
m_license = std::move(src.m_license);
m_licenseValidityDays = src.m_licenseValidityDays;
m_licenseExpirationDay = src.m_licenseExpirationDay;
m_licenseExpirationMonth = src.m_licenseExpirationMonth;
m_licenseExpirationYear = src.m_licenseExpirationYear;
}
LicenseImpl * GetLicense()
{
return m_license.get();
}
void SetLicense(LicenseImpl * lic)
{
m_license.reset(lic);
}
bool IsLicenseValid()
{
return m_isLicenseValid;
}
void SetLicenseValid(bool isValid)
{
m_isLicenseValid = isValid;
}
bool IsLicenseExpired()
{
return m_isLicenseExpired;
}
void SetLicenseExpired(bool licenseExpired)
{
m_isLicenseExpired = licenseExpired;
}
bool IsPaymentRequired()
{
return m_isPaymentRequired;
}
void SetPaymentRequired(bool paymentRequired)
{
m_isPaymentRequired = paymentRequired;
}
int GetLicenseValidityDays()
{
return m_licenseValidityDays;
}
void SetLicenseValidityDays(int days)
{
m_licenseValidityDays = days;
}
void GetLicenseExpirationDate(int * year, int * month, int * day)
{
*year = m_licenseExpirationYear;
*month = m_licenseExpirationMonth;
*day = m_licenseExpirationDay;
}
void SetLicenseExpirationDate(int year, int month, int day)
{
m_licenseExpirationYear = year;
m_licenseExpirationMonth = month;
m_licenseExpirationDay = day;
}
private:
bool m_isLicenseValid;
bool m_isLicenseExpired;
bool m_isPaymentRequired;
int m_licenseValidityDays;
int m_licenseExpirationYear, m_licenseExpirationMonth, m_licenseExpirationDay;
unique_ptr<LicenseImpl> m_license;
};
#endif

View File

@@ -0,0 +1,289 @@
#include "precomp.h"
#include <memory>
#include "licensingclient.h"
#include "licensevalidationargs.h"
#include "licensevalidationresult.h"
using namespace std;
namespace ANSCENTER {
namespace Licensing {
template<>
LicensingClientT<wchar_t>::LicensingClientT():
m_Impl(*(new LicensingClientImpl(this, true)))
{
}
template<>
LicensingClientT<char>::LicensingClientT():
m_Impl(*(new LicensingClientImpl(this, false)))
{
}
template<>
LicensingClientT<char>::~LicensingClientT()
{
delete & m_Impl;
}
template<>
LicensingClientT<wchar_t>::~LicensingClientT()
{
delete & m_Impl;
}
template<>
void LicensingClientT<char>::SetLicenseTemplate(LicenseTemplateT<char> * tmpl)
{
m_Impl.SetLicenseTemplate(&tmpl->m_Impl);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseTemplate(LicenseTemplateT<wchar_t> * tmpl)
{
m_Impl.SetLicenseTemplate(&tmpl->m_Impl);
}
template<>
void LicensingClientT<char>::SetLicenseKey(const char * key)
{
m_Impl.SetLicenseKey(key);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseKey(const wchar_t * key)
{
m_Impl.SetLicenseKey(w2s(key).c_str());
}
template<>
void LicensingClientT<char>::SetActivationKey(const char * key)
{
m_Impl.SetActivationKey(key);
}
template<>
void LicensingClientT<wchar_t>::SetActivationKey(const wchar_t * key)
{
m_Impl.SetActivationKey(w2s(key).c_str());
}
template<>
const char * LicensingClientT<char>::GetActivationKey()
{
return m_Impl.GetActivationKey();
}
template<>
const wchar_t * LicensingClientT<wchar_t>::GetActivationKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetActivationKey());
return wstr1.c_str();
}
template<>
void LicensingClientT<char>::SetHardwareId(const char * hwid)
{
m_Impl.SetHardwareId(hwid);
}
template<>
void LicensingClientT<wchar_t>::SetHardwareId(const wchar_t * hwid)
{
m_Impl.SetHardwareId(w2s(hwid).c_str());
}
template<>
const char * LicensingClientT<char>::GetHardwareId()
{
return m_Impl.GetHardwareId();
}
template<>
const wchar_t * LicensingClientT<wchar_t>::GetHardwareId()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetHardwareId());
return wstr1.c_str();
}
template<>
const wchar_t * LicensingClientT<wchar_t>::GetCurrentHardwareId()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetCurrentHardwareId());
return wstr1.c_str();
}
template<>
const char * LicensingClientT<char>::GetCurrentHardwareId()
{
return m_Impl.GetCurrentHardwareId();
}
template<>
bool LicensingClientT<char>::MatchCurrentHardwareId(const char * hwid)
{
return m_Impl.MatchCurrentHardwareId(hwid);
}
template<>
bool LicensingClientT<wchar_t>::MatchCurrentHardwareId(const wchar_t * hwid)
{
return m_Impl.MatchCurrentHardwareId(w2s(hwid).c_str());
}
template<>
void LicensingClientT<char>::SetLicensingServiceUrl(const char * url)
{
m_Impl.SetLicensingServiceUrl(url);
}
template<>
void LicensingClientT<wchar_t>::SetLicensingServiceUrl(const wchar_t * url)
{
m_Impl.SetLicensingServiceUrl(w2s(url).c_str());
}
template<>
void LicensingClientT<char>::SetLicenseTemplateId(const char * templateId)
{
m_Impl.SetLicenseTemplateId(templateId);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseTemplateId(const wchar_t * templateId)
{
m_Impl.SetLicenseTemplateId(w2s(templateId).c_str());
}
template<>
void LicensingClientT<char>::AcquireLicense()
{
m_Impl.AcquireLicense();
}
template<>
void LicensingClientT<wchar_t>::AcquireLicense()
{
m_Impl.AcquireLicense();
}
template<>
bool LicensingClientT<char>::IsLicenseValid()
{
return m_Impl.IsLicenseValid();
}
template<>
bool LicensingClientT<wchar_t>::IsLicenseValid()
{
return m_Impl.IsLicenseValid();
}
template<>
LicenseValidationResultT<char> * LicensingClientT<char>::ValidateLicense(LicenseValidationArgsT<char> * args)
{
static LicenseValidationResultT<char> result;
auto& resultImpl = m_Impl.ValidateLicense(&args->m_Impl);
result.m_Impl.MoveFrom(resultImpl);
return &result;
}
template<>
LicenseValidationResultT<wchar_t> * LicensingClientT<wchar_t>::ValidateLicense(LicenseValidationArgsT<wchar_t> * args)
{
static LicenseValidationResultT<wchar_t> result;
auto& resultImpl = m_Impl.ValidateLicense(&args->m_Impl);
result.m_Impl.MoveFrom(resultImpl);
return &result;
}
template<>
void LicensingClientT<char>::SetLicenseKeyValidationData(void * data, int len)
{
return m_Impl.SetLicenseKeyValidationData(data, len);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseKeyValidationData(void * data, int len)
{
return m_Impl.SetLicenseKeyValidationData(data, len);
}
template<>
int LicensingClientT<char>::GetLicenseActivationStatus()
{
return m_Impl.GetLicenseActivationStatus();
}
template<>
int LicensingClientT<wchar_t>::GetLicenseActivationStatus()
{
return m_Impl.GetLicenseActivationStatus();
}
template<>
void LicensingClientT<char>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
template<>
void LicensingClientT<wchar_t>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
template<>
void LicensingClientT<char>::SetTimeValidationMethod(int method)
{
return m_Impl.SetTimeValidationMethod(method);
}
template<>
void LicensingClientT<wchar_t>::SetTimeValidationMethod(int method)
{
return m_Impl.SetTimeValidationMethod(method);
}
};
};
const wchar_t * GetCurrentHardwareIdW(void * licensingClient)
{
static std::wstring result = ((ANSCENTER::Licensing::LicensingClientT<wchar_t> *)licensingClient)->GetCurrentHardwareId();
return result.c_str();
}
const char * GetCurrentHardwareIdA(void * licensingClient)
{
return ((ANSCENTER::Licensing::LicensingClientT<char> *)licensingClient)->GetCurrentHardwareId();
}
bool MatchCurrentHardwareIdW(void * licensingClient, const wchar_t * hwid)
{
return ((ANSCENTER::Licensing::LicensingClientT<wchar_t> *)licensingClient)->MatchCurrentHardwareId(hwid);
}
bool MatchCurrentHardwareIdA(void * licensingClient, const char * hwid)
{
return ((ANSCENTER::Licensing::LicensingClientT<char> *)licensingClient)->MatchCurrentHardwareId(hwid);
}

View File

@@ -0,0 +1,602 @@
#pragma once
#include <memory>
#include <vector>
#include "except.h"
#include "template.h"
#include "generator.h"
#include "validator.h"
#include "ntpclient.h"
#include "uniconv.h"
#include "license.h"
#include "licensevalidationargs.h"
#include "licensevalidationresult.h"
#include <time.h>
#ifdef _WIN32
#include <winhttp.h>
#include <tchar.h>
#else
#include <curl/curl.h>
#endif
using namespace std;
// these methods are compiler workarounds to eliminate circular references.
// They only call the corresponding LicensingClient::... methods
// GCC complains of cross-references between LicensingClientImpl and LicensingClientT
const wchar_t * GetCurrentHardwareIdW(void *);
const char * GetCurrentHardwareIdA(void *);
bool MatchCurrentHardwareIdW(void *, const wchar_t *);
bool MatchCurrentHardwareIdA(void *, const char *);
class LicensingClientImpl
{
public:
LicensingClientImpl(void * licensingClient, bool usesWideChar)
{
licenseKeyValidationDataLen = 0;
licenseTemplateId.clear();
parentLicensingClient = licensingClient;
parentUsesWideChar = usesWideChar;
timeValidationMethod = PREFER_INTERNET_TIME;
m_licenseValidityDays = 0;
// GetCurrentHardwareIdCallback = GetCurrentHardwareId;
// MatchCurrentHardwareIdCallback = MatchCurrentHardwareId;
}
void SetLicenseTemplate(const LicenseTemplateImpl* tmpl)
{
licenseTemplate = tmpl;
}
void SetLicenseKey(const char * key)
{
licenseKey = key;
}
void SetActivationKey(const char * key)
{
activationKey = key;
}
const char * GetActivationKey()
{
return activationKey.c_str();
}
void SetHardwareId(const char * hwid)
{
hardwareId = hwid;
}
const char * GetHardwareId()
{
return hardwareId.c_str();
}
void SetLicenseTemplateId(const char * templateId)
{
licenseTemplateId = templateId;
}
const char * GetLicenseTemplateId()
{
return licenseTemplateId.c_str();
}
void SetLicenseKeyValidationData(const void* data, unsigned len)
{
licenseKeyValidationData.resize(len);
memcpy(licenseKeyValidationData.data(), data, len);
licenseKeyValidationDataLen = len;
}
LicenseTemplateImpl * CreateActivationTemplate()
{
LicenseTemplateImpl * tmpl = new LicenseTemplateImpl();
tmpl->SetCharactersPerGroup(licenseTemplate->GetCharactersPerGroup());
tmpl->SetNumberOfGroups(licenseTemplate->GetNumberOfGroups());
tmpl->SetGroupSeparator(licenseTemplate->GetGroupSeparator());
//activationKeyTemplate.SetDataSize(t.GetDataSize());
tmpl->SetSignatureSize(licenseTemplate->GetSignatureSize());
tmpl->SetEncoding(licenseTemplate->GetEncoding());
tmpl->SetPublicKeyCertificate(licenseTemplate->GetPublicKeyCertificate());
int keyLen = tmpl->GetNumberOfGroups() * tmpl->GetCharactersPerGroup()
+ (tmpl->GetNumberOfGroups() - 1) * strlen(tmpl->GetGroupSeparator());
int hwidLen = 29;
if (hardwareId.length() > 0)
hwidLen = hardwareId.length();
tmpl->SetDataSize(tmpl->GetCharactersPerGroup() * tmpl->GetNumberOfGroups() * tmpl->GetEncoding() - tmpl->GetSignatureSize());
tmpl->SetValidationDataSize((keyLen + hwidLen ) * 8 + licenseTemplate->GetValidationDataSize());
tmpl->AddDataField("ExpirationDate", FIELD_TYPE_RAW, 16, 0);
tmpl->AddValidationField("LicenseKey", FIELD_TYPE_STRING, keyLen * 8, 0);
tmpl->AddValidationField("HardwareId", FIELD_TYPE_STRING, hwidLen * 8, keyLen * 8);
if (!licenseKeyValidationData.empty())
{
tmpl->AddValidationField("LicenseKeyValidationData", FIELD_TYPE_RAW, licenseKeyValidationDataLen * 8, (keyLen + hwidLen) * 8);
}
if (licensingServiceUrl.empty())
tmpl->SetLicensingServiceUrl(licenseTemplate->GetLicensingServiceUrl());
else
tmpl->SetLicensingServiceUrl(licensingServiceUrl.c_str());
if (licenseTemplateId.empty())
tmpl->SetTemplateId(licenseTemplate->GetTemplateId());
else
tmpl->SetTemplateId(licenseTemplateId.c_str());
return tmpl;
}
bool ValidateHardwareId()
{
if (!MatchCurrentHardwareIdCallback(hardwareId.c_str()))
{
activationStatus = STATUS_INVALID_HARDWARE_ID;
return false;
}
return true;
}
bool ValidateActivationKey(LicenseTemplateImpl* activationTemplate = nullptr, bool validateExpirationDate = true)
{
bool ownActivationTemplate = false;
try {
if (!activationTemplate)
{
activationTemplate = CreateActivationTemplate();
ownActivationTemplate = true;
}
KeyValidatorImpl validator(activationTemplate);
validator.SetValidationData("LicenseKey", licenseKey.c_str());
validator.SetValidationData("HardwareId", hardwareId.c_str());
if (!licenseKeyValidationData.empty())
validator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), (activationTemplate->GetValidationDataSize() + 7) >> 3);
try
{
validator.SetKey(activationKey.c_str());
}
catch (Exception * ex)
{
ex->Destroy();
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
if (ownActivationTemplate) delete activationTemplate;
return false;
}
if (!validator.IsKeyValid())
{
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
if (ownActivationTemplate) delete activationTemplate;
return false;
}
unsigned char rawKeyData[2];
int rawKeyDataBits = 16;
validator.QueryKeyData("ExpirationDate", rawKeyData, &rawKeyDataBits);
unsigned short keyData = (unsigned short)(((unsigned short)rawKeyData[0]) << 8 | rawKeyData[1]);
memset(&licenseExpirationTime, 0, sizeof(licenseExpirationTime));
if (keyData != 0)
{
licenseExpirationTime.tm_year = (2000 + (keyData >> 9)) - 1900;
licenseExpirationTime.tm_mon = ((keyData & 0x01FF) >> 5) - 1;
licenseExpirationTime.tm_mday = keyData & 0x001F;
if (!validateExpirationDate)
{
if (ownActivationTemplate) delete activationTemplate;
return true;
}
time_t currentTime;
if (timeValidationMethod != USE_LOCAL_TIME)
{
currentTime = NTPClient::GetCurrentTimeUTC();
if (currentTime == 0) // if couldn't obtain internet time
{
if (timeValidationMethod == USE_INTERNET_TIME) // internet time was mandatory
{
activationStatus = STATUS_NET_ERROR;
if (ownActivationTemplate) delete activationTemplate;
return false;
}
// fallback to local time
currentTime = time(NULL);
}
}
else
currentTime = time(NULL);
double diffSeconds = difftime(mktime(&licenseExpirationTime), currentTime);
if (diffSeconds < 0)
{
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() - (int)(((time_t)(-diffSeconds) + 86400 - 1) / 86400);
if (m_licenseValidityDays < 0)
m_licenseValidityDays = 0;
activationStatus = STATUS_LICENSE_EXPIRED;
if (ownActivationTemplate) delete activationTemplate;
return false;
} else
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() + (int)(((time_t)diffSeconds + 86400 - 1) / 86400);
}
else
m_licenseValidityDays = -1;
if (ownActivationTemplate) delete activationTemplate;
return true;
}
catch (...)
{
if (ownActivationTemplate && activationTemplate)
delete activationTemplate;
throw;
}
}
bool IsLicenseValid()
{
activationStatus = STATUS_GENERIC_ERROR;
try
{
if (ValidateHardwareId() && ValidateActivationKey())
{
activationStatus = STATUS_SUCCESS;
return true;
}
else
return false;
}
catch (Exception * ex)
{
ex->Destroy();
activationStatus = STATUS_GENERIC_ERROR;
return false;
}
catch (...)
{
activationStatus = STATUS_GENERIC_ERROR;
return false;
}
}
LicenseValidationResultImpl& ValidateLicense(LicenseValidationArgsImpl * args)
{
const LicenseImpl * license = args->GetLicense();
const char * lk = args->GetLicenseKey();
licenseKey = (lk) ? lk : "";
if (license == NULL && licenseKey.length() == 0)
throw new LicensingException(STATUS_GENERIC_ERROR, "either a license or a license key must be provided");
if (license == NULL)
{
try {
KeyValidatorImpl keyValidator;
keyValidator.SetKeyTemplate(licenseTemplate);
keyValidator.SetKey(lk);
if (licenseTemplate->GetValidationDataSize() > 0)
{
int fieldType, fieldSize, fieldOffset;
for (std::list<NameValuePair>::iterator iter = args->m_licenseKeyValidationData.begin(); iter != args->m_licenseKeyValidationData.end(); iter++)
{
if (!licenseTemplate->GetValidationField(iter->name.c_str(), &fieldType, &fieldSize, &fieldOffset))
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key validation data is invalid");
switch (fieldType)
{
case FIELD_TYPE_INTEGER:
keyValidator.SetValidationData(iter->name.c_str(), iter->intValue);
break;
case FIELD_TYPE_STRING:
keyValidator.SetValidationData(iter->name.c_str(), iter->stringValue.c_str());
break;
case FIELD_TYPE_DATE13:
case FIELD_TYPE_DATE14:
case FIELD_TYPE_DATE16:
keyValidator.SetValidationData(iter->name.c_str(), iter->dateValue.year, iter->dateValue.month, iter->dateValue.day);
break;
case FIELD_TYPE_RAW:
// keyValidator.SetValidationData(iter->name.c_str(), &(iter->value.binaryValue[0]), iter->value.binaryValue.size);
break;
default:
break;
}
}
licenseKeyValidationDataLen = (licenseTemplate->GetValidationDataSize() + 7) >> 3;
licenseKeyValidationData.resize(licenseKeyValidationDataLen);
keyValidator.QueryValidationData(NULL, licenseKeyValidationData.data(), &licenseKeyValidationDataLen);
}
if (!keyValidator.IsKeyValid())
{
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key is not valid");
}
AcquireLicense();
}
catch (LicensingException * ex)
{
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
{
m_licenseValidationResult.SetPaymentRequired(true);
ex->Destroy();
}
else
throw;
}
}
else
{
licenseKey = license->GetLicenseKey();
hardwareId = license->GetHardwareId();
activationKey = license->GetActivationKey();
const void* buf; int len;
license->GetLicenseKeyValidationData(&buf, &len);
if (buf && (len > 0))
SetLicenseKeyValidationData(buf, (unsigned int)len);
if (ValidateActivationKey(NULL, true))
{
m_licenseValidationResult.SetLicenseValid(true);
m_licenseValidationResult.SetPaymentRequired(false);
m_licenseValidationResult.SetLicenseExpired(false);
m_licenseValidationResult.SetLicense(NULL);
return m_licenseValidationResult;
}
else
{
if (activationStatus == STATUS_LICENSE_EXPIRED)
{
m_licenseValidationResult.SetLicenseExpired(true);
}
if ((activationStatus == STATUS_LICENSE_EXPIRED) && (m_licenseValidityDays > 0) && license->IsLease())
{
try
{
AcquireLicense();
m_licenseValidationResult.SetLicenseExpired(false);
}
catch (LicensingException * ex)
{
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
{
m_licenseValidationResult.SetPaymentRequired(true);
ex->Destroy();
}
else
throw;
}
}
}
}
if (licenseExpirationTime.tm_year > 0)
{
m_licenseValidationResult.SetLicenseExpirationDate(
1900 + licenseExpirationTime.tm_year,
1 + licenseExpirationTime.tm_mon,
licenseExpirationTime.tm_mday);
}
else
{
m_licenseValidationResult.SetLicenseExpirationDate(0, 0, 0);
}
return m_licenseValidationResult;
}
void AcquireLicense()
{
if (hardwareId.empty())
hardwareId = (parentLicensingClient) ? GetCurrentHardwareIdCallback() : GetCurrentHardwareId();
unique_ptr<LicenseTemplateImpl> activationTemplate(CreateActivationTemplate());
const char * templateId = activationTemplate->GetTemplateId();
if (templateId != NULL && templateId[0] != '\0')
{
char params[64] = "ProductId=";
sprintf(params + sizeof("ProductId"), "%s", activationTemplate->GetTemplateId());
activationTemplate->SetLicensingServiceParameters(params);
}
KeyGeneratorImpl generator(activationTemplate.get());
generator.SetKeyData("ExpirationDate", (int)0);
generator.SetValidationData("LicenseKey", licenseKey.c_str());
generator.SetValidationData("HardwareId", hardwareId.c_str());
if (!licenseKeyValidationData.empty())
{
generator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), licenseKeyValidationDataLen * 8);
}
try {
activationKey = generator.GenerateKey();
}
catch (LicensingException * ex)
{
if ((ex->GetCode() == STATUS_NET_ERROR) && (generator.GetSigningServiceStatusCode() == 406))
{
m_licenseValidationResult.SetPaymentRequired(true);
ex->Destroy();
}
else
throw;
}
if (ValidateActivationKey(activationTemplate.get(), false))
{
activationStatus = STATUS_SUCCESS;
}
else
throw new LicensingException(STATUS_GENERIC_ERROR, "internal error - invalid returned activation key");
m_licenseValidationResult.m_license = std::make_unique<LicenseImpl>();
m_licenseValidationResult.m_license->SetHardwareId(hardwareId.c_str());
m_licenseValidationResult.m_license->SetActivationKey(activationKey.c_str());
m_licenseValidationResult.m_license->SetLicenseKey(licenseKey.c_str());
m_licenseValidationResult.m_license->SetLicenseKeyValidationData(licenseKeyValidationData.data(), licenseKeyValidationDataLen);
int status = generator.GetSigningServiceStatusCode();
if (status == 200 /* HTTP OK */)
m_licenseValidationResult.m_license->SetLease(false);
else
if (status == 201 || status == 202)
m_licenseValidationResult.m_license->SetLease(true);
m_licenseValidationResult.SetLicenseValid(true);
}
void SetLicensingServiceUrl(const char * url)
{
licensingServiceUrl = url;
}
int GetLicenseActivationStatus()
{
return activationStatus;
}
void GetLicenseExpirationDate(int * year, int * month, int * day)
{
if (licenseExpirationTime.tm_year > 0)
{
*year = 1900 + licenseExpirationTime.tm_year;
*month = 1 + licenseExpirationTime.tm_mon;
*day = licenseExpirationTime.tm_mday;
} else
{
*year = 0;
*month = 0;
*day = 0;
}
}
const char * GetCurrentHardwareIdCallback()
{
if (parentUsesWideChar)
{
static string hwid = w2s(GetCurrentHardwareIdW(parentLicensingClient));
return hwid.c_str();
}
else
{
return GetCurrentHardwareIdA(parentLicensingClient);
}
}
bool MatchCurrentHardwareIdCallback(const char * hwid)
{
if (parentUsesWideChar)
{
return MatchCurrentHardwareIdW(parentLicensingClient, s2w(hwid).c_str());
}
else
return MatchCurrentHardwareIdA(parentLicensingClient, hwid);
}
static const char * GetCurrentHardwareId()
{
return KeyHelper::GetCurrentHardwareId();
}
static bool MatchCurrentHardwareId(const char * hwid)
{
return KeyHelper::MatchCurrentHardwareId(hwid);
}
void SetTimeValidationMethod(int method)
{
timeValidationMethod = method;
}
private:
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* licenseTemplate;
LicenseValidationResultImpl m_licenseValidationResult;
struct tm licenseExpirationTime;
string licenseKey;
string activationKey;
string hardwareId;
string licensingServiceUrl;
vector<unsigned char> licenseKeyValidationData;
int licenseKeyValidationDataLen;
int activationStatus;
string licenseTemplateId;
void * parentLicensingClient;
bool parentUsesWideChar;
int timeValidationMethod;
int m_licenseValidityDays;
//const char * (*GetCurrentHardwareIdCallback)(void * callerContext);
//bool (*MatchCurrentHardwareIdCallback)(void * callerContext, const char * hwid);
};

View File

@@ -0,0 +1,2 @@
#include "precomp.h"
#include "ntpclient.h"

View File

@@ -0,0 +1,113 @@
#pragma once
#ifndef _WIN32
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define INVALID_SOCKET (-1)
#define SOCKET int
#define SOCKET_ERROR (-1)
#define closesocket close
#endif
#include <time.h>
class NTPClient
{
public:
static time_t GetCurrentTimeUTC(const char * ntpserver = NULL)
{
#ifdef _WIN32
WSADATA w;
int remote_length;
#else
socklen_t remote_length;
#endif
SOCKET sd = INVALID_SOCKET;
char ntp_buffer[48];
time_t current_time = 0;
struct hostent *hp;
struct sockaddr_in remote;
struct sockaddr_in local;
char host_name[256];
hostent * host = NULL;
do {
#ifdef _WIN32
if (WSAStartup(MAKEWORD(2, 2), &w) != 0)
return 0;
#endif
if ((sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
break;
memset((void *)&remote, '\0', sizeof(struct sockaddr_in));
remote.sin_family = AF_INET;
remote.sin_port = htons(123);
if ((host = gethostbyname((ntpserver) ? ntpserver : "time.windows.com")) == NULL)
break;
remote.sin_addr.s_addr = *(u_long *)host->h_addr_list[0];
memset((void *)&local, '\0', sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(0);
local.sin_addr.s_addr = htonl(INADDR_ANY);
if (::bind(sd, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
break;
memset(ntp_buffer, 0, sizeof(ntp_buffer));
ntp_buffer[0] = 0x1B;
remote_length = sizeof(struct sockaddr_in);
if (sendto(sd, ntp_buffer, sizeof(ntp_buffer), 0, (struct sockaddr *)&remote, remote_length) == -1)
break;
fd_set fds;
FD_ZERO(&fds);
FD_SET(sd, &fds);
timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if (select(1, &fds, NULL, NULL, &timeout) != 1)
break;
if (recvfrom(sd, ntp_buffer, sizeof(ntp_buffer), 0, (struct sockaddr *)&remote, &remote_length) < 0)
break;
unsigned int int_part = *(unsigned int *)(ntp_buffer + 40);
unsigned int fract_part = *(unsigned int *)(ntp_buffer + 44);
int_part = SwapEndianness(int_part);
current_time = (time_t)(int_part -= 2208988800U);
}
while (0);
if (sd != INVALID_SOCKET)
closesocket(sd);
#ifdef _WIN32
WSACleanup();
#endif
return current_time;
}
static unsigned int SwapEndianness(unsigned int x)
{
return (unsigned int)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
};

1200
core/anslicensing/picojson.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"

View File

@@ -0,0 +1,32 @@
#pragma once
#include "anslicensing.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h> /* memset(), memcpy() */
#include <assert.h>
#include <string>
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <WinSock2.h>
#include <windows.h>
#include <tchar.h>
#include <malloc.h>
#endif
#ifndef _WIN32
#define _alloca alloca
#define _stricmp strcasecmp
#define _snprintf snprintf
#define _atoi64(s) strtoull(s, NULL, 10)
#endif

285
core/anslicensing/prime.cpp Normal file
View File

@@ -0,0 +1,285 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
// prime factory implementation
#include "precomp.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "bigint.h"
#include "prime.h"
extern void print( bigint x );
static int maybe_prime( const bigint & p )
{
return modexp( 2, p - 1, p ) == 1;
}
static int fermat_is_probable_prime( const bigint & p )
{
// Test based on Fermats theorem a**(p-1) = 1 mod p for prime p
// For 1000 bit numbers this can take quite a while
const int rep = 4;
const unsigned any[ rep ] = { 2,3,5,7 /*,11,13,17,19,23,29,31,37..*/ };
for ( unsigned i = 0; i < rep; i += 1 )
if ( modexp( any[ i ], p - 1, p ) != 1 )
return 0;
return 1;
}
static bigint random( const bigint & n )
{
bigint x = 0;
while ( x < n )
x = x * RAND_MAX + rand();
return x % n;
}
static int miller_rabin_is_probable_prime( const bigint & n )
{
unsigned T = 100;
unsigned v = 0;
bigint w = n - 1;
srand( (unsigned) time( 0 ) );
while ( w % 2 != 0 )
{
v += 1;
w = w / 2;
}
for ( unsigned j = 1; j <= T; j += 1 )
{
bigint a = 1 + random( n );
bigint b = modexp( a, w, n );
if ( b != 1 && b != n - 1 )
{
unsigned i = 1;
while ( 1 )
{
if ( i == v )
return 0;
b = ( b * b ) % n;
if ( b == n - 1 )
break;
if ( b == 1 )
return 0;
i += 1;
}
}
}
return 1;
}
int is_probable_prime( const bigint & n )
{
return fermat_is_probable_prime( n )
&& miller_rabin_is_probable_prime( n );
}
prime_factory::prime_factory( unsigned MP )
{
// Initialise pl
unsigned p = 2;
char * b = new char[ MP + 1 ]; // one extra to stop search
for ( unsigned i = 0; i <= MP; i += 1 )
b[ i ] = 1;
np = 0;
while ( 1 )
{
// skip composites
while ( b[ p ] == 0 )
p += 1;
if ( p == MP )
break;
np += 1;
// cross off multiples
unsigned c = p * 2;
while ( c < MP )
{
b[ c ] = 0;
c += p;
}
p += 1;
}
pl = new unsigned[ np ];
np = 0;
for ( p = 2; p < MP; p += 1 )
if ( b[ p ] )
{
pl[ np ] = p;
np += 1;
}
delete [] b;
}
prime_factory::~prime_factory()
{
delete [] pl;
}
bigint prime_factory::find_prime( bigint start )
{
unsigned SS = 1000; // should be enough unless we are unlucky
char * b = new char[ SS ]; // bitset of candidate primes
while ( 1 )
{
unsigned i;
for ( i = 0; i < SS; i += 1 )
b[ i ] = 1;
for ( i = 0; i < np; i += 1 )
{
unsigned p = pl[ i ];
unsigned r = to_unsigned( start % p ); // not as fast as it should be - could do with special routine
if ( r )
r = p - r;
// cross off multiples of p
while ( r < SS )
{
b[ r ] = 0;
r += p;
}
}
// now test candidates
for ( i = 0; i < SS; i+=1 )
{
if ( b[ i ] )
{
if ( is_probable_prime( start ) )
{
delete [] b;
return start;
}
}
start += 1;
}
}
}
bigint prime_factory::find_special( bigint start, bigint base )
{
// Returns a (probable) prime number x > start such that
// x and x*2+1 are both probable primes,
// i.e. x is a probable Sophie-Germain prime
unsigned SS = 40000; // should be enough unless we are unlucky
char * b1 = new char[ SS ]; // bitset of candidate primes
char * b2 = new char[ 2 * SS ];
while ( 1 )
{
unsigned i;
for ( i = 0; i < SS; i += 1 )
b1[ i ] = 1;
for ( i = 0; i < 2 * SS; i += 1 )
b2[ i ] = 1;
for ( i = 0; i < np; i += 1 )
{
unsigned p = pl[ i ];
unsigned r = to_unsigned( start % p ); // not as fast as it should be - could do with special routine
if ( r )
r = p - r;
// cross off multiples of p
while ( r < SS )
{
b1[ r ] = 0;
r += p;
}
r = to_unsigned( ( start * 2 + 1 ) % p );
if ( r )
r = p - r;
while ( r < 2 * SS )
{
b2[ r ] = 0;
r += p;
}
}
// now test candidates
for ( i = 0; i < SS; i += 1 )
{
if ( b1[ i ] && b2[ i * 2 ] )
{
printf("D=%u\n", to_unsigned( start * 2 + 1 - base ) );
if ( maybe_prime( start )
&& maybe_prime( start * 2 + 1 )
&& is_probable_prime( start )
&& is_probable_prime( start * 2 + 1 )
)
{
delete [] b1;
delete [] b2;
return start;
}
}
start += 1;
}
}
}
int prime_factory::make_prime( bigint & r, bigint & k, const bigint & min_p )
// Divide out small factors or r
{
k = 1;
for ( unsigned i = 0; i < np; i += 1 )
{
unsigned p = pl[ i ];
// maybe pre-computing product of several primes
// and then GCD(r,p) would be faster ?
while ( r % p == 0 )
{
if ( r == p )
return 1; // can only happen if min_p is small
r = r / p;
k = k * p;
if ( r < min_p )
return 0;
}
}
return is_probable_prime( r );
}

25
core/anslicensing/prime.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef __PRIME_H
#define __PRIME_H
class prime_factory
{
// construction
public:
prime_factory( unsigned MP = 2000 ); // sieve size
~prime_factory();
// methods
public:
bigint find_prime( bigint start );
int make_prime( bigint & r, bigint &k, const bigint & rmin );
bigint find_special( bigint start, bigint base=0 );
// properties
public:
unsigned np;
unsigned *pl;
};
int is_probable_prime( const bigint &p );
#endif

View File

@@ -0,0 +1,353 @@
#pragma once
#include "precomp.h"
#include "uniconv.h"
#include "tinyxml2.h"
#include "picojson.h"
#include <map>
#include <list>
#ifndef MAX_XML_BUFFER_SIZE
#define MAX_XML_BUFFER_SIZE 4096
#endif
class PathEntry
{
friend class PropertyCollection;
public:
PathEntry()
{
processed = false;
}
PathEntry(const PathEntry & copy)
{
processed = false;
path = copy.path;
nameValueCollection = copy.nameValueCollection;
}
PathEntry(const PathEntry * copy)
{
processed = false;
path = copy->path;
nameValueCollection = copy->nameValueCollection;
}
private:
string path;
std::map<string, string> nameValueCollection;
bool processed;
};
class PropertyCollection
{
public:
PropertyCollection()
{
}
void SetProperty(const char * path, const char * name, const char * value)
{
string propName = (name != NULL) ? name : "";
std::map<string, PathEntry>::iterator entry;
if ((entry = m_properties.find(path)) == m_properties.end())
{
PathEntry entry;
entry.path = path;
entry.nameValueCollection.insert(std::map<string, string>::value_type(propName, value));
m_properties.insert(std::map<string, PathEntry>::value_type(path, entry));
} else
entry->second.nameValueCollection.insert(std::map<string, string>::value_type(propName, value));
}
const char * GetProperty(const char * path, const char * name) const
{
std::map<string, PathEntry>::const_iterator entry = m_properties.find(path);
if (entry == m_properties.end())
return NULL;
std::map<string, string>::const_iterator nv = entry->second.nameValueCollection.find((name != NULL) ? name : "");
if (nv == entry->second.nameValueCollection.end())
return NULL;
return nv->second.c_str();
}
void LoadXml(tinyxml2::XMLElement * src)
{
XmlToPathList("", src);
}
void SaveXml(std::string & xml)
{
PathListToXml("/", &m_properties, xml, 1);
}
void LoadJson(picojson::object & json)
{
string path;
size_t pos;
for (picojson::object::iterator iter = json.begin(); iter != json.end(); iter++)
{
path = iter->first.c_str();
if ((pos = path.find_last_of('#')) == string::npos)
SetProperty(path.c_str(), NULL, iter->second.get<std::string>().c_str());
else
{
SetProperty(path.substr(0, pos).c_str(), path.substr(pos + 1).c_str(), iter->second.get<std::string>().c_str());
}
}
}
void SaveJson(std::string & json, const char * indent = "")
{
bool first = true;
json.append("{");
for (std::map<string, PathEntry>::const_iterator item = m_properties.begin(); item != m_properties.end(); item++)
{
for (std::map<string, string>::const_iterator innerItem = item->second.nameValueCollection.begin(); innerItem != item->second.nameValueCollection.end(); innerItem++)
{
if (!first) json.append(",");
json.append("\n");
json.append(indent);
json.append("\t");
json.append("\"");
json.append(item->first.c_str());
if (innerItem->first.length() > 0)
{
json.append("#"); json.append(innerItem->first.c_str());
}
json.append("\":\""); json.append(innerItem->second.c_str()); json.append("\"");
first = false;
}
}
json.append("\n"); json.append(indent); json.append("}");
}
size_t GetSize() const
{
return m_properties.size();
}
private:
std::map<string, PathEntry> m_properties;
void XmlToPathList(const std::string prefix, const tinyxml2::XMLElement * node)
{
const char * text = node->GetText();
if (text != NULL)
SetProperty(prefix.c_str(), "", text);
const tinyxml2::XMLAttribute * attr = node->FirstAttribute();
// risk of stack overflow because _alloca is called in loop. However the current number of properties
// is very low so it is acceptable
while (attr)
{
SetProperty(prefix.c_str(), attr->Name(), attr->Value());
attr = attr->Next();
}
tinyxml2::XMLElement * child;
for (child = (tinyxml2::XMLElement *)node->FirstChildElement(); child != NULL; child = child->NextSiblingElement())
{
XmlToPathList(prefix + "/" + child->Name(), child);
}
}
void PathListToXml(const std::string pathPrefix, std::map<string, PathEntry> * sortedPathList, std::string & xml, int indent)
{
std::string elementValue;
bool startElementClosed = false;
if (pathPrefix != "/")
{
if (indent > 0)
xml.append(indent, '\t');
xml.append("<"); xml.append(1 + strrchr(pathPrefix.c_str(), '/'));
}
for (std::map<string, PathEntry>::const_iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (strcmp(item->second.path.c_str(), pathPrefix.c_str()) == 0)
{
for (std::map<string, string>::const_iterator nvItem = item->second.nameValueCollection.begin();
nvItem != item->second.nameValueCollection.end();
nvItem++)
{
if (nvItem->first.length() == 0)
{
elementValue = nvItem->second.c_str();
} else
{
xml.append(" ");
xml.append(nvItem->first.c_str());
xml.append("=\"");
xml.append(nvItem->second.c_str());
xml.append("\"");
}
}
}
}
if (pathPrefix != "/")
{
xml.append(">");
if (elementValue.length() > 0)
{
xml.append(elementValue);
} else
if (indent >= 0)
xml.append("\n");
}
bool finished = false;
while (!finished)
{
finished = true;
std::string firstUnprocessedPrefix;
std::map<string, PathEntry> innerPathList;
for (std::map<string, PathEntry>::iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (!item->second.processed && item->second.path.length() > pathPrefix.length() && (firstUnprocessedPrefix.empty() || strncmp(item->second.path.c_str(), firstUnprocessedPrefix.c_str(), firstUnprocessedPrefix.length()) == 0))
{
if (firstUnprocessedPrefix.empty())
{
int nextSep = item->second.path.find('/', pathPrefix.length() + 1);
firstUnprocessedPrefix = item->second.path.substr(0, (nextSep >= 0) ? nextSep : item->second.path.length()).c_str();
}
innerPathList.insert(std::map<string, PathEntry>::value_type(item->first, item->second));
item->second.processed = true;
finished = false;
}
}
if (!finished)
PathListToXml(firstUnprocessedPrefix, &innerPathList, xml, (indent >= 0) ? indent + 1 : indent);
}
if (pathPrefix != "/")
{
if (indent > 0 && elementValue.length() == 0)
xml.append(indent, '\t');
xml.append("</"); xml.append(1 + strrchr(pathPrefix.c_str(), '/')); xml.append(">");
if (indent >= 0) xml.append("\n");
}
}
void PathListToJson(const std::string pathPrefix, std::map<string, PathEntry> * sortedPathList, std::string & xml, int indent)
{
std::string elementValue;
bool startElementClosed = false;
if (pathPrefix != "/")
{
if (indent > 0)
xml.append(indent, '\t');
xml.append("\""); xml.append(1 + strrchr(pathPrefix.c_str(), '/')); xml.append("\":");
}
for (std::map<string, PathEntry>::const_iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (strcmp(item->second.path.c_str(), pathPrefix.c_str()) == 0)
{
for (std::map<string, string>::const_iterator nvItem = item->second.nameValueCollection.begin();
nvItem != item->second.nameValueCollection.end();
nvItem++)
{
if (nvItem->first.length() == 0)
{
elementValue = nvItem->second.c_str();
}
else
{
xml.append(" ");
xml.append(nvItem->first.c_str());
xml.append("=\"");
xml.append(nvItem->second.c_str());
xml.append("\"");
}
}
}
}
if (pathPrefix != "/")
{
xml.append(">");
if (elementValue.length() > 0)
{
xml.append(elementValue);
}
else
if (indent >= 0)
xml.append("\n");
}
bool finished = false;
while (!finished)
{
finished = true;
std::string firstUnprocessedPrefix;
std::map<string, PathEntry> innerPathList;
for (std::map<string, PathEntry>::iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (!item->second.processed && item->second.path.length() > pathPrefix.length() && (firstUnprocessedPrefix.empty() || strncmp(item->second.path.c_str(), firstUnprocessedPrefix.c_str(), firstUnprocessedPrefix.length()) == 0))
{
if (firstUnprocessedPrefix.empty())
{
int nextSep = item->second.path.find('/', pathPrefix.length() + 1);
firstUnprocessedPrefix = item->second.path.substr(0, (nextSep >= 0) ? nextSep : item->second.path.length()).c_str();
}
innerPathList.insert(std::map<string, PathEntry>::value_type(item->first, item->second));
item->second.processed = true;
finished = false;
}
}
if (!finished)
PathListToXml(firstUnprocessedPrefix, &innerPathList, xml, (indent >= 0) ? indent + 1 : indent);
}
if (pathPrefix != "/")
{
if (indent > 0 && elementValue.length() == 0)
xml.append(indent, '\t');
xml.append("}");
if (indent >= 0) xml.append("\n");
}
}
};

View File

@@ -0,0 +1,66 @@
#include "precomp.h"
#include "bigint.h"
#include "rand.h"
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
#endif
#include <stdlib.h>
random::random()
{
#ifdef _WIN32
if ( !CryptAcquireContext( (HCRYPTPROV *)&m_hCryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) )
m_hCryptProv = NULL;
#else
::srand(time(NULL));
#endif
}
random::~random()
{
#ifdef _WIN32
if ( m_hCryptProv )
CryptReleaseContext( (HCRYPTPROV)m_hCryptProv, 0L );
#endif
}
unsigned random::rand( unsigned max )
{
unsigned rnd;
#ifdef _WIN32
if ( m_hCryptProv )
CryptGenRandom( (HCRYPTPROV)m_hCryptProv, sizeof( unsigned ), (BYTE *)&rnd );
#else
rnd = ::rand();
#endif
return rnd % max;
}
bigint random::rand( bigint & max )
{
unsigned n = ( max.bits() + ( ( sizeof( unsigned ) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned * buf = (unsigned*)malloc(n * sizeof(unsigned));
if ( !buf ) return max - 1;
bigint rnd;
#ifdef _WIN32
if ( m_hCryptProv )
CryptGenRandom( (HCRYPTPROV)m_hCryptProv, n * sizeof( unsigned ), (BYTE *)buf );
#else
for (unsigned i = 0; i < n; i++)
*((unsigned *)buf + i) = ::rand();
#endif
rnd.load( buf, n );
free(buf);
return rnd % max;
}

18
core/anslicensing/rand.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __RAND_H
#define __RAND_H
#include "bigint.h"
class random {
public:
random();
~random();
unsigned rand( unsigned max );
bigint rand( bigint & max );
protected:
void * m_hCryptProv;
};
#endif

View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by licensing.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,49 @@
#include "precomp.h"
#include "uniconv.h"
#include "template.h"
#include "validator.h"
#include "sdkregistration.h"
#include "version.h"
#include <time.h>
bool SDKRegistrationImpl::isRegistered = true;
bool SDKRegistrationImpl::isExpired = false;
string SDKRegistrationImpl::licenseKey;
void SDKRegistrationImpl::SetLicenseKey(const char * key)
{
licenseKey = key;
}
bool SDKRegistrationImpl::IsRegistered()
{
return true;
}
bool SDKRegistrationImpl::IsExpired()
{
return false;
}
const char * SDKRegistrationImpl::GetLicenseKey()
{
return licenseKey.c_str();
}
namespace ANSCENTER {
namespace Licensing {
template<>
void SDKRegistrationT<char>::SetLicenseKey(const char * key)
{
SDKRegistrationImpl::SetLicenseKey(key);
}
template<>
void SDKRegistrationT<wchar_t>::SetLicenseKey(const wchar_t * key)
{
string wkey = w2s(key);
SDKRegistrationImpl::SetLicenseKey(wkey.c_str());
}
};
};

View File

@@ -0,0 +1,21 @@
#ifndef __SDKREGISTRATION_H__
#define __SDKREGISTRATION_H__
class SDKRegistrationImpl
{
public:
static void SetLicenseKey(const char * key);
static const char * GetLicenseKey();
static bool IsRegistered();
static bool IsExpired();
private:
static bool isRegistered;
static bool isExpired;
static string licenseKey;
};
#endif

160
core/anslicensing/sha1.cpp Normal file
View File

@@ -0,0 +1,160 @@
#include "precomp.h"
#include "sha1.h"
#define MAX_FILE_READ_BUFFER 8000
// Rotate x bits to the left
#ifndef ROL32
#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
#endif
#ifdef SHA1_LITTLE_ENDIAN
#define SHABLK0(i) (m_block->l[i] = \
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
#else
#define SHABLK0(i) (m_block->l[i])
#endif
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
// SHA-1 rounds
#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
SHA1::SHA1()
{
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
Reset();
}
SHA1::~SHA1()
{
Reset();
}
void SHA1::Reset()
{
// SHA1 initialization constants
m_state[0] = 0x67452301;
m_state[1] = 0xEFCDAB89;
m_state[2] = 0x98BADCFE;
m_state[3] = 0x10325476;
m_state[4] = 0xC3D2E1F0;
m_count[0] = 0;
m_count[1] = 0;
}
void SHA1::Transform(unsigned int state[5], unsigned char buffer[64])
{
unsigned int a = 0, b = 0, c = 0, d = 0, e = 0;
memcpy(m_block, buffer, 64);
// Copy state[] to working vars
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
// 4 rounds of 20 operations each. Loop unrolled.
_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
// Add the working vars back into state[]
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
// Wipe variables
a = b = c = d = e = 0;
}
// Use this function to hash in binary data and strings
void SHA1::Update(unsigned char *data, unsigned int len)
{
unsigned int i = 0, j;
j = (m_count[0] >> 3) & 63;
if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
m_count[1] += (len >> 29);
if((j + len) > 63)
{
memcpy(&m_buffer[j], data, (i = 64 - j));
Transform(m_state, m_buffer);
for (; i+63 < len; i += 64)
Transform(m_state, &data[i]);
j = 0;
}
else i = 0;
memcpy(&m_buffer[j], &data[i], len - i);
}
void SHA1::Final()
{
unsigned int i = 0;
unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
for (i = 0; i < 8; i++)
finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
Update((unsigned char *)"\200", 1);
while ((m_count[0] & 504) != 448)
Update((unsigned char *)"\0", 1);
Update(finalcount, 8); // Cause a SHA1Transform()
for (i = 0; i < 20; i++)
{
m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
}
// Wipe variables for security reasons
i = 0;
memset(m_buffer, 0, 64);
memset(m_state, 0, 20);
memset(m_count, 0, 8);
memset(finalcount, 0, 8);
Transform(m_state, m_buffer);
}
// Get the raw message digest
void SHA1::GetHash(unsigned char *uDest)
{
memcpy(uDest, m_digest, 20);
}

58
core/anslicensing/sha1.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef ___SHA1_H___
#define ___SHA1_H___
#include <stdio.h> // Needed for file access
#include <memory.h> // Needed for memset and memcpy
#include <string.h> // Needed for strcat and strcpy
#define SHA1_LITTLE_ENDIAN
#ifdef LICENSING_BIG_ENDIAN
// If you're compiling big endian, just comment out the following line
#undef SHA1_LITTLE_ENDIAN
#endif
typedef union
{
unsigned char c[64];
unsigned int l[16];
} SHA1_WORKSPACE_BLOCK;
class SHA1
{
public:
// Two different formats for ReportHash(...)
enum
{
REPORT_HEX = 0,
REPORT_DIGIT = 1
};
// Constructor and Destructor
SHA1();
virtual ~SHA1();
unsigned int m_state[5];
unsigned int m_count[2];
unsigned char m_buffer[64];
unsigned char m_digest[20];
void Reset();
// Update the hash value
void Update(unsigned char *data, unsigned int len);
// Finalize hash and report
void Final();
void GetHash(unsigned char *uDest);
private:
// Private SHA-1 transformation
void Transform(unsigned int state[5], unsigned char buffer[64]);
// Member variables
unsigned char m_workspace[64];
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,528 @@
#pragma once
#include <memory>
#include <map>
#include "ecc.h"
#include "base64.h"
#include "uniconv.h"
#include "except.h"
#include "sdkregistration.h"
#include "certificate.h"
#include "propertycollection.h"
using namespace std;
class LicenseTemplateImpl {
friend LicenseTemplate;
struct FieldInfo
{
FieldInfo(int _type, int _size, int _offset)
{
type = (BitStruct::FIELD_TYPE)_type;
size = _size;
offset = _offset;
}
BitStruct::FIELD_TYPE type;
int size;
int offset;
};
public:
LicenseTemplateImpl(const char * xmlTemplate = NULL):
m_defaultDataOffset(0),
m_defaultValidationOffset(0)
{
Init();
if (xmlTemplate)
LoadXml(xmlTemplate);
}
void SetVersion(int version)
{
if (version > 3)
throw new LicensingException(STATUS_UNSUPPORTED_VERSION);
m_version = version;
}
unsigned GetVersion() const
{
return m_version;
}
void SetNumberOfGroups(int numGroups)
{
m_numGroups = numGroups;
}
unsigned GetNumberOfGroups() const
{
return m_numGroups;
}
void SetCharactersPerGroup(int charsPerGroup)
{
m_charsPerGroup = charsPerGroup;
}
unsigned GetCharactersPerGroup() const
{
return m_charsPerGroup;
}
void SetGroupSeparator(const char * groupSep)
{
m_groupSeparator = groupSep;
}
const char * GetGroupSeparator() const
{
return m_groupSeparator.c_str();
}
void SetEncoding(int encoding)
{
m_keyEncoding = encoding;
}
int GetEncoding() const
{
return m_keyEncoding;
}
void SetHeader(const char * header)
{
m_header = header;
}
const char * GetHeader() const
{
return m_header.c_str();
}
void SetFooter(const char * footer)
{
m_footer = footer;
}
const char * GetFooter() const
{
return m_footer.c_str();
}
void SetDataSize(int sizeInBits)
{
m_dataSize = sizeInBits;
}
unsigned GetDataSize() const
{
return m_dataSize;
}
void AddDataField(const char * fieldName, int fieldType, int fieldSizeInBits, int fieldOffset = -1)
{
if (fieldOffset < 0)
fieldOffset = m_defaultDataOffset;
m_dataFields.emplace(std::piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldSizeInBits, fieldOffset));
m_defaultDataOffset += fieldSizeInBits;
}
bool GetDataField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
{
auto info = m_dataFields.find(fieldName);
if (info == m_dataFields.end())
return false;
*fieldType = info->second.type;
*fieldSizeInBits = info->second.size;
*fieldOffset = info->second.offset;
return true;
}
bool EnumDataFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
{
map<string, FieldInfo>::const_iterator* pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new map<string, FieldInfo>::const_iterator(m_dataFields.begin());
if (!pIter)
return false;
}
else
pIter = (map<string, FieldInfo>::const_iterator*)(*enumHandle);
if (*pIter == m_dataFields.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.type;
*fieldSizeInBits = (*pIter)->second.size;
*fieldOffset = (*pIter)->second.offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void SetValidationDataSize(int sizeInBits)
{
m_validationDataSize = sizeInBits;
}
unsigned GetValidationDataSize() const
{
return m_validationDataSize;
}
void AddValidationField(const char * fieldName, int fieldType, int fieldBitSize, int fieldOffset = 0)
{
if (fieldOffset < 0)
fieldOffset = m_defaultValidationOffset;
m_validationFields.emplace(piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldBitSize, fieldOffset));
m_defaultValidationOffset += fieldBitSize;
}
bool GetValidationField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
{
auto info = m_validationFields.find(fieldName);
if (info == m_validationFields.end())
return false;
*fieldType = info->second.type;
*fieldSizeInBits = info->second.size;
*fieldOffset = info->second.offset;
return true;
}
bool EnumValidationFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSize, int * fieldOffset) const
{
map<string, FieldInfo>::const_iterator* pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new map<string, FieldInfo>::const_iterator(m_validationFields.begin());
if (!pIter)
return false;
}
else
pIter = (map<string, FieldInfo>::const_iterator*)(*enumHandle);
if (*pIter == m_validationFields.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.type;
*fieldSize = (*pIter)->second.size;
*fieldOffset = (*pIter)->second.offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void SetSignatureSize(int sizeInBits)
{
if (sizeInBits < 76 || sizeInBits > 322)
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
m_signatureSize = sizeInBits;
if (sizeInBits <= 108)
{
m_signatureKeyType = ECC::ECC_54;
m_signatureKeySize = 54;
} else
if (sizeInBits <= 146)
{
m_signatureKeyType = ECC::ECC_73;
m_signatureKeySize = 73;
} else
if (sizeInBits <= 158)
{
m_signatureKeyType = ECC::ECC_79;
m_signatureKeySize = 79;
} else
if (sizeInBits <= 182)
{
m_signatureKeyType = ECC::ECC_91;
m_signatureKeySize = 91;
} else
if (sizeInBits <= 200)
{
m_signatureKeyType = ECC::ECC_100;
m_signatureKeySize = 100;
} else
if (sizeInBits <= 240)
{
m_signatureKeyType = ECC::ECC_120;
m_signatureKeySize = 120;
} else
if (sizeInBits <= 262)
{
m_signatureKeyType = ECC::ECC_131;
m_signatureKeySize = 131;
} else
if (sizeInBits <= 282)
{
m_signatureKeyType = ECC::ECC_141;
m_signatureKeySize = 141;
} else
{
m_signatureKeyType = ECC::ECC_161;
m_signatureKeySize = 161;
}
}
unsigned GetSignatureSize() const
{
return m_signatureSize;
}
void LoadXml(const char * xmlTemplate);
const char * SaveXml(bool savePrivateKey);
void LoadJson(const char * jsonTemplate);
const char * SaveJson(bool savePrivateKey);
void SetLicensingServiceUrl(const char * url)
{
m_licensingServiceUrl = url;
}
const char * GetLicensingServiceUrl() const
{
return m_licensingServiceUrl.c_str();
}
void SetTemplateId(const char * templateId)
{
m_templateId = templateId;
}
const char * GetTemplateId() const
{
return m_templateId.c_str();
}
void SetLicensingServiceParameters(const char * params)
{
m_licensingServiceParameters = params;
}
void SetLicenseGracePeriod(int days)
{
m_licenseGracePeriod = days;
}
int GetLicenseGracePeriod() const
{
return m_licenseGracePeriod;
}
void SetPublicKeyCertificate(const char * base64Certificate)
{
m_certificate = make_unique<Certificate>(base64Certificate);
ValidateCertificate();
unsigned char keyBuf[256]; int keyLen = 256;
m_certificate->GetPublicKey(keyBuf, &keyLen);
m_verificationKey = make_unique<ECC::Key>(keyBuf, keyLen);
}
const char * GetPublicKeyCertificate() const
{
if (!m_certificate)
throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a certificate");
return m_certificate->ToString();
}
void SetPrivateKey(const char * base64Key)
{
BASE64 base64;
int keyLen;
int keyLenSizeT;
auto keyData = base64.decode(base64Key, (unsigned)strlen(base64Key), &keyLenSizeT);
if (keyData.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 private key");
keyLen = (unsigned)keyLenSizeT;
SetPrivateKey(keyData.data(), keyLen);
}
const char * GetPrivateKey() const
{
if (!m_signingKey)
throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a private key");
return m_signingKey->ToString();
}
void GenerateSigningKeyPair()
{
Key * privateKey = NULL,
* publicKey = NULL;
if (!SDKRegistrationImpl::IsRegistered())
{
privateKey = new Key(); privateKey->Load(&m_demoPrivateKeys[m_signatureKeyType][1], m_demoPrivateKeys[m_signatureKeyType][0], m_signatureKeyType);
publicKey = new Key(); publicKey->Load(&m_demoPublicKeys[m_signatureKeyType][1], m_demoPublicKeys[m_signatureKeyType][0], m_signatureKeyType);
} else
{
ECC::GenerateKeyPair(m_signatureKeyType, &privateKey, &publicKey);
}
m_certificate.reset(Certificate::Generate(m_signatureSize, privateKey, publicKey, NULL, NULL, NULL, 0));
ValidateCertificate();
m_signingKey.reset(privateKey);
m_verificationKey.reset(publicKey);
}
void SetProperty(const char * path, const char * name, const char * value)
{
m_properties.SetProperty(path, name, value);
}
const char * GetProperty(const char * path, const char * name) const
{
return m_properties.GetProperty(path, name);
}
public:
// general
int m_version;
// key format
int m_numGroups;
int m_charsPerGroup;
int m_keyEncoding;
string m_groupSeparator;
string m_header;
string m_footer;
string m_licensingServiceUrl;
string m_templateId;
string m_licensingServiceParameters;
map<string, FieldInfo> m_dataFields;
int m_defaultDataOffset;
map<string, FieldInfo> m_validationFields;
int m_defaultValidationOffset;
// key signature
unique_ptr<ECC::Key> m_verificationKey;
unique_ptr<ECC::Key> m_signingKey;
unique_ptr<Certificate> m_certificate;
bool m_hasPrivateKey;
ECC::KEY_TYPE m_signatureKeyType;
int m_signatureKeySize;
int m_signatureSize;
int m_dataSize;
int m_validationDataSize;
// buffer used to hold the xml representation of the template
string m_xmlTemplate;
// other stuff
int m_licenseGracePeriod;
PropertyCollection m_properties;
protected:
static const unsigned char m_demoPublicKeys[10][23];
static const unsigned char m_demoPrivateKeys[10][23];
private:
void Init()
{
SetVersion(3);
SetLicenseGracePeriod(0);
SetGroupSeparator("-");
SetNumberOfGroups(6);
SetCharactersPerGroup(6);
SetEncoding(ENCODING_BASE32X);
SetSignatureSize(158);
SetDataSize(22); // 6 groups * 6 chars per group * 5 bits per char - 158 signature size = 22 data size
SetValidationDataSize(0);
m_hasPrivateKey = false;
}
void SetPrivateKey(const void * keyBuf, int keyLen)
{
ValidatePrivateKey(keyBuf, keyLen);
m_signingKey.reset(new Key(keyBuf, keyLen));
m_hasPrivateKey = true;
}
void ValidatePrivateKey(const void * keyBuf, int keyLen)
{
if (keyLen <= 2)
{
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid private key length");
}
keyLen -= 2;
keyBuf = (unsigned char *)keyBuf + 2;
if (!SDKRegistrationImpl::IsRegistered())
{
if (keyLen != m_demoPrivateKeys[m_signatureKeyType][0] || memcmp(keyBuf, &m_demoPrivateKeys[m_signatureKeyType][1], keyLen) != 0)
{
m_signingKey.reset();
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid public/private key. The SDK is in DEMO mode because a SDK license key was not set. In this mode, only certain public/private keys can be set. Did you set a valid SDK license key via ANSCENTER::Licensing::SDKRegistration::SetLicenseKey() ?");
}
}
}
void ValidateCertificate()
{
unique_ptr<Certificate> validationCertificate = make_unique<Certificate>("AE4vDQELjMGgCJew5QSVMBWSAN2PaBa0zzYpjSYe0rcu88lYggE=");
if (!Certificate::VerifySignature(m_certificate.get(), validationCertificate.get()))
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signature is not valid");
}
};

File diff suppressed because it is too large Load Diff

1968
core/anslicensing/tinyxml2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
#pragma once
#include <stdexcept>
#include <string>
using namespace std;
#ifdef _WIN32
inline wstring s2w(const char* str, size_t size = -1)
{
if (size == -1)
size = strlen(str);
if (size == 0)
return wstring();
size_t req_size = ::MultiByteToWideChar(CP_UTF8, 0,
str, (int)size, NULL, 0);
if (req_size == 0)
throw runtime_error("Failed converting UTF-8 string to UTF-16");
wstring wstr(req_size, 0);
int conv_size = ::MultiByteToWideChar(CP_UTF8, 0,
str, (int)size, wstr.data(), req_size);
if (conv_size == 0)
throw runtime_error("Failed converting UTF-8 string to UTF-16");
return wstr;
}
inline wstring s2w(const string& str)
{
return s2w(str.data(), str.size());
}
inline string w2s(const wchar_t* wstr, size_t size = -1)
{
size_t req_size = WideCharToMultiByte(CP_UTF8, 0, wstr, size, nullptr, 0, nullptr, nullptr);
if (!req_size)
throw runtime_error("wide to multibyte conversion failed");
string str(req_size, 0);
int conv_size = WideCharToMultiByte(CP_UTF8, 0L, wstr, size, str.data(), req_size, nullptr, nullptr);
if (!conv_size)
throw runtime_error("wide to multibyte conversion failed");
return str;
}
inline string w2s(const wstring& wstr)
{
return w2s(wstr.data(), wstr.size());
}
#else
inline wstring s2w(const char* str, size_t size = -1)
{
throw runtime_error("not implemented");
}
inline wstring s2w(const string& str)
{
return s2w(str.data(), str.size());
}
inline string w2s(const wchar_t* wstr, size_t size = -1)
{
throw runtime_error("not implemented");
}
inline string w2s(const wstring& wstr)
{
return w2s(wstr.data(), wstr.size());
}
#endif

View File

@@ -0,0 +1,205 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "anslicensing.h"
#include "template.h"
#include "bitstream.h"
#include "base32.h"
#include "base64.h"
#include "sha1.h"
#include "except.h"
#include "uniconv.h"
#include "validator.h"
namespace ANSCENTER {
namespace Licensing {
template<>
KeyValidatorT<char>::KeyValidatorT():
m_Impl( *new KeyValidatorImpl() )
{
}
template<>
KeyValidatorT<wchar_t>::KeyValidatorT():
m_Impl( *new KeyValidatorImpl() )
{
}
template<>
KeyValidatorT<char>::KeyValidatorT(const LicenseTemplateT<char> * keyTemplate):
m_Impl( *new KeyValidatorImpl(&keyTemplate->m_Impl) )
{
}
template<>
KeyValidatorT<wchar_t>::KeyValidatorT(const LicenseTemplateT<wchar_t> * keyTemplate):
m_Impl( *new KeyValidatorImpl(&keyTemplate->m_Impl) )
{
}
template<>
KeyValidatorT<char>::~KeyValidatorT()
{
delete & m_Impl;
}
template<>
KeyValidatorT<wchar_t>::~KeyValidatorT()
{
delete & m_Impl;
}
template<>
KeyValidatorT<char> * KeyValidatorT<char>::Create()
{
return new KeyValidatorT<char>();
}
template<>
KeyValidatorT<wchar_t> * KeyValidatorT<wchar_t>::Create()
{
return new KeyValidatorT<wchar_t>();
}
template<>
void KeyValidatorT<char>::Destroy(KeyValidatorT<char> * obj)
{
delete obj;
}
template<>
void KeyValidatorT<wchar_t>::Destroy(KeyValidatorT<wchar_t> * obj)
{
delete obj;
}
template<>
void KeyValidatorT<char>::SetKeyTemplate(const LicenseTemplateT<char> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
void KeyValidatorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
void KeyValidatorT<char>::SetValidationData(const char * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(fieldName, buf, len);
}
template<>
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), buf, len);
}
template<>
void KeyValidatorT<char>::SetValidationData(const char * fieldName, const char * data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const wchar_t * data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), w2s(data).c_str());
}
template<>
void KeyValidatorT<char>::SetValidationData(const char * fieldName, int data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, int data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), data);
}
template<>
void KeyValidatorT<char>::SetKey(const char * key)
{
m_Impl.SetKey(key);
}
template<>
void KeyValidatorT<wchar_t>::SetKey(const wchar_t * key)
{
m_Impl.SetKey(w2s(key).c_str());
}
template<>
bool KeyValidatorT<char>::IsKeyValid()
{
return m_Impl.IsKeyValid();
}
template<>
bool KeyValidatorT<wchar_t>::IsKeyValid()
{
return m_Impl.IsKeyValid();
}
template<>
void KeyValidatorT<char>::QueryKeyData(const char * dataField, void * buf, int * len)
{
m_Impl.QueryKeyData(dataField, buf, len);
}
template<>
void KeyValidatorT<wchar_t>::QueryKeyData(const wchar_t * dataField, void * buf, int * len)
{
m_Impl.QueryKeyData(w2s(dataField).c_str(), buf, len);
}
template<>
int KeyValidatorT<char>::QueryIntKeyData(const char * dataField)
{
return m_Impl.QueryIntKeyData(dataField);
}
template<>
int KeyValidatorT<wchar_t>::QueryIntKeyData(const wchar_t * dataField)
{
return m_Impl.QueryIntKeyData(w2s(dataField).c_str());
}
template<>
void KeyValidatorT<char>::QueryDateKeyData(const char * dataField, int * year, int * month, int * day)
{
m_Impl.QueryDateKeyData(dataField, year, month, day);
}
template<>
void KeyValidatorT<wchar_t>::QueryDateKeyData(const wchar_t * dataField, int * year, int * month, int * day)
{
m_Impl.QueryDateKeyData(w2s(dataField).c_str(), year, month, day);
}
template<>
void KeyValidatorT<char>::QueryValidationData(const char * dataField, void * buf, int * len)
{
m_Impl.QueryValidationData(dataField, buf, len);
}
template<>
void KeyValidatorT<wchar_t>::QueryValidationData(const wchar_t * dataField, void * buf, int * len)
{
m_Impl.QueryValidationData((dataField) ? w2s(dataField).c_str() : NULL, buf, len);
}
};
};

View File

@@ -0,0 +1,224 @@
#pragma once
#include <memory>
#include "bitstream.h"
#include "base64.h"
#include "base32.h"
#ifdef _WIN32
#include <tchar.h>
#endif
using namespace std;
class KeyValidatorImpl {
public:
KeyValidatorImpl()
{
}
KeyValidatorImpl(const LicenseTemplateImpl* templ, const char * key = NULL)
{
SetKeyTemplate(templ);
if (key)
SetKey(key);
}
~KeyValidatorImpl()
{
}
void SetKeyTemplate(const LicenseTemplateImpl* templ)
{
m_keyTemplate = templ;
if (templ->m_validationDataSize)
{
m_validationData.Create(templ->m_validationDataSize);
for (const auto& field : m_keyTemplate->m_validationFields)
m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
}
else
m_validationData.Create(0);
}
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);
}
void SetValidationData(const char * fieldName, int year, int month, int day)
{
m_validationData.Set(fieldName, year, month, day);
}
void SetKey(const char * licKey)
{
if (!licKey)
throw new LicensingException(STATUS_INVALID_PARAM, "invalid license key");
string key(licKey);
if (key.length() < m_keyTemplate->GetCharactersPerGroup() * m_keyTemplate->GetNumberOfGroups() +
strlen(m_keyTemplate->GetHeader()) +
strlen(m_keyTemplate->GetFooter()) +
strlen(m_keyTemplate->GetGroupSeparator()) * (m_keyTemplate->GetNumberOfGroups() - 1))
{
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "invalid license key (too short)");
}
// remove header and footer (if any)
if (!m_keyTemplate->m_header.empty())
{
key.erase(0, m_keyTemplate->m_header.length() + 2);
}
if (!m_keyTemplate->m_footer.empty())
{
key.erase(key.length() - m_keyTemplate->m_footer.length() - 2, m_keyTemplate->m_footer.length() + 2);
}
// ungroup license key
for (int i = 0, erasePos = 0; i < m_keyTemplate->m_numGroups - 1; i++)
{
erasePos += m_keyTemplate->m_charsPerGroup;
key.erase(erasePos, m_keyTemplate->m_groupSeparator.length());
}
// decode license key
switch ( m_keyTemplate->m_keyEncoding )
{
case ENCODING_BASE32X:
{
BASE32 base32;
int padLen;
int len = base32.encode_pad_length(((int)key.length() * 5 + 7) >> 3, &padLen);
if (len > (int)key.length())
key.append(len - key.length(), 'A');
if (padLen)
key.append(padLen,'=');
auto keyBuf = base32.decode(key.c_str(), (int)key.length(), &len );
if (keyBuf.empty())
throw new LicensingException(STATUS_INVALID_LICENSE_KEY);
// reverse last byte
keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups);
}
break;
case ENCODING_BASE64X:
{
BASE64 base64;
int padLen;
int len = base64.encode_pad_length(((int)key.length() * 6 + 7) >> 3, &padLen);
if (len > (int)key.length())
key.append(len - key.length(), 'A');
if (padLen)
key.append(padLen,'=');
auto keyBuf = base64.decode(key.c_str(), (int)key.length(), &len );
if (keyBuf.empty())
throw new LicensingException(STATUS_INVALID_LICENSE_KEY);
// reverse last byte
keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups);
}
break;
default:
throw new LicensingException(STATUS_INVALID_KEY_ENCODING);
}
for (const auto& field : m_keyTemplate->m_dataFields)
m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
}
bool IsKeyValid()
{
ECC::Verifier verifier;
BitStream signedData,
signature;
signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize);
signedData.Clear();
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);
signature.Create(m_keyTemplate->m_signatureSize);
m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize);
m_keyData.GetBitStream().Read(signature.GetBuffer(), m_keyTemplate->m_signatureSize);
signature.ReleaseBuffer(m_keyTemplate->m_signatureSize);
signature.Seek(m_keyTemplate->m_signatureSize);
signature.ZeroPadToNextByte();
signature.ReleaseBuffer(m_keyTemplate->m_signatureSize);
// 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))
verifier.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize);
else
verifier.SetHashSize(0);
verifier.SetPublicKey(m_keyTemplate->m_verificationKey.get());
return verifier.Verify(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3, signature.GetBuffer(), (signature.GetSize() + 7) >> 3 , m_keyTemplate->m_signatureSize);
}
void QueryKeyData(const char * fieldName, void * buf, int * len)
{
m_keyData.Get(fieldName, buf, len);
}
int QueryIntKeyData(const char * fieldName)
{
return m_keyData.GetInt(fieldName);
}
void QueryDateKeyData(const char * fieldName, int * year, int * month, int * day)
{
m_keyData.GetDate(fieldName, year, month, day);
}
void QueryValidationData(const char * fieldName, void * buf, int * len)
{
return m_validationData.Get(fieldName, buf, len);
}
public:
const LicenseTemplateImpl* m_keyTemplate;
BitStruct m_keyData;
BitStruct m_validationData;
};

View File

@@ -0,0 +1,6 @@
#pragma once
#define VERSION_MAJOR 3
#define VERSION_MINOR 9
#define VERSION_BUILD 52
#define BUILD_TIMESTAMP 1479947203

View File

@@ -0,0 +1,209 @@
#pragma once
#define _WIN32_DCOM
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>
#include <list>
#include <string>
#include "uniconv.h"
#pragma comment(lib, "wbemuuid.lib")
using namespace std;
class WmiHelper
{
public:
WmiHelper()
{
HRESULT hres;
wbemServices = NULL;
wbemLocator = NULL;
ownCoInitialize = false;
// Initialize COM.
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (hres == S_OK)
{
ownCoInitialize = true;
}
// Initialize
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &wbemLocator);
if (FAILED(hres))
{
if (ownCoInitialize)
CoUninitialize();
throw new exception("failed to create IWbemLocator", hres);
}
// Connect to the root\cimv2 namespace with the
// current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = wbemLocator->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
NULL, // User name
NULL, // User password
0, // Locale
NULL, // Security flags
0, // Authority
0, // Context object
&wbemServices // IWbemServices proxy
);
if (FAILED(hres))
{
wbemLocator->Release();
if (ownCoInitialize)
CoUninitialize();
throw new exception("could not connect to WMI", hres);
}
// Set the IWbemServices proxy so that impersonation
// of the user (client) occurs.
hres = CoSetProxyBlanket(
wbemServices, // the proxy to set
RPC_C_AUTHN_WINNT, // authentication service
RPC_C_AUTHZ_NONE, // authorization service
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
wbemServices->Release();
wbemLocator->Release();
if (ownCoInitialize) CoUninitialize();
throw new exception("could not connecto to WMI", hres);
}
}
~WmiHelper()
{
if (wbemServices) wbemServices->Release();
if (wbemLocator) wbemLocator->Release();
if (ownCoInitialize) CoUninitialize();
}
void GetPropertyList(const char * wqlQuery, const char * propertyName, list<string> * propList, int maxElements = 0x7FFFFFFF)
{
HRESULT hres;
// For example, query for all the running processes
IEnumWbemClassObject* pEnumerator = NULL;
hres = wbemServices->ExecQuery(
bstr_t("WQL"),
bstr_t(wqlQuery),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
throw new exception("WMI query failed");
}
else
{
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
int numElements = 0;
while (1)
{
hres = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
VariantInit(&vtProp);
// Get the value of the Name property
hres = pclsObj->Get(_bstr_t(propertyName), 0, &vtProp, 0, 0);
//
if (SUCCEEDED(hres))
{
switch (vtProp.vt)
{
case VT_BSTR:
propList->push_back(w2s(vtProp.bstrVal).c_str());
numElements++;
break;
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_I4:
case VT_UI4:
{
char strVal[32];
_itoa(vtProp.intVal, strVal, 10);
propList->push_back(strVal);
numElements++;
}
break;
case VT_I8:
case VT_UI8:
{
char strVal[32];
_i64toa(vtProp.llVal, strVal, 10);
propList->push_back(strVal);
numElements++;
}
break;
default:
break;
}
VariantClear(&vtProp);
}
pclsObj->Release();
if (numElements >= maxElements)
break;
}
pEnumerator->Release();
}
}
private:
bool ownCoInitialize;
IWbemServices * wbemServices;
IWbemLocator * wbemLocator;
};