#include "proboard.hpp" //************************************************************************** // // TELEGRAFIX CONFIDENTIAL // PROTECTED TRADE SECRETS // // The contents of this file are confidential materials of TeleGrafix // Communications, Inc. Use of this information is subject to the terms and // conditions set forth in the TeleGrafix software source code licensing // contract. // //************************************************************************** //########################################################################## // // Module file: SERIALIZ.C // // Last modified: 12/11/94 (Jeff Reeder) // Author(s): Jeff Reeder - 12/11/94 // // ------------------------------------------------------------------------- // // Copyright (c) 1992-95 TeleGrafix Communications, Inc. // All Rights Reserved // // ------------------------------------------------------------------------- // // REVISION HISTORY INFORMATION // // Version Date Description // ------------------------------------------------------------------ // // //########################################################################## #include #include #include #include #include #include #include //-------------------------------------------------------------------------- #define UNREG_STRING "(Unregistered copy)" #define SERIAL_NUMBER_LENGTH 17 #define USERNAME_LEN 31 #define DEFAULT_REGNAME "Name of Registered Owner here!" #define SERIAL_NUM_LEN 17 #define DEFAULT_SERIALNO "" #define SYSTEM_CODE_LEN 13 #define DEFAULT_SYSTEM_CODE "TELEGRAFIX\0\0" //--------------------- // Product Code defines //--------------------- #define PROBOARD_BBS "PB" #define PROBOARD_BBS_NAME "ProBoard BBS" //----------------- // Platform defines //----------------- #define PLATFORM_DOS 'D' #define PLATFORM_DOS_NAME "MS-DOS" //--------------- // Origin defines //--------------- #define ORIGIN_TELEGRFX '0' #define ORIGIN_TELEGRFX_NAME "TeleGrafix Corporate HQ" #define ORIGIN_TELEGRFX_COMP '1' #define ORIGIN_TELEGRFX_NAME_COMP "Free Upgrades" #define ORIGIN_TELEGRFX_GIF '2' #define ORIGIN_TELEGRFX_NAME_GIF "GIF edition" //------------- // Misc defines //------------- #define BASE_36 36 // Meganums are base 36 #define START_YEAR 1992 // The year TeleGrafix began #define MAX_SN_COUNTER 1285 // 1295 is ZZ in meganums, set to 1285 to prevent duplicate serial numbers (says Jeff) #define MAX_SN_YEARS 35 // Seconds / 2 #define MAX_SN_MONTHS 11 // Seconds / 2 #define MAX_SN_DAYS 31 // Number of 2 #define MAX_SN_HOURS 23 // Seconds / 2 #define MAX_SN_MINS 29 // Minutes / 2 #define MAX_SN_SECS 29 // Seconds / 2 #define MAX_SN_LENGTH 16 // Maximum length of a serial number static char regname_buf [ USERNAME_LEN ] = DEFAULT_REGNAME; static char serial_buf [ SERIAL_NUM_LEN ] = DEFAULT_SERIALNO; static char system_code_buf[ SYSTEM_CODE_LEN ] = DEFAULT_SYSTEM_CODE; enum regResults { registrationNone = 0, // Software is not registered registrationBad, // Illegal registration information registrationGood, // Software is fully registered }; static word crc_table_16[ 256 ] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; static word makeCRC16( word count, word crc, byte *buffer ) { byte *p = buffer; while ( count-- != 0 ) { crc = word( ( crc << 8 ) ^ crc_table_16[ ( crc >> 8 ) ^ *p++ ] ); } return crc; } byte *decryptData( byte *buf, short len, byte key ) { short i; byte c; byte shift = 0; byte iPrime; byte nKey; (void) shift; iPrime = 0x17; nKey = ( byte ) ~key; for ( i = 0; i < len; i++, key++, iPrime++, nKey++ ) { c = ( buf[ i ] ^ nKey ) ^ iPrime; // Get encrypted char //-------------------------------------------------------------- // Now let's do the bit shifting (rolling) to the left. We used // to do this in a loop, but doing it this way avoids the loop // overhead and speeds things up at the cost of slightly larger // code size. //-------------------------------------------------------------- shift = ( byte ) ( i & 0x07 ); if ( shift != 0 ) { c = ( byte ) ( ( c << shift ) | ( c >> ( 8 - shift ) ) ); } //----------------------------------- // Now let's perform the bit swapping //----------------------------------- c = ( byte ) ~( ( c >> 7 ) | ( c << 7 ) | ( ( c & 0x40 ) >> 5 ) | ( ( c & 0x02 ) << 5 ) | ( ( c & 0x20 ) >> 3 ) | ( ( c & 0x04 ) << 3 ) | ( ( c & 0x10 ) >> 1 ) | ( ( c & 0x08 ) << 1 ) ); buf[ i ] = ( byte ) ( ( c ^ key ) ^ 0x49 ); // Store real char in buf } return( buf ); } static byte *encryptData( byte *buf, short len, byte key ) { short i; byte c; byte shift = 0; byte iPrime; byte nKey; (void) shift; iPrime = 0x17; nKey = ( byte ) ~key; for ( i = 0; i < ( short ) len; i++, key++, iPrime++, nKey++ ) { //------------------ // Get the character //------------------ c = ( byte ) ( ( buf[ i ] ^ key ) ^ 0x49 ); //----------------------------------- // Now let's perform the bit swapping //----------------------------------- c = ( byte ) ~( ( c >> 7 ) | ( c << 7 ) | ( ( c & 0x40 ) >> 5 ) | ( ( c & 0x02 ) << 5 ) | ( ( c & 0x20 ) >> 3 ) | ( ( c & 0x04 ) << 3 ) | ( ( c & 0x10 ) >> 1 ) | ( ( c & 0x08 ) << 1 ) ); //---------------------------------------------------------------- // Now let's do the bit shifting (rolling) to the right. We used // to do this in a loop, but doing it this way eliminates the loop // code overhead and consequently speeds things up a bit. //---------------------------------------------------------------- shift = ( byte ) ( i & 0x07 ); if ( shift != 0 ) { c = ( byte ) ( ( c >> shift ) | ( c << ( 8 - shift ) ) ); } buf[ i ] = ( c ^ iPrime ) ^ nKey; } return( buf ); } static int isValidMegaNum( char iChar ) { if ( iChar >= '0' && iChar <= '9' ) { return 1; } else if ( isalpha( iChar ) ) { return 1; } else { return 0; } } static word serialNumberDecode( char *sBuf, word *piNodeCount ) { char pstrProductID[ 3 ]; byte iPlatformID; byte iOriginID; char buf[ 16 + 1 ]; char eBuf[ 16 + 1 ]; struct dosdate_t dt; struct dostime_t tm; word yearValue; word minValue; word secValue; char counterBuf[ 8 ]; char minuteBuf[ 8 ]; char dayBuf[ 8 ]; char secBuf[ 8 ]; char yearBuf[ 8 ]; char hourBuf[ 8 ]; char monthBuf[ 8 ]; char crcBuf[ 5 ]; word oldCRC; word newCRC; word iCounter; char P1; // Product Code byte 1 char P2; // Product Code byte 2 char Pl; // Platform char Or; // Origin char N1; // Numeric Counter byte 1 char N2; // Numeric Counter byte 2 char Yr; // Year char Mo; // Month char Dy; // Day char Hr; // Hour char Mi; // Minute/2 char Se; // Second/2 char R1; // CRC byte 1 char R2; // CRC byte 2 char R3; // CRC byte 3 char R4; // CRC byte 4 if ( piNodeCount ) { *piNodeCount = 2; } if ( strlen( sBuf ) != MAX_SN_LENGTH ) { //----------------------------- // Illegal serial number length //----------------------------- return( 0 ); } //------------------------------------------------------ // Assign buffer fields to our serial number field codes //------------------------------------------------------ R1 = sBuf[ 7 ]; R2 = sBuf[ 14 ]; R3 = sBuf[ 5 ]; R4 = sBuf[ 11 ]; P1 = sBuf[ 0 ]; P2 = sBuf[ 1 ]; Pl = sBuf[ 2 ]; Or = sBuf[ 3 ]; N2 = sBuf[ 4 ]; Mi = sBuf[ 6 ]; Dy = sBuf[ 8 ]; Se = sBuf[ 9 ]; Yr = sBuf[ 10 ]; Hr = sBuf[ 12 ]; N1 = sBuf[ 13 ]; Mo = sBuf[ 15 ]; crcBuf[ 0 ] = R1; crcBuf[ 1 ] = R2; crcBuf[ 2 ] = R3; crcBuf[ 3 ] = R4; crcBuf[ 4 ] = '\0'; //---------------------------------- // build buffer for encryption check //---------------------------------- buf[ 0 ] = P1; buf[ 1 ] = P2; buf[ 2 ] = Pl; buf[ 3 ] = Or; buf[ 4 ] = N2; buf[ 5 ] = Mi; buf[ 6 ] = Dy; buf[ 7 ] = Se; buf[ 8 ] = Yr; buf[ 9 ] = Hr; buf[ 10 ] = N1; buf[ 11 ] = Mo; buf[ 12 ] = '\0'; oldCRC = word( strtol( crcBuf, NULL, 16 ) ); strcpy( eBuf, buf ); encryptData( eBuf, strlen( eBuf ), 0 ); newCRC = makeCRC16( strlen( buf ), 0, eBuf ); sprintf( crcBuf, "%04x", newCRC ); strupr( crcBuf ); if ( toupper( P1 ) != 'P' || toupper( P2 ) != 'B' ) { //--------------------- // Invalid product code //--------------------- return( 0 ); } pstrProductID[ 0 ] = P1; // buf[ 0 ]; pstrProductID[ 1 ] = P2; // buf[ 1 ]; pstrProductID[ 2 ] = '\0'; iPlatformID = Pl; // buf[ 2 ]; iOriginID = Or; // buf[ 3 ]; counterBuf[ 0 ] = N1; // buf[ 10 ]; counterBuf[ 1 ] = N2; // buf[ 4 ]; counterBuf[ 2 ] = '\0'; minuteBuf[ 0 ] = Mi; // buf[ 5 ]; minuteBuf[ 1 ] = '\0'; dayBuf[ 0 ] = Dy; // buf[ 6 ]; dayBuf[ 1 ] = '\0'; secBuf[ 0 ] = Se; // buf[ 7 ]; secBuf[ 1 ] = '\0'; yearBuf[ 0 ] = Yr; // buf[ 8 ]; yearBuf[ 1 ] = '\0'; hourBuf[ 0 ] = Hr; // buf[ 9 ]; hourBuf[ 1 ] = '\0'; monthBuf[ 0 ] = Mo; // buf[ 11 ]; monthBuf[ 1 ] = '\0'; if ( not isxdigit( R1 ) or not isxdigit( R2 ) or not isxdigit( R3 ) or not isxdigit( R4 ) ) { //------------------------------------ // Illegal CRC value - not hexadecimal //------------------------------------ return( 0 ); } else if ( newCRC != oldCRC ) { //----------------------- // CRC values don't match //----------------------- return( 0 ); } else if ( not isupper( iPlatformID ) ) { //-------------------- // Illegal platform ID //-------------------- return( 0 ); } else if ( not isValidMegaNum( iOriginID ) ) { //------------------ // Illegal origin ID //------------------ return( 0 ); } else if ( not isValidMegaNum( counterBuf[ 0 ] ) or not isValidMegaNum( counterBuf[ 1 ] ) ) { //---------------------- // Illegal counter value //---------------------- return( 0 ); } else if ( not isValidMegaNum( yearBuf[ 0 ] ) ) { //------------------- // Illegal year value //------------------- return( 0 ); } else if ( not isValidMegaNum( monthBuf[ 0 ] ) ) { //-------------------- // Illegal month value //-------------------- return( 0 ); } else if ( not isValidMegaNum( dayBuf[ 0 ] ) ) { //------------------ // Illegal day value //------------------ return( 0 ); } else if ( not isValidMegaNum( hourBuf[ 0 ] ) ) { //------------------- // Illegal hour value //------------------- return( 0 ); } else if ( not isValidMegaNum( minuteBuf[ 0 ] ) ) { //--------------------- // Illegal minute value //--------------------- return( 0 ); } else if ( not isValidMegaNum( secBuf[ 0 ] ) ) { //--------------------- // Illegal second value //--------------------- return( 0 ); } iCounter = ( word ) strtol( counterBuf, NULL, BASE_36 ); minValue = ( word ) strtol( minuteBuf, NULL, BASE_36 ); dt.day = strtol( dayBuf, NULL, BASE_36 ); secValue = ( word ) strtol( secBuf, NULL, BASE_36 ); yearValue = ( word ) strtol( yearBuf, NULL, BASE_36 ); tm.hour = strtol( hourBuf, NULL, BASE_36 ); dt.month = strtol( monthBuf, NULL, BASE_36 ); if ( iCounter > MAX_SN_COUNTER ) { //--------------------------- // Counter value out of range //--------------------------- return( 0 ); } else if ( yearValue > BASE_36 ) { //------------------ // year out of range //------------------ return( 0 ); } else if ( dt.month > MAX_SN_MONTHS ) { //---------------------- // Month second of range //---------------------- return( 0 ); } else if ( dt.day > MAX_SN_DAYS ) { //----------------- // Day out of range //----------------- return( 0 ); } else if ( tm.hour > MAX_SN_HOURS ) { //--------------------- // Hour second of range //--------------------- return( 0 ); } else if ( minValue > MAX_SN_MINS ) { //--------------------------- // Minutes value out of range //--------------------------- return( 0 ); } else if ( secValue > MAX_SN_SECS ) { //-------------------- // second out of range //-------------------- return( 0 ); } dt.month++; dt.day++; dt.year = START_YEAR + yearValue; tm.minute = minValue * 2; tm.second = secValue * 2; if ( piNodeCount ) { *piNodeCount = iCounter; } return( 1 ); } static regResults registration_info( char *name, char *serial, char *actcode, word *node_count ) { word i; word checksum = 0; byte nBuf[ 80 ]; byte sBuf[ 80 ]; if ( memcmp( system_code_buf, DEFAULT_SYSTEM_CODE, SYSTEM_CODE_LEN ) == 0 ) { //--------------------- // System Code is blank //--------------------- if ( actcode ) { strcpy( actcode, DEFAULT_SYSTEM_CODE ); } } else { //--------------------------------------------------------- // Looks like we have a valid system code. Let's decode it //--------------------------------------------------------- char eBuf[ 80 ]; memmove( eBuf, system_code_buf, SYSTEM_CODE_LEN ); decryptData( eBuf, SYSTEM_CODE_LEN, 0x00 ); if ( actcode ) { //--------------------------------------------------------- // Now let's copy that system code to our calling parameter //--------------------------------------------------------- sprintf( actcode, "%-12.12s", eBuf ); } } if ( memcmp( regname_buf, DEFAULT_REGNAME, USERNAME_LEN ) == 0 ) { //------------------- // User name is blank //------------------- return( registrationNone ); } else if ( memcmp( serial_buf, DEFAULT_SERIALNO, SERIAL_NUM_LEN ) == 0 ) { //----------------------- // Serial number is blank //----------------------- return( registrationNone ); } for ( i = 0; i < USERNAME_LEN; i++ ) { checksum += regname_buf[ i ]; } checksum = checksum & 0x00FF; memmove( nBuf, regname_buf, USERNAME_LEN ); memmove( sBuf, serial_buf, SERIAL_NUM_LEN ); decryptData( nBuf, USERNAME_LEN, 0x00 ); decryptData( sBuf, SERIAL_NUM_LEN, checksum ); if ( memchr( sBuf, '\0', SERIAL_NUM_LEN ) == NULL ) { //--------------------------------- // One of 'em isn't null terminated //--------------------------------- return( registrationBad ); } else if ( memchr( nBuf, '\0', USERNAME_LEN ) == NULL ) { //--------------------------------- // One of 'em isn't null terminated //--------------------------------- return( registrationBad ); } else if ( not serialNumberDecode( sBuf, node_count ) ) { //---------------------------------- // couldn't decode the serial number //---------------------------------- return( registrationBad ); } if ( name ) { strcpy( name, nBuf ); } if ( serial ) { serial[ 0 ] = sBuf[ 0 ]; serial[ 1 ] = sBuf[ 1 ]; serial[ 2 ] = sBuf[ 2 ]; serial[ 3 ] = sBuf[ 3 ]; serial[ 4 ] = '-'; serial[ 5 ] = sBuf[ 4 ]; serial[ 6 ] = sBuf[ 5 ]; serial[ 7 ] = sBuf[ 6 ]; serial[ 8 ] = sBuf[ 7 ]; serial[ 9 ] = '-'; serial[ 10 ] = sBuf[ 8 ]; serial[ 11 ] = sBuf[ 9 ]; serial[ 12 ] = sBuf[ 10 ]; serial[ 13 ] = sBuf[ 11 ]; serial[ 14 ] = '-'; serial[ 15 ] = sBuf[ 12 ]; serial[ 16 ] = sBuf[ 13 ]; serial[ 17 ] = sBuf[ 14 ]; serial[ 18 ] = sBuf[ 15 ]; serial[ 19 ] = sBuf[ 16 ]; serial[ 20 ] = '\0'; } return( registrationGood ); } static char *serialFormatted( char *sBuf ) { static char tBuf[ 20 ]; sprintf( tBuf, "%-4.4s %-4.4s %-4.4s %-4.4s", sBuf, sBuf + 4, sBuf + 8, sBuf + 12 ); return( tBuf ); } char *software_serial_number( void ) { static char buf[ 50 ]; regResults result; if ( registered ) { result = registration_info( NULL, buf, NULL, NULL ); //------------------------------------------- // This is a "shareware" copy of the software //------------------------------------------- if ( result == registrationGood ) { //---------------------------------------------------------- // We have valid registration information. Let's return the // serial number to the calling function. //---------------------------------------------------------- return buf; //return( serialFormatted( buf ) ); } } //------------------------------------------------------------- // We have a version with no serial number. This means that we // have an unregistered copy of the software. //------------------------------------------------------------- return( UNREG_STRING ); } char *registered_user_name( void ) { regResults result; static char buf[ 50 ]; if ( registered ) { result = registration_info( buf, NULL, NULL, NULL ); //------------------------------------------- // This is a "shareware" copy of the software //------------------------------------------- if ( result == registrationGood ) { //---------------------------------------------------------- // We have valid registration information. Let's return the // user's name to the calling function. //---------------------------------------------------------- return( buf ); } } //--------------------------------------------------------- // We have a version with no user name. This means that we // have an unregistered copy of the software. //--------------------------------------------------------- return( UNREG_STRING ); } char *get_system_code( void ) { regResults result; static char buf[ 30 ]; if ( registered ) { result = registration_info( NULL, NULL, buf, NULL ); //------------------------------------------- // This is a "shareware" copy of the software //------------------------------------------- if ( result == registrationGood ) { return( buf ); } } return( UNREG_STRING ); } word get_node_count( void ) { regResults result; word iNodeCount = 2; if ( registered ) { result = registration_info( NULL, NULL, NULL, & iNodeCount ); //------------------------------------------- // This is a "shareware" copy of the software //------------------------------------------- if ( result == registrationGood ) { return iNodeCount; } } return 2; } word is_version_registered( void ) { regResults result; char serial[ 80 ]; char name[ 80 ]; result = registration_info( name, serial, NULL, NULL ); if ( result == registrationGood ) { //---------------------- // Fully registered copy //---------------------- return( TRUE ); } else { //--------------------- // Unregistered edition //--------------------- return( TRUE ); } } void CHECK_REG( void ) { if ( is_version_registered() ) { registered = TRUE; max_node_count = get_node_count(); } else { registered = TRUE; max_node_count = 255; } }