WinRAR-Keygen
1. What is WinRAR?
-
WinRAR is a trialware file archiver utility for Windows, developed by Eugene Roshal of win.rar GmbH.
-
It can create and view archives in RAR or ZIP file formats and unpack numerous archive file formats.
-
WinRAR is not a free software. If you want to use it, you should pay to RARLAB and then you will get a license file named
"rarreg.key"
. -
This repository will tell you how WinRAR license file
"rarreg.key"
is generated.
2. How is "rarreg.key" generated?
-
WinRAR uses a signature algorithm, which is a variant of Chinese SM2 digital signature algorithm, to process the user's name and the license type he/she got. Save the result to "rarreg.key" and add some header info, then a license file is generated.
-
The following will talk about the detail of the signature algorithm that WinRAR uses and how WinRAR process the user's name and his/her license type.
2.1. Signature Algorithm
- WinRAR uses ECC (Elliptic-curve Cryptography) to do signature. The elliptic curve it uses is over a composite finite field where the primitive polynomial of base finite field is:
- And the primitive polynomial of extend finite field is:
- The elliptic curve equation is:
-
Let be base point that will be used during signature. The exact value is:
auto G = ecCurve.GetPoint({ // X, represents a polynomial 0x38CC, 0x052F, 0x2510, 0x45AA, // over GF((2 ^ 15) ^ 17), the first term 0x1B89, 0x4468, 0x4882, 0x0D67, // is in the front. 0x4FEB, 0x55CE, 0x0025, 0x4CB7, 0x0CC2, 0x59DC, 0x289E, 0x65E3, 0x56FD }, { // Y, represents a polynomial 0x31A7, 0x65F2, 0x18C4, 0x3412, // over GF((2 ^ 15) ^ 17), the first term 0x7388, 0x54C1, 0x539B, 0x4A02, // is in the front. 0x4D07, 0x12D6, 0x7911, 0x3B5E, 0x4F0E, 0x216F, 0x2BF2, 0x1974, 0x20DA });
-
is the order that will be used during signature. The exact value is:
const uint64_t P[4] = { // P = 0x1026dd85081b82314691ced9bbec30547840e4bf72d8b5e0d258442bbcd31 0x5e0d258442bbcd31, 0x0547840e4bf72d8b, 0x2314691ced9bbec3, 0x0001026dd85081b8 };
, Random Number and Hash
2.1.1 The Generation of PrivateKey-
To generate PrivateKey , random number and hash , we need two byte-arrays. We call them in_data and in_private. Their length is in_data_length and in_private_length respectively.
-
is generated by in_private.
is generated by in_data.
is generated by both in_data and in_private.For better understanding, here I give an case:
byte in_private[7] = { 'P', 'h', 'a', 'n', 't', 'o', 'm' }; byte in_data[9] = { 'L', 'a', 'b', 'y', 'r', 'i', 'n', 't', 'h' };
where in_private_length is 7 and in_data_length is 9.
.
2.1.1.1 The Generation of-
Calculate in_private's SHA-1 digest.
In the case I give, it should be:
byte in_private_sha1[] = { // standard sha-1 value is : { 0xc0, 0x16, 0x3f, 0x02, // 0x02, 0x3f, 0x16, 0xc0, 0x78, 0x4b, 0xac, 0x8c, // 0x8c, 0xac, 0x4b, 0x78, 0xaf, 0x97, 0x0d, 0xe6, // 0xe6, 0x0d, 0x97, 0xaf, 0xd9, 0x46, 0xa4, 0x91, // 0x91, 0xa4, 0x46, 0xd9, 0xdc, 0xb3, 0xbf, 0x06 // 0x06, 0xbf, 0xb3, 0xdc }; // }
NOTICE: Compared with standard SHA-1 calculation, WinRAR reversed each 32-bits block.
If in_private is null, use default value:
byte in_private_sha1[] = { 0x81, 0xb7, 0x3e, 0xeb, 0x29, 0x53, 0x26, 0x50, 0xa3, 0xf4, 0x5e, 0xdc, 0xd5, 0xb9, 0x47, 0x68, 0x4c, 0x3b, 0xe4, 0xcd };
It is probably the SHA-1 digest of some secret data used in RARLAB
-
To get each part of , do 15 rounds of SHA-1 calculation:
1. Let i be
uint32_t
varing from 1 to 15.2. In each round, we calculate the SHA-1 digest of a 24-bytes-long byte-array which is the combination of i (little-endian) and src_data_sha1. Then take the first two bytes and append them at the end of .
-
After that, should be a 30-bytes-long and its value is:
byte PrivateKey[30] = { // PrivateKey = 0xb7e256217a67f14e3fb4246e889ea18b69b246616e04525e96d515831f2a 0x2a, 0x1f, 0x83, 0x15, // which is a 240-bits-long integer. 0xd5, 0x96, 0x5e, 0x52, 0x04, 0x6e, 0x61, 0x46, 0xb2, 0x69, 0x8b, 0xa1, 0x9e, 0x88, 0x6e, 0x24, 0xb4, 0x3f, 0x4e, 0xf1, 0x67, 0x7a, 0x21, 0x56, 0xe2, 0xb7 };
In my code I use a
uint64_t[4]
array to store it.
and .
2.1.1.2 The Generation of-
During the generation of , there is a temporary 24-bytes-long byte-array. After all of the 15 rounds, the temporary byte-array should be the combination of uint32_t(15) (little endian) and src_data_sha1.
In the case I give, it should be:
byte in_private_sha1_temp[] = { 0x0f, 0x00, 0x00, 0x00, 0xc0, 0x16, 0x3f, 0x02, 0x78, 0x4b, 0xac, 0x8c, 0xaf, 0x97, 0x0d, 0xe6, 0xd9, 0x46, 0xa4, 0x91, 0xdc, 0xb3, 0xbf, 0x06 };
-
Calculate in_data's SHA-1 digest:
In the case I give, it should be:
byte in_data_sha1[] = { 0xfc, 0x0e, 0xcd, 0xba, 0x12, 0xa0, 0xc6, 0x2e, 0x96, 0xf6, 0xbe, 0xdb, 0x9f, 0x89, 0x72, 0x10, 0x05, 0x05, 0x71, 0xe0 };
-
Append
byte empty_sha1[] = { 0x43, 0x8d, 0xfd, 0x0f, 0x7c, 0x3c, 0xe3, 0xb4, 0xd1, 0x1b, 0x46, 0x53, 0x46, 0xa5, 0x27, 0x0f, 0x0d, 0xd9, 0x50, 0x10 };
at the end of in_data_sha1 so we can get byte-array (in_data_sha1 + empty_sha1). The byte-array appended is the SHA-1 digest of null while 5 SHA-1 initial constants is set 0. Then take the first 30 bytes of (in_data_sha1 + empty_sha1) as .
-
Append (in_data_sha1 + empty_sha1) at the end of in_private_sha1_temp.
In the case I give, it should be:
byte in_private_sha1_temp[] = { 0x0f, 0x00, 0x00, 0x00, // original in_private_sha1_temp. 0xc0, 0x16, 0x3f, 0x02, 0x78, 0x4b, 0xac, 0x8c, 0xaf, 0x97, 0x0d, 0xe6, 0xd9, 0x46, 0xa4, 0x91, 0xdc, 0xb3, 0xbf, 0x06, 0xfc, 0x0e, 0xcd, 0xba, // in_data_sha1 0x12, 0xa0, 0xc6, 0x2e, 0x96, 0xf6, 0xbe, 0xdb, 0x9f, 0x89, 0x72, 0x10, 0x05, 0x05, 0x71, 0xe0, 0x43, 0x8d, 0xfd, 0x0f, // empty_sha1 0x7c, 0x3c, 0xe3, 0xb4, 0xd1, 0x1b, 0x46, 0x53, 0x46, 0xa5, 0x27, 0x0f, 0x0d, 0xd9, 0x50, 0x10 };
-
To get each part of , do 15 rounds of SHA-1 calculation.
In each round, do++*reinterpreter_cast<uint32_t*>(in_private_sha1_temp);
first, then calculate the SHA-1 digest of in_private_sha1_temp and append the first two bytes of the digest at the end of .
In the case I give, it should be:
byte K[] = { 0xeb, 0xed, 0x4f, 0xba, 0x0b, 0x30, 0xe8, 0x26, 0xf4, 0xec, 0xe6, 0x92, 0x76, 0xcc, 0xe8, 0x0b, 0xa8, 0x9c, 0x6f, 0x3a, 0x41, 0x6d, 0x5c, 0xfe, 0x21, 0x42, 0x5a, 0x5a, 0x5d, 0xbe };
In my code I use a
uint64_t[4]
array to store it.
-
and PublicKey
2.1.2 The Generation of Singnature-
Now we have PrivateKey , random number , hash , order and base point .
-
NOTICE:
1. The dot in refers to the elliptic curve point multiplication on over .
2. means takeing X-axis value of a point. This value is a polynomial over .
3. Function converts a polynomial over to a integer whose bit length would not larger than
15 * 17 = 255
. The detail of function will be talked about later. -
NOTICE:
-
NOTICE:
-
About function :
As I said before, it converts a polynomial over to a integer. If I use a 17-elements-long list represent a polynomial over , whose every element represents a polynomial over , function can be defined as the following Python code:def T(x : list): ret = 0 for i in range(0, 17): ret += x[i] * 2 ** (15 * i) return ret
-
2.2. The Generation of "rarreg.key"
-
rarreg.key consists of a header, user's name, license type, UID, registration data and checksum.
2.2.1 Header
-
It is just a text line:
RAR registration data
-
Actually, when WinRAR verifies user's license file, it does not care what content the header have.
2.2.2 User's name
-
It is also just a text line. Here I give a case:
Phantom
2.2.3 License type
-
Also just a text line. Actually it can be any text. Here I give a case:
Single PC usage License
2.2.5 UID
-
It is just a join of two parts of registration data. Here I give a case:
UID=294d3fd81ae79b20c48c
-
Actually, when WinRAR verifies user's license file, it does not case UID at all.
2.2.5 Registration data
-
Registration data has four parts. We name them RegData0, RegData1, RegData2, RegData3 respectively.
-
If ECC signature of license type is and (, which means in_data = license type, in_private = null) , convert their value to hex string str_R, str_S. The max possible length of str_R and str_S is 60 because and are both 30 bytes long. So RegData1 is the format output of "60", str_S and str_R:
_stprintf_s(RegData[1], TEXT("60%060s%060s"), str_S, str_R);
In the case I give, it should be:
char RegData[1] = "60cc0b2d34fdb287124c6ca6b4f3239d36aa3ef82a9aba3a22d45552465c93260c3f609e601c26f312c4f44e7f8773a98b078809297303f8cac4a5ff92";
-
Let str_Kpub be the hex string of that is generated by user's name (in_private = user's name). RegData3 is:
_stprintf_s(RegData[3], TEXT("%zd%.48s"), strlen(str_Kpub) - 4, str_Kpub);
In the case I give, it should be:
char RegData[3] = "6067c38462f2ff189c4b04e3c0540548d096e1068d9235023c";
-
Let str_Kpub2 be the hex string of that is generated by RegData3 (in_private = RegData3). So:
_stprintf_s(RegData[0], TEXT("%s"), str_Kpub2);
In the case I give, it should be:
char RegData[0] = "c48c1c168f2ddf266ab3c33118678236ddeb1319b06790c929a038e487c79c60";
-
UID is:
_stprintf_s(UID, TEXT("UID=%.16s%.4s"), str_Kpub + 48, str_Kpub2);
In the case I give, it should be:
char UID = "UID=294d3fd81ae79b20c48c";
which is the same as what said before.
-
If ECC signature of str_UserName_RegData0 that is the join of user's name and RegData0 is and (, which means in_data = user's name + RegData0, in_private = null) , convert their value to hex string str_R2, str_S2. So RegData2 is the format output of "60", str_S2 and str_R2:
_stprintf_s(RegData[2], TEXT("60%060s%060s"), str_S2, str_R2);
In the case I give, it should be:
char RegData[2] = "60625690ab228461b54ab9a4c0a4cc5f7fdf47aa192f839596b1628abf1bec0f405163f46ce6a778adc398cefae18dbb0e4f46291e4d61e573ae0eaeb9";
2.2.5 Registration data
- TODO
-
- The output:
is rarreg.key.
_tprintf_s(TEXT("RAR registration data\n%s\n%s\n%s\n"), UserName, LicenseType, UID); char temp[1024] = { }; _stprintf_s(temp, TEXT("%zd%zd%zd%zd%s%s%s%s%lu"), strlen(RegisterData[0]), strlen(RegisterData[1]), strlen(RegisterData[2]), strlen(RegisterData[3]), RegisterData[0], RegisterData[1], RegisterData[2], RegisterData[3], checksum); for (int i = 0; i < 8; ++i) _tprintf_s(TEXT("%.54s\n"), temp + i * 54);
3. How to build keygen?
-
Please make sure that you have Visual Studio 2015 or the higher. Because this is a VS2015 project.
-
You can open the project by VS2015 IDE and then build it with one click. Or use VS Developer Command Prompt:
msbuild winrar-keygen.vcxproj /p:Configuration=Release;Platform=<x86|x64>;OutputPath=<your_output_dir> /t:build
-
NOTICE: Do not use "Debug" configuration. Otherwise you may approximately wait for half a minute every time you generate a license file.
4. Example
D:\Github\winrar-keygen>msbuild winrar-keygen.vcxproj /p:Configuration=Release;Platform=x64;OutDir=D:\winrar-keygen\ /t:build
......
......
D:\Github\winrar-keygen>cd D:\winrar-keygen
D:\winrar-keygen>winrar-keygen.exe "Phantom" "Single PC License" >> rarreg.key