184 lines
3.7 KiB
C
184 lines
3.7 KiB
C
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "h.h"
|
|
|
|
static bool
|
|
overflow15(uint32_t a, uint32_t b)
|
|
{
|
|
return (a + b > 0x7FFF);
|
|
}
|
|
|
|
static char *
|
|
mnsnc(const char *s)
|
|
{
|
|
static char buf[3];
|
|
uint16_t a;
|
|
uint16_t flag;
|
|
int c = s[8] % 16;
|
|
|
|
for (a = 0; *s != '\0'; ++s) {
|
|
if (overflow15(a, *s))
|
|
flag = 1;
|
|
else
|
|
flag = 0;
|
|
a = flag | (2 * (a + *s));
|
|
}
|
|
|
|
for (; c > 0; --c)
|
|
a = ((a & 0x8000U) >> 15) | (uint16_t)(2 * a);
|
|
|
|
buf[2] = 0;
|
|
buf[1] = a % 26 + 'a';
|
|
a /= 26;
|
|
buf[0] = a % 26 + 'a';
|
|
|
|
return buf;
|
|
}
|
|
|
|
static void
|
|
strbn(char *out, unsigned int in)
|
|
{
|
|
static const char *alphabet = "abcdefghijklmnopqrstuvwxyz";
|
|
size_t i;
|
|
|
|
for (i = 3; i > 0; --i) {
|
|
out[i - 1] = alphabet[in % 26];
|
|
in /= 26;
|
|
}
|
|
}
|
|
|
|
static void
|
|
decfrp(char *s)
|
|
{
|
|
char *p;
|
|
unsigned char a, b;
|
|
|
|
a = b = 0;
|
|
|
|
for (p = s + strlen(s) - 1; p >= s; --p) {
|
|
a = (*p - 'a' + b) % 26;
|
|
a = (a + 'a') & 0xFF;
|
|
b += a;
|
|
b %= 26;
|
|
*p = a;
|
|
}
|
|
}
|
|
|
|
/* Implementation of xorshift* without retaining seed state. */
|
|
static uint64_t
|
|
rnd(uint64_t seed)
|
|
{
|
|
seed ^= seed >> 12;
|
|
seed ^= seed << 25;
|
|
seed ^= seed >> 27;
|
|
return seed * 0x2545F4914F6CDD1D;
|
|
}
|
|
|
|
static unsigned int
|
|
mkver(unsigned int lictype, unsigned int major, unsigned int minor)
|
|
{
|
|
return ((lictype << 12) | (major * 10 + minor));
|
|
}
|
|
|
|
static void
|
|
mksnak(bool has_snakext, uint16_t product_id, uint16_t major, uint16_t minor,
|
|
char *serno, char *actkey)
|
|
{
|
|
const char *cksum;
|
|
uint64_t serial;
|
|
unsigned int version = mkver((has_snakext ? 3 : 2), major, minor);
|
|
char merged[18];
|
|
|
|
memset(serno, 0, 10);
|
|
memset(actkey, 0, 9);
|
|
#ifdef DBG
|
|
printf("has_snakext: %d, major: %u, minor: %u, version: %u\n",
|
|
!!has_snakext, major, minor, version);
|
|
#endif
|
|
|
|
/* bitmask to ensure at most six digits */
|
|
serial = rnd((uintptr_t)serno * time(NULL)) & 0xEFFFF;
|
|
snprintf(serno, 10, "SCO%06" PRIu64, serial);
|
|
|
|
strbn(actkey, product_id);
|
|
strbn(actkey + 3, version);
|
|
snprintf(merged, sizeof(merged), "%s%s", serno, actkey);
|
|
|
|
cksum = mnsnc(merged);
|
|
actkey[6] = cksum[0];
|
|
actkey[7] = cksum[1];
|
|
|
|
decfrp(actkey);
|
|
}
|
|
|
|
static uint16_t
|
|
strtou16lim(const char *in, unsigned long limit)
|
|
{
|
|
char *end;
|
|
unsigned long i;
|
|
|
|
if (limit > UINT16_MAX)
|
|
die("internal: limit > UINT16_MAX");
|
|
|
|
i = strtoul(in, &end, 10);
|
|
if (*in == '\0' || *end != '\0')
|
|
die("%s not a number", in);
|
|
if (i > limit)
|
|
die("%s out of range (max %"PRIu16")", in, limit);
|
|
|
|
return i;
|
|
}
|
|
|
|
int
|
|
gen_snak(int argc, char *argv[])
|
|
{
|
|
char *snakext = NULL;
|
|
uint16_t product_id, major, minor;
|
|
char serno[10], actkey[9], snakextmd[7];
|
|
|
|
if (argc < 3) {
|
|
usage(true);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* "zzz" is the maximum possible product ID encoded value.
|
|
* This decodes to a value of 17575.
|
|
*/
|
|
product_id = strtou16lim(argv[0], 17575);
|
|
|
|
/* License type (whether snakext is to be read), version major and
|
|
* version minor share an integer, max encoded as "zzz".
|
|
* The license type is shifted up by 12, leaving 0xFFF (4095) for the
|
|
* version major and minor.
|
|
* Of that, the version major is all the upper digits, and the minor is
|
|
* the bottom digit (i.e. version/10 => major, version%10 => minor).
|
|
*
|
|
* Without doing too much checking, the maximum major version is 409 and
|
|
* the maximum minor version is 9.
|
|
*/
|
|
major = strtou16lim(argv[1], 409);
|
|
minor = strtou16lim(argv[2], 9);
|
|
|
|
if (argc >= 4)
|
|
snakext = argv[3];
|
|
|
|
mksnak(snakext != NULL, product_id, major, minor, serno, actkey);
|
|
printf("Serial number: %s\n"
|
|
"Activation key: %s\n", serno, actkey);
|
|
|
|
if (snakext != NULL) {
|
|
mdsnakext(serno, actkey, snakext, snakextmd);
|
|
printf("License data: %s;m%s\n", snakext, snakextmd);
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|