So here it is:
//
// Copyright (c) 2014 RIGLOL Technologies, Inc. All Rights Reversed.
// This product includes software developed by the OpenSSL Project
// for use in the OpenSSL Toolkit. (http://www.openssl.org/)
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "rc5.h"
extern "C"
{
#include "miracl.h"
}
// ECC parameters
char A[] = "2982";
char B[] = "3408";
char P[] = "AEBF94CEE3E707";
char N[] = "AEBF94D5C6AA71";
char Gx[] = "7A3E808599A525";
char Gy[] = "28BE7FAFD2A052";
typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned long long uint64;
#define LICENSE_CODE_LENGTH 28
// sample key sets for different scopes
#if 1
// DS2D1542....
static const uint8 RC5Key1[16] = { 0x3F, 0x57, 0x8E, 0x1C, 0x44, 0x18, 0x34, 0xDD, 0xA5, 0x46, 0x21, 0x36, 0x32, 0x81, 0xFB, 0xCF };
static const uint8 RC5Key2[16] = { 0x14, 0xDC, 0x15, 0xAF, 0xA1, 0x48, 0x3D, 0x7D, 0x6A, 0xC1, 0xDC, 0xA1, 0x79, 0x8D, 0xAA, 0x3E };
static const uint8 XXTEAKey[16] = { 0x39, 0x69, 0xA2, 0x04, 0x55, 0x9C, 0x35, 0x52, 0x90, 0x44, 0xED, 0x85, 0x52, 0x16, 0x13, 0x32 };
char ECCPublicKey[] = "A51BF373712F7D";
#else
// DS2D1543....
static const uint8 RC5Key1[16] = { 0x41, 0x55, 0xBF, 0xD8, 0x2D, 0x42, 0x9E, 0xA6, 0x9B, 0x3E, 0xE7, 0xD7, 0xD5, 0x9C, 0x89, 0x06 };
static const uint8 RC5Key2[16] = { 0xB9, 0xBC, 0x53, 0xD8, 0xB8, 0xCE, 0x6C, 0xE3, 0x59, 0x45, 0x55, 0xAA, 0x89, 0x55, 0x65, 0x43 };
static const uint8 XXTEAKey[16] = { 0x86, 0xF4, 0xA0, 0x93, 0x0B, 0xC7, 0xED, 0x27, 0x6B, 0x2D, 0x6C, 0x2C, 0xE2, 0x93, 0x53, 0x5F };
char ECCPublicKey[] = "A0581020E5C012";
#endif
uint32 DecodeChar(char value)
{
char *charMap = "LRE8YFGHJK9SNBQ36MPVWXAZ2U45TC7D";
char *charPos = strchr(charMap, value);
return charPos == NULL ? 0 : charPos - charMap;
}
uint64 DecodeSignature(uint64 value)
{
uint32 shiftCount = value & 0x0f;
do value >>= 4; while(shiftCount-- > 0);
return value;
}
uint32 DecodeLicenseCode(char *licenseCode, uint64& sig1, uint64& sig2)
{
if(strlen(licenseCode) != LICENSE_CODE_LENGTH)
return 0;
uint8 licenseBits[35];
for(int i = 0, j = 0; i < LICENSE_CODE_LENGTH; i += 4, j += 5)
{
uint32 bitBuffer =
(DecodeChar(licenseCode[i]) << 15) +
(DecodeChar(licenseCode[i+1]) << 10) +
(DecodeChar(licenseCode[i+2]) << 5) +
DecodeChar(licenseCode[i+3]);
licenseBits[j] = bitBuffer >> 16;
licenseBits[j+1] = (bitBuffer >> 12) & 0xf;
licenseBits[j+2] = (bitBuffer >> 8) & 0xf;
licenseBits[j+3] = (bitBuffer >> 4) & 0xf;
licenseBits[j+4] = bitBuffer & 0xf;
}
uint64 RC5Block1 = 0;
uint64 RC5Block2 = 0;
for(int i = 0; i < 16; i++)
{
RC5Block1 |= uint64(licenseBits[i]) << i*4;
RC5Block2 |= uint64(licenseBits[i + 16]) << i*4;
}
RC5_32_KEY RC5Key;
RC5_32_set_key(&RC5Key, 16, RC5Key1, 16);
RC5_32_ecb_encrypt((uint8*)&RC5Block1, (uint8*)&RC5Block1, &RC5Key, 1);
RC5_32_set_key(&RC5Key, 16, RC5Key2, 16);
RC5_32_ecb_encrypt((uint8*)&RC5Block2, (uint8*)&RC5Block2, &RC5Key, 0);
// ECDSA signature
sig1 = DecodeSignature((RC5Block2 >> 8) | (uint64(licenseBits[33]) << 56));
sig2 = DecodeSignature(((RC5Block1 & 0xffffffffffff) << 8) | (RC5Block2 & 0xff) | (uint64(licenseBits[32]) << 56));
// option bits
return uint32(RC5Block1 >> 48) | (uint32(licenseBits[34]) << 16);
}
char* EncodeOptionBits(uint32 optionBits)
{
char *charMap = "XBCNEF8HJ3LMKPZRSAUVWTYQ5D4276G9";
char *optionString = new char[5];
for(int i = 0; i < 4; i++)
optionString[i] = charMap[(optionBits >> ((3-i)*5)) & 0x1f];
optionString[4] = '\0';
return optionString;
}
char* EncodeSerialNumber(char *serialNumber)
{
if(strlen(serialNumber) < 4)
return 0;
uint32 header = *((uint32*)serialNumber);
for(int i = 0; i < 16; i++)
header =
(header << 1) |
(header >> 31) ^
(header >> 30) & 1 ^
(header >> 28) & 1 ^
(header >> 22) & 1 ^
(header >> 13) & 1 ^
(header >> 6) & 1;
char* result = strdup(serialNumber);
*((uint32*)result) = header;
return result;
}
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void XXTEA(uint32 *v, int n, uint32 const key[4])
{
uint32 y, z, sum;
unsigned p, rounds, e;
if (n > 1)
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
} while (--rounds);
}
else if (n < -1)
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
} while ((sum -= DELTA) != 0);
}
}
uint64 ByteSwap64(uint64 value)
{
uint64 result = 0;
for(int i = 0; i < 8; i++)
{
result = (result << 8) | (value & 0xff);
value >>= 8;
}
return result;
}
bool VerifySignature(uint64 sig1, uint64 sig2, uint8 signatureDataHash[20])
{
mirsys(0x320, 16)->IOBASE = 16;
big p = mirvar(0);
big n = mirvar(0);
big a = mirvar(0);
big b = mirvar(0);
big x = mirvar(0);
big y = mirvar(0);
big lic1 = mirvar(0);
big lic2 = mirvar(0);
big hash = mirvar(0);
big m1 = mirvar(0);
big m2 = mirvar(0);
big v = mirvar(0);
big g = mirvar(0);
epoint *pt1 = epoint_init();
epoint *pt2 = epoint_init();
instr(a, A);
instr(b, B);
instr(p, P);
instr(n, N);
ecurve_init(a, b, p, MR_PROJECTIVE);
instr(x, Gx);
instr(y, Gy);
if (!epoint_set(x, y, 0, pt1))
{
printf("ERR: Point G is invalid\n");
exit(-1);
}
instr(x, ECCPublicKey);
if (!epoint_set(x, x, 1, pt2))
{
printf("ERR: Public key is invalid\n");
exit(-1);
}
bytes_to_big(20, (char*)signatureDataHash, hash);
sig1 = ByteSwap64(sig1);
bytes_to_big(8, (char*)&sig1, lic1);
sig2 = ByteSwap64(sig2);
bytes_to_big(8, (char*)&sig2, lic2);
xgcd(lic2, n, lic2, lic2, lic2);
copy(lic2, g);
mad(hash, g, g, n, n, m1);
mad(lic1, g, g, n, n, m2);
ecurve_mult2(m1, pt1, m2, pt2, pt1);
epoint_get(pt1, v, v);
divide(v, n, n);
return mr_compare(v, lic1) == 0;
}
bool VerifyLicenseCode(char *serialNumber, char *licenseCode)
{
uint64 sig1, sig2;
uint32 optionBits = DecodeLicenseCode(licenseCode, sig1, sig2);
char *optionString = EncodeOptionBits(optionBits);
char *encodedSerialNumber = EncodeSerialNumber(serialNumber);
uint32 optionStringLength = strlen(optionString);
uint32 encodedSerialNumberLength = strlen(encodedSerialNumber);
uint32 signatureDataLength = (encodedSerialNumberLength + optionStringLength + 3) & ~3;
uint8 *signatureData = new uint8[signatureDataLength];
memset(signatureData, 0, signatureDataLength);
memcpy(signatureData, encodedSerialNumber, encodedSerialNumberLength);
memcpy(signatureData + encodedSerialNumberLength, optionString, optionStringLength);
XXTEA((uint32*)signatureData, signatureDataLength >> 2, (uint32*)XXTEAKey);
uint8 hash[20];
sha sh;
shs_init(&sh);
for(int i = 0; i < signatureDataLength; i++)
shs_process(&sh, signatureData[i]);
shs_hash(&sh, (char*)hash);
return VerifySignature(sig1, sig2, hash);
}