Skip to content

oemoemoem/WinRAR-Keygen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

WinRAR-Keygen

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.

  1. 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 FiniteField where the primitive polynomial of base finite field is:

And the primitive polynomial of extend finite field is:

The elliptic curve equation is:

Let G 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 }); P is the order that will be used during signature. The exact value is:

const uint64_t P[4] = { // P = 0x1026dd85081b82314691ced9bbec30547840e4bf72d8b5e0d258442bbcd31 0x5e0d258442bbcd31, 0x0547840e4bf72d8b, 0x2314691ced9bbec3, 0x0001026dd85081b8 }; 2.1.1 The Generation of PrivateKey PrivateKey, Random Number K and Hash e To generate PrivateKey PrivateKey, random number K and hash e, we need two byte-arrays. We call them in_data and in_private. Their length is in_data_length and in_private_length respectively.

PrivateKey is generated by in_private. e is generated by in_data. K 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 PrivateKey. 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 PrivateKey, 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 PrivateKey.

After that, PrivateKey should be a 30-bytes-long and its value is:

In the case I give, PrivateKey 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.

2.1.1.2 The Generation of K and e. During the generation of PrivateKey, 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 e.

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 red_K, 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 K.

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.

2.1.2 The Generation of Singnature rs and PublicKey PublicKey Now we have PrivateKey PrivateKey, random number K, hash e, order P and base point G.

equation

NOTICE:

  1. The dot in equation refers to the elliptic curve point multiplication on equation over FiniteField.

  2. equation means takeing X-axis value of a point. This value is a polynomial over FiniteField.

  3. Function T converts a polynomial over FiniteField to a integer whose bit length would not larger than 15 * 17 = 255. The detail of function T will be talked about later.

  4. equation is integer addition.

equation

NOTICE:

  1. equation is integer multiplication.

equation

NOTICE:

  1. equation is division over FiniteField.

  2. equation is binary AND operation.

About function T: As I said before, it converts a polynomial over FiniteField to a integer. If I use a 17-elements-long list represent a polynomial over FiniteField, whose every element represents a polynomial over equation, function T 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 r and s (, 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 r and s 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 PublicKey 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 PublicKey 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 r and s (, 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: _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); is rarreg.key. 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.

  1. 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

Releases

No releases published

Packages

No packages published