first commit

Version 3.x.x
This commit is contained in:
VNGhostMans
2023-05-14 20:21:09 +07:00
parent a3037a8db3
commit 5ec92ee05e
1166 changed files with 1036539 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Serial number encryption algorithms</title>
</head>
<body>
<h1>Serial number encryption algorithms</h1>
<p>The security of a key in the licensing system is based on asymmetric cryptography algorithms. The current version implements the RSA algorithm with the key length from 1024 to 16384 bits. Future versions are planned to implement other algorithms based on ECC as well as symmetric+asymmetric combined cryptography.</p>
<p>The algorithm used is unique for each product. Keys made with one algorithm cannot be used with another one, this means changing algorithms after at least one license is created is not allowed. The protection module in the protected program "knows" which algorithm the serial number is encrypted with and will not accept keys made with other algorithms or with the same algorithm but different parameters (say, different key length).</p>
<h3>RSA Algorithm</h3>
<p>A serial number is encrypted with the RSA algorithm as follows:</p>
<ul>
<li><strong>Adding random data to the beginning of the serial number</strong> - the method is based on RFC2313, but the implementation is slightly different. The following bytes are added to the beginning of the key: 00 02 NN...NN 00, where NN..NN
are from 8 to 16 random non-zero bytes. The number of bytes is random, but the system takes into account the length of the key and its maximum capacity.</li>
<li><strong>Adding random data to the end of the serial number</strong>
- the total number of bytes in a serial number must be equal to the number of bits in keys of the algorithm divided by 8.
The serial number is appended with the corresponding number of bytes holding random data. As a result, the following serial number format is produced: 00 02 NN..NN 00 DD..DD MM..MM, where NN is a set of random non-zero bytes, DD is the original serial number, MM is a set of random bytes (including zeros). The summary length of the sequence should be equal to the number of bits in keys of the algorithm divided by 8</li>
<li><strong>Encryption</strong> goes using a typical procedure implemented in many libraries to process big numbers. The PHP generator contains all the required information.</li>
<li><strong>Packing</strong> - the set of bytes obtained after encryption is encoded to base-64 &mdash; this is a serial number that goes to a customer.</li>
</ul><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,70 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Serial number generators</title>
</head>
<body>
<h1>Serial number generators</h1><strong>What are they for?</strong>
<p>Apart from VMProtect, other software can generate serial numbers too. This is necessary to automate sending serial numbers. A customer purchases the product, an e-commerce agent sends an HTTP query to the website of the vendor, the generator runs on the server and produces a serial number based on customer's data. The serial number is sent to the customer and to the vendor. The vendor then adds the serial to VMProtect manually using the import license dialog.</p><strong>How it works</strong>
<p>The licensing system of VMProtect is based on asymmetric algorithms, that is why a secret product key is required to generate a serial number. You can export this key in the project properties window and pass it to the generator in any suitable way.</p>
<p>The generator is called by the e-commerce agent using an HTTP query. A PHP generator can be called directly, a DLL-based generator - indirectly, but the principle is the same:</p>
<ul>
<li>Receive user data from the e-commerce agent</li>
<li>Add all required information specified by the vendor</li>
<li>Generate a serial number</li>
<li>Encrypt it with one of algorithms</li>
<li>Send the result to the e-commerce agent</li>
</ul><strong>Are there any existing generators?</strong>
<p>The licensing system comes with three ready to use serial number generators <a href="keygen_dll.htm">as DLL</a>,
<a href="keygen_net.htm">for the .Net platform</a> and <a href=
"keygen_php.htm">on PHP</a>.</p><strong>Can I make my own generator?</strong>
<p>Yes, you can. The format of the serial number is <a href=
"serial_format.htm">here</a>, serial number encryption algorithms are described <a href=
"algorithms.htm">here</a>.</p><strong>Is it safe?</strong>
<p>Generally, yes, this is safe. However, you should follow these recommendations:</p>
<ul>
<li><strong>Use HTTPS</strong> - if your e-commerce provider can send HTTPS queries, and your web hosting provider can answer such requests - you should prefer this variant over the typical HTTP, because in this case all data are transmitted in the encrypted form and the generated serial number cannot be intercepted.</li>
<li><strong>"Hide" your generator</strong> - make sure no one can open the generator occasionally. The
www.site.com/keygen.php address is a bad idea. While
www.site.com/abc123.php is much better. Make sure you do not put any external links to the key generator, it isn't listed in website directories, and don't put it into any service file like robot.txt. The less is known about the location of the generator, the better. Optionally, you can even place the generator on another website.</li>
<li><strong>Make sure it is the e-commerce agent who calls the generator</strong> -
the program processing queries from the agent should check the IP address of the caller. E-commerce providers usually publish the IP-range the use to query serial number generators. Find that list at your agent and add a check to the program. If IP address sending a query lies beyond the specified IP range, do not produce comprehensible error messages. Either do not return anything or produce a simple 404.
Do not give any clues to why the query has failed.</li>
<li><strong>Check input parameters</strong> - product settings in the e-commerce agent's control panel usually allow you to specify a query string the agent should make to receive a license. For instance, you want to receive user name, e-mail address, date of purchase and the order id. So make sure all these parameters are passed and all of them have the correct format. Do not produce any response to erroneous queries. Send a message to your own e-mail whenever an erroneous query to the generator is made. This should help to investigate the issue.</li>
<li><strong>Add a "password"</strong> specify an additional parameter in the query sent by the e-commerce agent, a password. It should have an non-obvious name and value. Check this parameter from the receiving side. If the value is wrong, or the parameter is not specified - do not generate a serial number.</li>
</ul><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,199 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Windows-version</title>
</head>
<body>
<h1>Windows-version</h1>
<h3>Description</h3>
<p>Windows key generators are DLL-files for x86 and x64 platforms, a C language header file and an MSVC-compatible lib-file. Therefore, the library can be both linked statically and loaded dynamically.</p>
<p>All files of the generator are located in the
<strong>Keygen\DLL</strong> folder. A test application generating serial numbers is also there.</p>
<h3>Generator API</h3>
<p>The generator exports just two functions: the first one generates a serial number, while the second one frees up memory allocated by the first one. Let's start with the first and the main one:</p>
<pre class="code"><strong>VMProtectErrors</strong> __stdcall <strong>VMProtectGenerateSerialNumber</strong>(
<strong>VMProtectProductInfo *</strong> pProductInfo,
<strong>VMProtectSerialNumberInfo *</strong> pSerialInfo,
<strong>char **</strong> pSerialNumber
);
</pre>
<p>The first parameter is a pointer to the
<strong>VMProtectProductInfo</strong> structure, which contents are uploaded to VMProtect (see <a href=
"../licenses.htm#export">Exporting product parameters</a>).
The structure contains product private key, the algorithm used and the identifier of the product. More details on filling this structure follow below.</p>
<p>The second parameter is a pointer to the
<strong>VMProtectSerialNumberInfo</strong> structure, which contents are moved to the generated serial number. The structure holds all fields of a serial number and a bit mask that defines which fields should be written to the serial number.</p>
<pre class="code">struct <strong>VMProtectSerialNumberInfo</strong>
{
<strong>INT</strong> flags;
<strong>wchar_t *</strong> pUserName;
<strong>wchar_t *</strong> pEMail;
<strong>DWORD</strong> dwExpDate;
<strong>DWORD</strong> dwMaxBuildDate;
<strong>BYTE</strong> nRunningTimeLimit;
<strong>char *</strong> pHardwareID;
<strong>size_t</strong> nUserDataLength;
<strong>BYTE *</strong> pUserData;
};
</pre>
<p>The <strong>flags</strong> field contains bit flags from the
<strong>VMProtectSerialNumberFlags</strong> set described before the structure:</p>
<ul>
<li><strong>HAS_USER_NAME</strong> - put the user name from the
<strong>pUserName</strong> variable into the serial number.</li>
<li><strong>HAS_EMAIL</strong> - put the e-mail from the
<strong>pEMail</strong> variable into the serial number.</li>
<li><strong>HAS_EXP_DATE</strong> - the serial number will expire after the date specified in the
<strong>dwExpDate</strong> variable.</li>
<li><strong>HAS_MAX_BUILD_DATE</strong> - the serial number will only work with version of the product built up to the date specified in the <strong>dwMaxBuildDate</strong> variable.</li>
<li><strong>HAS_TIME_LIMIT</strong> - the program stops working after the time specified in the
<strong>nRunningTimeLimit</strong> variable expires (the time is specified in minutes and shouldn't exceed 255).</li>
<li><strong>HAS_HARDWARE_ID</strong> - the program works only on hardware with the id specified in the <strong>pHardwareID</strong> variable.</li>
<li><strong>HAS_USER_DATA</strong> - put custom user data of
<strong>nUserDataLength</strong> length at the address of <strong>pUserData</strong> to the serial number.</li>
</ul>
<p>The third parameter is a pointer to a pointer. The address of the generated serial number is written there. After generating the serial number, it should be copied, and the address must be passed to the second API function of the generator that will free memory taken by the serial number.</p>
<pre class="code"><strong>void</strong> __stdcall <strong>VMProtectFreeSerialNumberMemory</strong>(<strong>char *</strong> pSerialNumber);
</pre>
<p>The <strong>VMProtectGenerateSerialNumber</strong> function
returns a <strong>VMProtectErrors</strong> value that either contains 0 if the serial number is successfully generated, or an error code.
Possible error codes are:</p>
<ul>
<li><strong>ALL_RIGHT</strong> - no errors, the serial number is generated.</li>
<li><strong>UNSUPPORTED_ALGORITHM</strong> - an incorrect key encryption algorithm is passed in the first parameter of the function.</li>
<li><strong>UNSUPPORTED_NUMBER_OF_BITS</strong> - an incorrect number of bits is passed in the first parameter of the function.</li>
<li><strong>USER_NAME_IS_TOO_LONG</strong> - the length of the UTF-8 encoded user name exceeded 255 byte.</li>
<li><strong>EMAIL_IS_TOO_LONG</strong> - the length of the UTF-8 encoded user e-mail exceeded 255 byte.</li>
<li><strong>USER_DATA_IS_TOO_LONG</strong> - the length of the user data exceeded 255 byte.</li>
<li><strong>HWID_HAS_BAD_SIZE</strong> - the hardware identifier has incorrect size.</li>
<li><strong>PRODUCT_CODE_HAS_BAD_SIZE</strong> - the identifier of the product passed in the first parameter of the function has incorrect size.</li>
<li><strong>SERIAL_NUMBER_TOO_LONG</strong> - the serial number is too long and can't fit the number of bits specified in the algorithm.</li>
<li><strong>BAD_PRODUCT_INFO</strong> - the first parameter of the function is incorrect or NULL.</li>
<li><strong>BAD_SERIAL_NUMBER_INFO</strong> - the second parameter of the function is incorrect or NULL.</li>
<li><strong>BAD_SERIAL_NUMBER_CONTAINER</strong> - the third parameter of the function doesn't point to memory to write the serial number address to.</li>
<li><strong>NOT_EMPTY_SERIAL_NUMBER_CONTAINER</strong> - the third parameter of the function doesn't point to an empty memory cell, the cell must be NULL.</li>
<li><strong>BAD_PRIVATE_EXPONENT</strong> - the first parameter of the function contains an incorrect value of the private exponent.</li>
<li><strong>BAD_MODULUS</strong> - the first parameter of the function contains an incorrect value of modulus.</li>
</ul>
<p>Errors can be of two categories: those caused by incorrect parameters or incorrect value of the first parameter, and all the rest. First category errors are rare and they indicate incorrect configuration of the structure. You should upload the product information again and check if the structure is filled correctly. An example of a proper filling of the structure can be found below.</p>
<p>Second category errors are caused by an attempt to put more data to the key than it can hold with its size. In this case we recommend to send a message to the e-commerce provider containing a text like "The key will be sent in 24 hours" instead of the actual serial number, and send all the required information to your own e-mail. In this case, the key is generated manually in VMProtect, some data are truncated to fit all crucial information to the maximum key size.</p>
<h3>Example of usage</h3>
<p>Below is a code example that calls the above functions and generates a serial number. Notice the block of code in the very beginning. The example will not work until you replace it with the one exported from VMProtect for your product:</p>
<pre class="code">//////////////////////////////////////////////////////////////////////////
// !!! this block should be generated by VMProtect !!! ///
//////////////////////////////////////////////////////////////////////////
<strong>VMProtectAlgorithms</strong> g_Algorithm = ALGORITHM_RSA;
<strong>size_t</strong> g_nBits = 0;
<strong>byte</strong> g_vModulus[1];
<strong>byte</strong> g_vPrivate[1];
<strong>byte</strong> g_vProductCode[1];
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
<strong>int</strong> _tmain(<strong>int</strong> argc, <strong>_TCHAR*</strong> argv[])
{
<strong>VMProtectProductInfo</strong> pi;
pi.algorithm = g_Algorithm;
pi.nBits = g_nBits;
pi.nModulusSize = sizeof(g_vModulus);
pi.pModulus = g_vModulus;
pi.nPrivateSize = sizeof(g_vPrivate);
pi.pPrivate = g_vPrivate;
pi.nProductCodeSize = sizeof(g_vProductCode);
pi.pProductCode = g_vProductCode;
<strong>VMProtectSerialNumberInfo</strong> si = {0};
si.flags = HAS_USER_NAME | HAS_EMAIL;
si.pUserName = L"John Doe";
si.pEMail = L"john@doe.com";
<strong>char *</strong> pBuf = NULL;
<strong>VMProtectErrors</strong> res = <strong>VMProtectGenerateSerialNumber</strong>(&amp;pi, &amp;si, &amp;pBuf);
<strong>if</strong> (res == ALL_RIGHT)
{
<strong>printf</strong>("Serial number:\n%s\n", pBuf);
<strong>VMProtectFreeSerialNumberMemory</strong>(pBuf);
}
else
{
<strong>printf</strong>("Error: %d\n", res);
}
<strong>return</strong> 0;
}
</pre>
<p>This is an example project for Microsoft Visual Studio from <strong>Keygen\DLL\Example</strong>. Below are the most interesting parts of the code with our comments.</p>
<p>First lines of the <strong>main</strong> function fill the <strong>VMProtectProductInfo</strong> structure with data, exported from VMProtect. This code is typical and it shouldn't be changed to avoid errors. Then we create the
<strong>VMProtectSerialNumberInfo</strong> structure and insert a bit combination of user name and e-mail to the flag field.
In the next line, we put the user name and the password to the appropriate fields in the structure. Note, values are accepted in the UNICODE encoding. The key generator will transform them to UTF-8.</p>
<p>Then, we initialize a pointer variable where the address of the generated key will be stored, and call
<strong>VMProtectGenerateSerialNumber</strong>, then analyze the return code. If there are no errors, the generated key goes out to console, and a call to free serial number memory function is made.</p><strong>The rest fields of the
VMprotectSerialNumberInfo structure</strong>
<p>Some fields of the structure may needs some additional explanations. For example, <strong>dwExpDate</strong> and
<strong>dwMaxBuildDate</strong> fields contain dates in the specific format: <strong>0xYYYYMMDD</strong>, that is, the year is stored in the high wordб while the month and the day are in the respectively high and low bytes of the low word.
To produce such a number, the following macros is used: <strong>MAKEDATE(y,
m, d)</strong>. You can call it like this: <strong>MAKEDATE(2010,
05, 12)</strong>.</p>
<p>The <strong>pHardwareID</strong> field should contain a pointer to a string the
<strong>VMProtectGetCurrentHWID</strong> method from the licensing SDK has returned.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,78 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>.Net-version</title>
<style type="text/css">
/*<![CDATA[*/
p.c1 {color:red;}
/*]]>*/
</style>
</head>
<body>
<h1>.Net-version</h1>
<h3>Description</h3>
<p>The .Net-version of the key generator is a build containing all that is required to generate serial numbers. Source codes are in <strong>Keygen\Net</strong> as two projects: KeyGen (the key generator itself) and Usage (an example of use of the key generator).</p>
<p class="c1">The key generator is supplied in source codes for quick building under a given version of the .Net
Framework, however we strongly do not recommend to apply any changes to the code. In future versions of VMProtect some new possibilities may be added to the generator, and that may lead to repeated modification of the code. Also, this may lead to errors that are very difficult to locate.
If you found errors in the original code of the generator or would like to suggest improvements, please contact the support team.</p>
<h3>Using the generator</h3>
<p>Take the code from the <strong>Usage</strong> project as a base,
then add to your project a link to the VMProtect.KeyGen.dll build. After that you will be able to generate serial numbers in your application. To function properly, the generator must "know" which product you generate serial numbers for.
To achieve this, in VMProtect open the "Project | Export key pair" dialog and select the "Parameters for KeyGen.Net" option. The text area below will contain text information you should copy and paste to your application as a string constant.</p>
<p>Here is an example code to call the generator:</p>
<pre>
try
{
string data = @""; // put the exported data here
Generator g = new Generator(data);
g.UserName = "John Doe";
g.EMail = "john@doe.com";
g.ExpirationDate = DateTime.Now.AddMonths(1);
g.MaxBuildDate = DateTime.Now.AddYears(1);
g.RunningTimeLimit = 15;
g.HardwareID = "AQIDBAgHBgU=";
g.UserData = new byte[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
string serial = g.Generate();
Console.WriteLine("Serial number:\n{0}\n", serial);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex);
}
</pre>
<p>The string you copied from VMProtect should be placed to the <strong>data</strong> variable passed as a parameter to the serial number class constructor. In case of any problems occur while parsing the product data, the constructor throws an exception containing a description of the problem. If the constructor successfully finishes its work, the generator is ready to produce serial numbers.</p>
<p>A serial number can contain various information specified using the generator properties. The above example displays how to fill all and every field of a serial number. Certain fields have limitations. For example, the <strong>User Name</strong> and
<strong>E-Mail</strong> cannot accept strings exceeding 255 symbols in the UTF-8 encoding. If incorrect data are supplied, properties throw exceptions containing a description of the problem.</p>
<p>When the generator setup is done, the
<strong>Generate()</strong> method is invoked. This method generates a serial number. At this step, all data of the serial number are combined, the checksum is calculated and the data are encrypted. If the volume of data exceeds the allowed length, the method throws an exception.</p>
<p>If you need to generate multiple serial numbers, you can use the generator class several times in a row, without the need to create it from scratch. To clear any given property of the generator, simply assign a <strong>null</strong> value to it.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,94 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>UNIX-version</title>
</head>
<body>
<h1>UNIX-version</h1>
<h3>Description</h3>
<p>The UNIX-version of the key generator is a PHP file that contains all necessary information for serial number generation. The file is located in <strong>Keygen\PHP</strong>. Below we describe the key points of using such a generator.</p>
<h3>Configuring the generator</h3>
<p>In the beginning of the PHP file, the setup code is located:</p>
<pre class="code">//////////////////////////////////////////////////////////////////////////////////////////////
// The following lines should be generated by VMProtect License Manager
$exported_algorithm = "RSA";
$exported_bits = 2048;
$exported_private = "PJvj4kEpoQMIpYK+9wEt......xKeiSZgzdiln8Q==";
$exported_modulus = "rOlny/3QgZb/VmGr3CmY......I6ESAUmtQ+RBqQ==";
$exported_product_code = "oLQdGUn8kVk=";
//////////////////////////////////////////////////////////////////////////////////////////////
</pre>
<p>This code is automatically generated by VMProtect (see <a href=
"../licenses.htm#export">Exporting product parameters</a>) and is unique for each particular product. It is crucial to copy it accurately, as otherwise the generator will work incorrectly.</p>
<h3>Contents of a key</h3>
<p>Then, the generator specifies the contents of a serial number
The contents are specified in an array, with all possible parameters of the key listed below. However, in real applications, some of them may be omitted:</p>
<pre class="code">$params = <strong>array</strong>(
user_name =&gt; "John Doe", // UTF-8!
email =&gt; "john@doe.com",
hwid =&gt; "vHGMdMRvGCPjWcCQ", // Exactly as returned by VMProtectGetCurrentHWID
expire_date =&gt; <strong>array</strong>(year =&gt; 2009, month =&gt; 10, day =&gt; 1),
maxbuild_date =&gt; <strong>array</strong>(year =&gt; 2009, month =&gt; 10, day =&gt; 1),
time_limit =&gt; 10,
user_data =&gt; <strong>base64_decode</strong>("CGCvRvMWcPHGdMjQ"), // string of bytes
);
</pre>
<h3>Successful key generation handler function</h3>
<p>Below you can see a simplest function called upon successful generation of a serial number. The only parameter sent to it is a serial number string. The function must pass the serial number to the caller (an e-commerce agent), usually with the <strong>echo</strong> command. The string is preliminarily split to sub-strings 75 symbols each, for convenience. Also, this function could send the generated serial number by e-mail to the developer or add it to a database.</p>
<pre class="code">function <strong>OnSerialGenerated</strong>($serial)
{
$serial = <strong>wordwrap</strong>($serial, 75, "\n", true);
<strong>echo</strong> $serial;
}
</pre>
<h3>Key generator error handler function</h3>
<p>The final part of the code that needs our attention is a function called when something goes wrong. This function receives a string with the error message, and when it finishes, the <strong>die()</strong> function is called. The handler function must do two things: instead of a key, return to an e-commerce agent a message saying the key will be sent manually. And send to the developer an exhaustive information about the error to fix it and generate the key manually.</p>
<pre class="code">function <strong>OnSerialGenerationFailed</strong>($details)
{
<strong>echo</strong> "You will receive serial number in the next 24 hours"; // message to the customer
// mail("support@vendor.com", "Houston, we have a problem", $details); // message to vendor
}
</pre>
<p>There are several possible causes of mistakes: incorrect parameters of the algorithms, incorrect parameters of the key, a too long user name or e-mail, or a too long serial number that doesn't fit to the number of bits specified in the algorithm.
That is why the <strong>OnSerialGenerationFailed</strong> function must send a detailed information about the issue to the developer, so he could generate a serial number and send it to the customer.</p>
<h3>Other things to consider</h3>
<p>Examples hold a simplified version of the key generator. It doesn't take into account <a href="index.htm">recommendations to develop web generators</a>. It does not check the IP address of the caller and does not analyze input parameters. Please pay attention to this when developing your own generator based on this one.</p>
<p>A user name and an e-mail must be passed as UTF-8 strings. Make sure your e-commerce agent sends these data in the UTF-8 encoding, or transcode the information if this is not so. Wrong encoding won't lead to an incorrect serial number generated, but the registration name displayed for such a serial number can be different from the real user's name, so he or she may be surprised to see it in the "About" window of the application</p>
<p>Asymmetric encryption is a complex mathematical process. If it is implemented using pure PHP without any third-party libraries, serial number generation can take dozens of seconds. The generator uses
<strong>gmp_powm</strong>, <strong>bi_powmod</strong>,
<strong>bcpowod</strong> functions whenever they are available. If serial number generation take too long on your hosting, we recommend to ask the hosting provider to enable these functions. For example, the <strong>gmp_powm</strong> function works ten of times faster than <strong>bcpowmod</strong>.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>

View File

@@ -0,0 +1,206 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Stylesheet" type="text/css" href=
"../../default.css" />
<meta http-equiv="Content-Type" content=
"text/html; charset=utf-8" />
<title>Serial number format</title>
<style type="text/css">
/*<![CDATA[*/
th {text-align:left;}
table {border-collapse:collapse; margin-top: 4px;}
td,th {border: 1px solid #B0B0B0; padding-left:10;padding-right:10;}
/*]]>*/
</style>
</head>
<body>
<h1>Serial number format</h1>
<h3>Serial number structure</h3>
<p>The serial number consists of blocks. Each block starts from an identifier byte that indicates contents of the block and possibly its length. The last block always has the 255 identifier that contains a checksum of the serial number except the last block.</p>
<p>Depending on the type of the block, it can have constant or variable length. In the latter case, the length is specified in the byte following the block identifier. The exact format of each block is described below.</p>
<h3>Block format</h3>
<table border="1" cellspacing="0" cellpadding="2">
<tr>
<th>ID</th>
<th>Name</th>
<th>Size (byte)</th>
<th>Description</th>
<th>Example</th>
</tr>
<tr>
<td>0x01</td>
<td>Version</td>
<td>1</td>
<td>The block contains a version of the serial number, 1-byte sized.
The version must be 1.</td>
<td>01 01</td>
</tr>
<tr>
<td>0x02</td>
<td>User name</td>
<td>1 + N</td>
<td>The block contains a UTF-8 encoded user name. Before the user name, there is 1 byte holding the length of the name. Therefore, the total length of a user name must not exceed 255 bytes. No trailing 0 is required.</td>
<td>02 04 4A 5F 48 4E</td>
</tr>
<tr>
<td>0x03</td>
<td>E-Mail</td>
<td>1 + N</td>
<td>The block contains a UTF-8 encoded e-mail of the user.
Before the e-mail there is 1 byte holding the length. Therefore, the total length of an e-mail must not exceed 255 bytes. No trailing 0 is required.</td>
<td>03 07 61 40 62 2E 63 6F 6D</td>
</tr>
<tr>
<td>0x04</td>
<td>Hardware identifier</td>
<td>1 + N</td>
<td>The block contains hardware identifier as returned by the <strong>VMProtectGetCurrentHWID()</strong> function. The function returns a base-64 string. A decoded version of the string is put to the serial number. The length of the data block must be a multiple of 4. There is a length byte before the data block. The maximum block length is 32 bytes.</td>
<td>04 08 E1 E2 E3 E4 A1 A2 A3 A4</td>
</tr>
<tr>
<td>0x05</td>
<td>License expiration date</td>
<td>4</td>
<td>The block contains serial number expiration date
Date format is described below.</td>
<td>05 01 0A 07 DA</td>
</tr>
<tr>
<td>0x06</td>
<td>Maximum operation time</td>
<td>1</td>
<td>the block contains 1 byte holding the time in minutes the program can operate. Therefore, the maximum time can be 255 minutes.</td>
<td>06 05</td>
</tr>
<tr>
<td>0x07</td>
<td>Product code</td>
<td>8</td>
<td>The block contains a product code - 8 bytes created by VMProtect and exported with product parameters.
These data are exported in the base-64 encoding and must be decoded to a byte array before putting to a serial number.
The size of the array must be exactly 8 bytes.
<strong>This block is obligatory! Without it, the protected program will not work correctly.</strong></td>
<td>07 01 02 03 04 05 06 07 08</td>
</tr>
<tr>
<td>0x08</td>
<td>User data</td>
<td>1 + N</td>
<td>The block contains up to 255 bytes of custom user data.
The license system doesn't analyze these data and will return them when the
<strong>VMProtectGetSerialNumberData()</strong> function is called. Before the data block, there is a byte holding the size of the user data.</td>
<td>08 05 01 02 03 04 05</td>
</tr>
<tr>
<td>0x09</td>
<td>Maximum build date</td>
<td>4</td>
<td>The block contains the maximum build date of the application. The format is described below.</td>
<td>09 01 0A 07 DA</td>
</tr>
<tr>
<td>0xFF</td>
<td>Checksum</td>
<td>4</td>
<td>The block contains the serial number checksum. The block is located before the last one, and the checksum is calculated for all previous blocks. The checksum calculation mechanism is described below.</td>
<td>FF 01 02 03 04</td>
</tr>
</table>
<h3>Date storage format</h3>
<p>Dates are stored in a serial number as a double word -
0xYYYYMMDD. The high order word contains the year, and the lower order word holds the day and the month.
Bytes follow the Little Endian representation - from lower to higher. If there is a pointer to the first byte of the record, the date can be read or written with the following code:</p>
<pre class="code"><strong>byte *</strong>pDate = 0xNNNNNN; // date address
<strong>*</strong>(<strong>DWORD *</strong>)pDate = (2010 &lt;&lt; 16) | (10 &lt;&lt; 8) | 1; // October 1, 2010
<strong>DWORD</strong> dwExp = *(<strong>DWORD *</strong>)pDate;
</pre>
<h3>Checksum calculation</h3>
<p>The checksum of the serial number is calculated using the SHA-1 hashing algorithm. The result is five 32-bit words. The first word is used as a checksum for the serial number. <strong>Please note:</strong> the word is Little Endian (from lower to higher). The string representation of SHA-1 hash the Big Endian is used - numbers go from the higher byte to the lower one, so if the SHA-1 hash is generated by a string function (like in PHP), the first four bytes of the hash must be reversed.</p>
<h3>Additional information</h3>
<p>Block with numbers other than those specified above are ignored by the licensing system. New blocks may be added in newer versions. <strong>We do not recommend creating your own blocks using non-occupied identifiers!</strong> Firstly, this could render the key non-functional with newer version of the licensing system. Secondly, the protected program cannot read the values of theses blocks anyway. To store additional information in a key, use the <strong>User
Data</strong> field instead. It was meant exactly for this purpose.</p>
<p>A serial number doesn't have SALT, a random information intended to provide variability of keys based on the same input data. This task is imposed to the encryption algorithm. If you need differences on the serial number level, for example, when selling a series of keys to an organization, you can add individual indices to the user name field ("Company" LLC,
key 1 of 10) or insert this information to the <strong>User
Data</strong> field in any appropriate format.</p><br />
<br />
<br />
<br />
<br />
<hr noshade="noshade" size="1" />
<div align="center">
© 2006-2015 Copyright VMProtect Software
</div>
</body>
</html>