Add a simple license key: I take the CRC of the license info, plus

some magic numbers. This would be trivial to break, but still more
difficult than patching the binary to skip the check...

[git-p4: depot-paths = "//depot/solvespace/": change = 1853]
solver
Jonathan Westhues 2008-02-09 05:52:01 -08:00
parent 5a2803617b
commit 0c10efdab6
12 changed files with 362 additions and 71 deletions

View File

@ -39,7 +39,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
RES = $(OBJDIR)\resource.res RES = $(OBJDIR)\resource.res
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib \ LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib shell32.lib opengl32.lib glu32.lib \
extlib\libpng.lib extlib\zlib.lib extlib\libpng.lib extlib\zlib.lib
all: $(OBJDIR)/solvespace.exe all: $(OBJDIR)/solvespace.exe

View File

@ -1304,7 +1304,7 @@ for new users; to learn about this program, see the video tutorials.
<h2>Licensing</h2> <h2>Licensing</h2>
As downloaded, MechSketch does not include a license key. This means As downloaded, MechSketch does not include a license key. This means
that it cannot create files with more than seven groups. Larger files that it cannot create files with more than six groups. Larger files
may be opened, but not modified. This light version of MechSketch may be opened, but not modified. This light version of MechSketch
is intended for evaluation, but non-commercial / personal use is is intended for evaluation, but non-commercial / personal use is
also permitted. also permitted.

View File

@ -117,46 +117,46 @@ havepoly:
// Some software, like Adobe Illustrator, insists on a header. // Some software, like Adobe Illustrator, insists on a header.
fprintf(f, fprintf(f,
" 999\n" " 999\r\n"
"file created by SolveSpace\n" "file created by SolveSpace\r\n"
" 0\n" " 0\r\n"
"SECTION\n" "SECTION\r\n"
" 2\n" " 2\r\n"
"HEADER\n" "HEADER\r\n"
" 9\n" " 9\r\n"
"$ACADVER\n" "$ACADVER\r\n"
" 1\n" " 1\r\n"
"AC1006\n" "AC1006\r\n"
" 9\n" " 9\r\n"
"$INSBASE\n" "$INSBASE\r\n"
" 10\n" " 10\r\n"
"0.0\n" "0.0\r\n"
" 20\n" " 20\r\n"
"0.0\n" "0.0\r\n"
" 30\n" " 30\r\n"
"0.0\n" "0.0\r\n"
" 9\n" " 9\r\n"
"$EXTMIN\n" "$EXTMIN\r\n"
" 10\n" " 10\r\n"
"0.0\n" "0.0\r\n"
" 20\n" " 20\r\n"
"0.0\n" "0.0\r\n"
" 9\n" " 9\r\n"
"$EXTMAX\n" "$EXTMAX\r\n"
" 10\n" " 10\r\n"
"10000.0\n" "10000.0\r\n"
" 20\n" " 20\r\n"
"10000.0\n" "10000.0\r\n"
" 0\n" " 0\r\n"
"ENDSEC\n"); "ENDSEC\r\n");
// Now begin the entities, which are just line segments reproduced from // Now begin the entities, which are just line segments reproduced from
// our piecewise linear curves. // our piecewise linear curves.
fprintf(f, fprintf(f,
" 0\n" " 0\r\n"
"SECTION\n" "SECTION\r\n"
" 2\n" " 2\r\n"
"ENTITIES\n"); "ENTITIES\r\n");
int i, j; int i, j;
for(i = 0; i < sp->l.n; i++) { for(i = 0; i < sp->l.n; i++) {
@ -172,22 +172,22 @@ havepoly:
double s = SS.exportScale; double s = SS.exportScale;
fprintf(f, fprintf(f,
" 0\n" " 0\r\n"
"LINE\n" "LINE\r\n"
" 8\n" // Layer code " 8\r\n" // Layer code
"%d\n" "%d\r\n"
" 10\n" // xA " 10\r\n" // xA
"%.6f\n" "%.6f\r\n"
" 20\n" // yA " 20\r\n" // yA
"%.6f\n" "%.6f\r\n"
" 30\n" // zA " 30\r\n" // zA
"%.6f\n" "%.6f\r\n"
" 11\n" // xB " 11\r\n" // xB
"%.6f\n" "%.6f\r\n"
" 21\n" // yB " 21\r\n" // yB
"%.6f\n" "%.6f\r\n"
" 31\n" // zB " 31\r\n" // zB
"%.6f\n", "%.6f\r\n",
0, 0,
e0.x/s, e0.y/s, 0.0, e0.x/s, e0.y/s, 0.0,
e1.x/s, e1.y/s, 0.0); e1.x/s, e1.y/s, 0.0);
@ -195,10 +195,10 @@ havepoly:
} }
fprintf(f, fprintf(f,
" 0\n" " 0\r\n"
"ENDSEC\n" "ENDSEC\r\n"
" 0\n" " 0\r\n"
"EOF\n" ); "EOF\r\n" );
spa.Clear(); spa.Clear();
fclose(f); fclose(f);

View File

@ -7,6 +7,7 @@
#define mFile (&SolveSpace::MenuFile) #define mFile (&SolveSpace::MenuFile)
#define mGrp (&Group::MenuGroup) #define mGrp (&Group::MenuGroup)
#define mAna (&SolveSpace::MenuAnalyze) #define mAna (&SolveSpace::MenuAnalyze)
#define mHelp (&SolveSpace::MenuHelp)
#define S 0x100 #define S 0x100
#define C 0x200 #define C 0x200
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
@ -101,11 +102,11 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "&Stop Tracing...\tCtrl+Shift+S", MNU_STOP_TRACING, 'S'|S|C,mAna }, { 1, "&Stop Tracing...\tCtrl+Shift+S", MNU_STOP_TRACING, 'S'|S|C,mAna },
{ 1, "Step &Dimension...\tCtrl+Shift+D", MNU_STEP_DIM, 'D'|S|C,mAna }, { 1, "Step &Dimension...\tCtrl+Shift+D", MNU_STEP_DIM, 'D'|S|C,mAna },
{ 0, "&Help", 0, NULL }, { 0, "&Help", 0, 0, NULL },
{ 1, "&Load License...", 0, NULL }, { 1, "&Load License...", MNU_LICENSE, 0, mHelp },
{ 1, NULL, 0, NULL }, { 1, NULL, 0, 0, NULL },
{ 1, "&Website / Manual", 0, NULL }, { 1, "&Website / Manual", MNU_WEBSITE, 0, mHelp },
{ 1, "&About", 0, NULL }, { 1, "&About", MNU_ABOUT, 0, mHelp },
{ -1 }, { -1 },
}; };

View File

@ -17,6 +17,14 @@ void Group::AddParam(IdList<Param,hParam> *param, hParam hp, double v) {
} }
void Group::MenuGroup(int id) { void Group::MenuGroup(int id) {
if(!SS.license.licensed && SS.group.n >= 7) {
Error("The free version of this software does not support more "
"than six groups.\r\n\r\n"
"To remove this restriction, please choose Help -> "
"Website / Manual, and purchase a license.");
return;
}
Group g; Group g;
ZERO(&g); ZERO(&g);
g.visible = true; g.visible = true;

64
keygen.pl Normal file
View File

@ -0,0 +1,64 @@
#!/usr/bin/perl
$POLY = 0xedb88320;
sub ProcessBit {
my ($bit) = @_;
my $topWasSet = ($shiftReg & (1 << 31));
$shiftReg <<= 1;
if($bit) {
$shiftReg |= 1;
}
if($topWasSet) {
$shiftReg ^= $POLY;
}
}
sub ProcessByte {
my ($v) = @_;
for(0..7) {
ProcessBit($v & (1 << $_));
}
}
sub ProcessString {
my ($str) = @_;
for (split //, $str) {
if($_ ne "\n" and $_ ne "\r") {
ProcessByte(ord($_));
}
}
}
sub LicenseKey {
my @MAGIC = ( 203, 244, 134, 225, 45, 250, 70, 65,
224, 189, 35, 3, 228, 51, 77, 169, );
my $magic = join('', map { chr($_) } @MAGIC);
my ($line1, $line2, $users) = @_;
$shiftReg = 0;
ProcessString($line1);
ProcessString($line2);
ProcessString($users);
ProcessString($magic);
my $key = '±²³MechSketchLicense' . "\n";
$key .= $line1 . "\n";
$key .= $line2 . "\n";
$key .= $users . "\n";
$key .= sprintf("%08x\n", $shiftReg);
return $key;
}
$line1 = "Jonathan Westhues";
$line2 = "";
$users = "single-user license";
print LicenseKey($line1, $line2, $users);

View File

@ -2,7 +2,21 @@
SolveSpace SS; SolveSpace SS;
void SolveSpace::CheckLicenseFromRegistry(void) {
// First, let's see if we're running licensed or free
CnfThawString(license.line1, sizeof(license.line1), "LicenseLine1");
CnfThawString(license.line2, sizeof(license.line2), "LicenseLine2");
CnfThawString(license.users, sizeof(license.users), "LicenseUsers");
license.key = CnfThawDWORD(0, "LicenseKey");
license.licensed =
LicenseValid(license.line1, license.line2, license.users, license.key);
}
void SolveSpace::Init(char *cmdLine) { void SolveSpace::Init(char *cmdLine) {
CheckLicenseFromRegistry();
// Then, load the registry settings.
int i; int i;
// Default list of colors for the model material // Default list of colors for the model material
modelColor[0] = CnfThawDWORD(RGB(150, 150, 150), "ModelColor_0"); modelColor[0] = CnfThawDWORD(RGB(150, 150, 150), "ModelColor_0");
@ -431,14 +445,14 @@ void SolveSpace::MenuAnalyze(int id) {
case GraphicsWindow::MNU_STOP_TRACING: { case GraphicsWindow::MNU_STOP_TRACING: {
char exportFile[MAX_PATH] = ""; char exportFile[MAX_PATH] = "";
if(GetSaveFile(exportFile, CSV_EXT, CSV_PATTERN)) { if(GetSaveFile(exportFile, CSV_EXT, CSV_PATTERN)) {
FILE *f = fopen(exportFile, "w"); FILE *f = fopen(exportFile, "wb");
if(f) { if(f) {
int i; int i;
SContour *sc = &(SS.traced.path); SContour *sc = &(SS.traced.path);
for(i = 0; i < sc->l.n; i++) { for(i = 0; i < sc->l.n; i++) {
Vector p = sc->l.elem[i].p; Vector p = sc->l.elem[i].p;
double s = SS.exportScale; double s = SS.exportScale;
fprintf(f, "%.10f, %.10f, %.10f\n", fprintf(f, "%.10f, %.10f, %.10f\r\n",
p.x/s, p.y/s, p.z/s); p.x/s, p.y/s, p.z/s);
} }
fclose(f); fclose(f);
@ -457,3 +471,126 @@ void SolveSpace::MenuAnalyze(int id) {
} }
} }
void SolveSpace::Crc::ProcessBit(int bit) {
bool topWasSet = ((shiftReg & (1 << 31)) != 0);
shiftReg <<= 1;
if(bit) {
shiftReg |= 1;
}
if(topWasSet) {
shiftReg ^= POLY;
}
}
void SolveSpace::Crc::ProcessByte(BYTE b) {
int i;
for(i = 0; i < 8; i++) {
ProcessBit(b & (1 << i));
}
}
void SolveSpace::Crc::ProcessString(char *s) {
for(; *s; s++) {
if(*s != '\n' && *s != '\r') {
ProcessByte((BYTE)*s);
}
}
}
bool SolveSpace::LicenseValid(char *line1, char *line2, char *users, DWORD key)
{
BYTE magic[17] = {
203, 244, 134, 225, 45, 250, 70, 65,
224, 189, 35, 3, 228, 51, 77, 169,
0
};
crc.shiftReg = 0;
crc.ProcessString(line1);
crc.ProcessString(line2);
crc.ProcessString(users);
crc.ProcessString((char *)magic);
return (key == crc.shiftReg);
}
void SolveSpace::CleanEol(char *in) {
char *s;
s = strchr(in, '\r');
if(s) *s = '\0';
s = strchr(in, '\n');
if(s) *s = '\0';
}
void SolveSpace::LoadLicenseFile(char *filename) {
FILE *f = fopen(filename, "rb");
if(!f) {
Error("Couldn't open file '%s'", filename);
return;
}
char buf[100];
fgets(buf, sizeof(buf), f);
char *str = "±²³MechSketchLicense";
if(memcmp(buf, str, strlen(str)) != 0) {
fclose(f);
Error("This is not a license file,");
return;
}
char line1[512], line2[512], users[512];
fgets(line1, sizeof(line1), f);
CleanEol(line1);
fgets(line2, sizeof(line2), f);
CleanEol(line2);
fgets(users, sizeof(users), f);
CleanEol(users);
fgets(buf, sizeof(buf), f);
DWORD key = 0;
sscanf(buf, "%x", &key);
if(LicenseValid(line1, line2, users, key)) {
// Install the new key
CnfFreezeString(line1, "LicenseLine1");
CnfFreezeString(line2, "LicenseLine2");
CnfFreezeString(users, "LicenseUsers");
CnfFreezeDWORD(key, "LicenseKey");
Message("License key successfully installed.");
// This updates our display in the text window to show that we're
// licensed now.
CheckLicenseFromRegistry();
SS.later.showTW = true;
} else {
Error("License key invalid.");
}
fclose(f);
}
void SolveSpace::MenuHelp(int id) {
switch(id) {
case GraphicsWindow::MNU_WEBSITE:
OpenWebsite("http://www.mechsketch.com/helpmenu");
break;
case GraphicsWindow::MNU_ABOUT:
Message("This is MechSketch version 0.1.\r\n\r\n"
"For more information, see http://www.mechsketch.com/\r\n\r\n"
"Built " __TIME__ " " __DATE__ ".\r\n\r\n"
"Copyright 2008 Jonathan Westhues, All Rights Reserved.");
break;
case GraphicsWindow::MNU_LICENSE: {
char licenseFile[MAX_PATH] = "";
if(GetOpenFile(licenseFile, LICENSE_EXT, LICENSE_PATTERN)) {
SS.LoadLicenseFile(licenseFile);
}
break;
}
default: oops();
}
}

View File

@ -64,11 +64,16 @@ int SaveFileYesNoCancel(void);
#define DXF_EXT "dxf" #define DXF_EXT "dxf"
#define CSV_PATTERN "CSV File (*.csv)\0*.csv\0All Files (*)\0*\0\0" #define CSV_PATTERN "CSV File (*.csv)\0*.csv\0All Files (*)\0*\0\0"
#define CSV_EXT "csv" #define CSV_EXT "csv"
#define LICENSE_PATTERN \
"License File (*.license)\0*.license\0All Files (*)\0*\0\0"
#define LICENSE_EXT "license"
BOOL GetSaveFile(char *file, char *defExtension, char *selPattern); BOOL GetSaveFile(char *file, char *defExtension, char *selPattern);
BOOL GetOpenFile(char *file, char *defExtension, char *selPattern); BOOL GetOpenFile(char *file, char *defExtension, char *selPattern);
void GetAbsoluteFilename(char *file); void GetAbsoluteFilename(char *file);
void LoadAllFontFiles(void); void LoadAllFontFiles(void);
void OpenWebsite(char *url);
void CheckMenuById(int id, BOOL checked); void CheckMenuById(int id, BOOL checked);
void EnableMenuById(int id, BOOL checked); void EnableMenuById(int id, BOOL checked);
@ -92,6 +97,7 @@ void dbp(char *str, ...);
CO((tri).a), CO((tri).b), CO((tri).c)) CO((tri).a), CO((tri).b), CO((tri).c))
void SetWindowTitle(char *str); void SetWindowTitle(char *str);
void Message(char *str, ...);
void Error(char *str, ...); void Error(char *str, ...);
void ExitNow(void); void ExitNow(void);
@ -376,6 +382,7 @@ public:
// The platform-dependent code calls this before entering the msg loop // The platform-dependent code calls this before entering the msg loop
void Init(char *cmdLine); void Init(char *cmdLine);
void CheckLicenseFromRegistry(void);
void Exit(void); void Exit(void);
// File load/save routines, including the additional files that get // File load/save routines, including the additional files that get
@ -464,6 +471,29 @@ public:
bool generateAll; bool generateAll;
} later; } later;
void DoLater(void); void DoLater(void);
// For the licensing
class Crc {
public:
static const DWORD POLY = 0xedb88320;
DWORD shiftReg;
void ProcessBit(int bit);
void ProcessByte(BYTE b);
void ProcessString(char *s);
};
Crc crc;
struct {
bool licensed;
char line1[512];
char line2[512];
char users[512];
DWORD key;
} license;
static void MenuHelp(int id);
void CleanEol(char *s);
void LoadLicenseFile(char *filename);
bool LicenseValid(char *line1, char *line2, char *users, DWORD key);
}; };
extern SolveSpace SS; extern SolveSpace SS;

View File

@ -98,6 +98,9 @@ void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
void TextWindow::ScreenShowConfiguration(int link, DWORD v) { void TextWindow::ScreenShowConfiguration(int link, DWORD v) {
SS.TW.GoToScreen(SCREEN_CONFIGURATION); SS.TW.GoToScreen(SCREEN_CONFIGURATION);
} }
void TextWindow::ScreenGoToWebsite(int link, DWORD v) {
OpenWebsite("http://www.mechsketch.com/txtlink");
}
void TextWindow::ShowListOfGroups(void) { void TextWindow::ShowListOfGroups(void) {
Printf(true, "%Ftactv show ok group-name%E"); Printf(true, "%Ftactv show ok group-name%E");
int i; int i;
@ -140,6 +143,22 @@ void TextWindow::ShowListOfGroups(void) {
&(TextWindow::ScreenShowGroupsSpecial)); &(TextWindow::ScreenShowGroupsSpecial));
Printf(false, " %Fl%Ls%fconfiguration%E", Printf(false, " %Fl%Ls%fconfiguration%E",
&(TextWindow::ScreenShowConfiguration)); &(TextWindow::ScreenShowConfiguration));
// Show license info
Printf(false, "");
if(SS.license.licensed) {
Printf(false, "%FtLicensed to:");
Printf(false, "%Fg %s", SS.license.line1);
if(strlen(SS.license.line2)) {
Printf(false, "%Fg %s", SS.license.line2);
}
Printf(false, "%Fg %s", SS.license.users);
} else {
Printf(false, "%Fx*** THIS SOFTWARE IS NOT LICENSED ***");
Printf(false, "%Fx eval / non-commercial use only");
Printf(false, "%Fx buy at %Fl%f%Llhttp://www.mechsketch.com/%E",
&ScreenGoToWebsite);
}
} }

View File

@ -11,6 +11,7 @@ const TextWindow::Color TextWindow::fgColors[] = {
{ 'r', RGB( 0, 0, 0) }, { 'r', RGB( 0, 0, 0) },
{ 'x', RGB(255, 20, 20) }, { 'x', RGB(255, 20, 20) },
{ 'i', RGB( 0, 255, 255) }, { 'i', RGB( 0, 255, 255) },
{ 'g', RGB(160, 160, 160) },
{ 0, 0 }, { 0, 0 },
}; };
const TextWindow::Color TextWindow::bgColors[] = { const TextWindow::Color TextWindow::bgColors[] = {

5
ui.h
View File

@ -130,6 +130,7 @@ public:
static void ScreenColor(int link, DWORD v); static void ScreenColor(int link, DWORD v);
static void ScreenShowConfiguration(int link, DWORD v); static void ScreenShowConfiguration(int link, DWORD v);
static void ScreenGoToWebsite(int link, DWORD v);
static void ScreenStepDimSteps(int link, DWORD v); static void ScreenStepDimSteps(int link, DWORD v);
static void ScreenStepDimFinish(int link, DWORD v); static void ScreenStepDimFinish(int link, DWORD v);
@ -224,6 +225,10 @@ public:
MNU_TRACE_PT, MNU_TRACE_PT,
MNU_STOP_TRACING, MNU_STOP_TRACING,
MNU_STEP_DIM, MNU_STEP_DIM,
// Help,
MNU_LICENSE,
MNU_WEBSITE,
MNU_ABOUT,
} MenuId; } MenuId;
typedef void MenuHandler(int id); typedef void MenuHandler(int id);
typedef struct { typedef struct {

View File

@ -1,4 +1,5 @@
#include <windows.h> #include <windows.h>
#include <shellapi.h>
#include <commctrl.h> #include <commctrl.h>
#include <commdlg.h> #include <commdlg.h>
#include <gl/gl.h> #include <gl/gl.h>
@ -55,25 +56,50 @@ void dbp(char *str, ...)
va_end(f); va_end(f);
} }
void Error(char *str, ...)
static void DoMessageBox(char *str, va_list f, BOOL error)
{ {
va_list f; char buf[1024*50];
char buf[1024];
va_start(f, str);
vsprintf(buf, str, f); vsprintf(buf, str, f);
va_end(f);
EnableWindow(GraphicsWnd, FALSE); EnableWindow(GraphicsWnd, FALSE);
EnableWindow(TextWnd, FALSE); EnableWindow(TextWnd, FALSE);
int flags;
if(error) {
flags = MB_OK | MB_ICONERROR;
} else {
flags = MB_OK | MB_ICONINFORMATION;
}
HWND h = GetForegroundWindow(); HWND h = GetForegroundWindow();
MessageBox(h, buf, "SolveSpace Error", MB_OK | MB_ICONERROR); MessageBox(h, buf, "SolveSpace", flags);
EnableWindow(TextWnd, TRUE); EnableWindow(TextWnd, TRUE);
EnableWindow(GraphicsWnd, TRUE); EnableWindow(GraphicsWnd, TRUE);
SetForegroundWindow(GraphicsWnd); SetForegroundWindow(GraphicsWnd);
} }
void Error(char *str, ...)
{
va_list f;
va_start(f, str);
DoMessageBox(str, f, TRUE);
va_end(f);
}
void Message(char *str, ...)
{
va_list f;
va_start(f, str);
DoMessageBox(str, f, FALSE);
va_end(f);
}
void OpenWebsite(char *url) {
ShellExecute(GraphicsWnd, "open", url, NULL, NULL, SW_SHOWNORMAL);
}
void ExitNow(void) { void ExitNow(void) {
PostQuitMessage(0); PostQuitMessage(0);
} }