A keygen for TuxeraNTFS-keygen

Double Sine 20946ec4aa Add TuxeraNTFS-verifier 5 years ago
code 20946ec4aa Add TuxeraNTFS-verifier 5 years ago
.gitignore 7b028c1f1f Add ignoring item tuxera_key.bin 5 years ago
LICENSE 99739f95c3 Add LICENSE 5 years ago
README.md 5f4c074b6f Update README.md, fix some mistakes 5 years ago
README.zh-CN.md 646ba0c052 Update README.zh-CN.md, add sth about short product key 5 years ago

README.md

Tuxera NTFS keygen

中文版README

1. What is Tuxera NTFS?

Tuxera NTFS is a performance optimized, fail-safe, fully compatible NTFS file system driver. It ships for example in smart TVs, set-top boxes, smartphones, tablets, routers, NAS and other devices. It is available for Android and other Linux platforms, QNX, WinCE Series 40, Nucleus RTOS and VxWorks. Supported architectures are ARM architecture, MIPS architecture, PowerPC, SuperH and x86.

From Wikipedia

2. How is the key generated?

There are 2 types of keys (also called Product Key in Tuxera NTFS) that can activate Tuxera NTFS, which are:

Key Type Key Length Format
Long Product Key 34 chars xxxxxx-xxxxxx-xxxxxx-xxxxxx-xxxxxx
Short Product Key 23 chars xxxxx-xxxxx-xxxxx-xxxxx

The x in Format column represents a character in encoding table. This encoding table is:

// defined in CustomBase32Encode function, helper.c file.
const char SubstitutionTable[33] = "0123456789ACDEFGHJKLMNPQRTUVWXYZ";

where null-terminator \0 is not contained.

2.1 How is Long Product Key generated?

Tuxera NTFS uses ECC (Elliptic-curve Cryptography) to generate long product keys.

The curve it uses is secp112r1 of which the equation is

over finite field where


The base point is

whose order is

Tuxera NTFS has stored its official public key in the following files:

Path
/Library/PreferencePanes/Tuxera\ NTFS.prefPane/Contents/MacOS/Tuxera\ NTFS
/Library/PreferencePanes/Tuxera\ NTFS.prefPane/Contents/Resources/WriteActivationData
/Library/PreferencePanes/Tuxera\ NTFS.prefPane/Contents/Resources/WriteActivationDataTiger
/Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.4/ntfsck
/Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.4/tuxera_ntfs
/Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.5/ntfsck
/Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.5/tuxera_ntfs

The public key is

So far I don't know what the corresponding private key is. If you know, please tell me and I will be appreciated with your generous. So we must make a patch to those files which is to replace the official public key with our own public key.

The following is how long product key is generated:

  1. Generate random big number . must be .

  2. Calculate .

  3. Prepare a buffer uint8_t bin_rG[2][14]. Save big number and to bin_rG[0] and bin_rG[1] respectively with big-endian. If big number is not 14-bytes-long, pad zero byte at Most Significant Bit.

  4. Prepare a buffer uint8_t Hash[5]. Calculate the hash of bin_rG with argon2_hash function.

     argon2_hash(1,
                 1 << 16,
                 1,
                 bin_rG,
                 sizeof(bin_rG),
                 salt,
                 sizeof(salt),
                 Hash,
                 sizeof(Hash),
                 NULL,
                 0,
                 Argon2_d,
                 ARGON2_VERSION_13);
    

    where salt is

     const uint8_t salt[16] = {
         0xa1, 0x38, 0x11, 0x98, 0x12, 0x2f, 0x28, 0xee,
         0x2c, 0x3a, 0xa0, 0x57, 0xbd, 0xcf, 0x2d, 0x83
     };
    

    Then clear the lower two bits of Hash[4]. In other words, execute Hash[4] &= 0xFC;.

  5. Convert Hash(5 bytes) to a big number with big endian.

  6. Prepare a buffer uint8_t bin_s[14]. Calculate

    and save to bin_s with big-endian. If big number is not 14-bytes-long, pad zero byte at Most Significant Bit.

  7. Join bin_s(14 bytes) and Hash(5 bytes) and you will get uint8_t key_data[14 + 5] where the first 14 bytes are bin_s.

  8. Encode key_data by custom Base32 and you will get prekey_str that has 31 chars. The differences between custom Base32 and standard Base32 are:

    1. The alphabet table in custom Base32 is 0123456789ACDEFGHJKLMNPQRTUVWXYZ while ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 in standard Base32.

    2. When a 5-bits-long unit crosses over a byte, swap bits in the byte and bits in the next byte.

      Example:

      If 2-bytes-long data to encode is 10111010 11110100, the units to encode are 10111 11010 11010 00000 in custom Base32 while 10111 01011 11010 00000 in standard Base32. That means 010 and 11 in unit 01011 in standard Base32 are swapped because 01011 crossed those two bytes.

    3. No = padding in custom Base32.

  9. The last character in prekey_str must be '0' because Hash[4] was &-masked by 0xFC. Remove the last character and the length of prekey_str becomes 30.

  10. Reverse prekey_str. And divide 30 chars in prekey_str to five 6-chars-long blocks. Join them with hyphen('-') and you will get long product key.

2.2 How is Short Product Key generated?

Short product key is generated by 20 integers of which each is 5-bits-long. In order to explain it easily, I use uint8_t data[20] to represent these 20 integers.

There are two types of short product key. They have different format:

Key Type 1 2
data[0] x0x0x xxx10
data[1] 10xx0 1xx1x
data[2] x10xx 0xx1x
data[3] 0xxx0
data[4] xx01x 11xxx
data[5] xxx10 1xx1x
data[6] xx10x xx1x1
data[7] xx0x1 xx01x
data[8] x1xxx x00xx
data[9] 1x1xx xx1x1
data[10] xxxx1 1x1xx
data[11] xx11x x0xx0
data[12] x01xx
data[13] x0xx1 x0xx0
data[14] x00xx 00xxx
data[15] 10xxx 1xx0x
data[16] xx0x1 x0x1x
data[17] 101xx xxx01
data[18] xxx0x x11xx
data[19] 10xx1 x10xx

The x in the last two columns means that the corresponding bit can be bit 1 or bit 0. Other bits must be as shown in the table.

data[12] in key type 1 and data[3] in key type 2 are checksum. They must be the value of the sum of other 19 integers in module 32.

Substitute uint8_t data[20] according to the following table

const char SubstitutionTable[33] = "0123456789ACDEFGHJKLMNPQRTUVWXYZ";

then you will get you will get prekey_str. Reverse prekey_str and divide 20 chars in prekey_str to four 5-chars-long blocks. Join them with hyphen('-') and you will get short product key.

However a short product key that is randomly generated cannot activate Tuxera NTFS. Because Tuxera has hashed all of valid short product keys and stored their hash values in his binary release. A short product key is valid if and only if the hash value of this short product key matches one of hash values that are stored in his binary release.

It seems that they have 150388 valid short product keys. I have extracted their hash values from /Library/PreferencePanes/Tuxera\ NTFS.prefPane/Contents/MacOS/Tuxera\ NTFS file. You can see them in code/key_hashes.c.

The following is how the hash value of a short product key is calculated:

  1. A short product key is 23 chars long. Pad \n\0 at the end and you will get 25 chars data. Let it be uint8_t buf[25].

  2. Use argon2_hash to hash buf and you will get uint8_t Hash[6]:

     argon2_hash(1,
                 1 << 16,
                 1,
                 buf,
                 sizeof(buf),
                 salt,
                 sizeof(salt),
                 Hash,
                 sizeof(Hash),
                 NULL,
                 0,
                 Argon2_d,
                 ARGON2_VERSION_13);
    

    where salt is

     const uint8_t salt[16] = {
         0x06, 0x9c, 0x5e, 0xf4, 0x90, 0x67, 0x39, 0x4c,
         0x7b, 0x61, 0xa7, 0xee, 0x36, 0x97, 0xc6, 0x02
     };
    
  3. uint8_t Hash[6] is the hash value of a short product key.

3. How is the key verified?

3.1 How is Long Product Key verified?

  1. Decode long product key to 19-bytes-long key_data;

  2. Convert the first 14 bytes and the latter 5 bytes to big number and with big endian.

  3. Calculate and convert the result to uint8_t bin_R[2][14].

  4. Use argon2_hash to hash bin_R and you will get uint8_t Hash[5]. Don't forget that the lower two bits of Hash[4] must be cleared.

  5. Check if Hash is equal to the latter 5 bytes in key_data. If true the long product key is valid, otherwise invalid.

Why? Because if the long product key is valid, we must have

So that Hash shall be equal to the latter 5 bytes in key_data. This is the prerequisite for a valid key. If not equal, the long product key must be an invalid key.

3.2 How is Short Product Key verified?

  1. Decode short product key to uint8_t data[20].

  2. Check if uint8_t data[20] matches the format of key type 1 or key type 2. If none is matched, the short product key is invalid.

  3. The following short product keys are banned explicitly:

     N0P1N-0N267-Z9TWU-24CP1    // it may be development-used only
     J0M1H-37VYL-YEVNK-VFVM5    // a widely used leaked key
     9DTQN-166PM-XLUEY-VTCZF    // a widely used leaked key
    

    If match one of these keys, the short product key is invalid.

  4. Calculate the hash value of the short product key and check if it match one of hash values that are stored in the binary release. If match, the short product key is valid. Otherwise invalid.

4. How to build?

  1. PLEASE MAKE SURE YOU HAVE openssl and argon2. You can install them by Homebrew.

     $ brew install openssl
     $ brew install argon2
    
  2. To make patcher, in console:

     $ cd code
     $ make patcher
    

    and you will get file TuxeraNTFS-patcher.

    To make keygen, in console:

     $ cd code
     $ make keygen
    

    and you will get file TuxeraNTFS-keygen.

    To clean, in console:

     $ cd code
     $ make clean
    

5. How to use?

Last Test Time: 2018-07-13

Last Test Version: 2018 (released 2018-01-25) Download from here:

  1. Build patcher and keygen.

  2. Use TuxeraNTFS-patcher to make a patch for Tuxera NTFS. In console:

     $ sudo ./TuxeraNTFS-patcher
    

    Example:

     $ sudo ./TuxeraNTFS-patcher
     Password:
     -----secp112r1 Private Key-----
     Bin: 42 EE 5D 2C CD 53 0A 06 43 B9 9A 9E 29 B0
    
     -----secp112r1 Public Key-----
     Bin: X = C3 15 26 EC 75 DE AA 90 4C 70 7B 09 2B EC
     Bin: Y = 68 49 70 AA 04 3D 9F B3 DF 42 63 3D 55 FF
    
     Write private key to tuxera_key.bin successfully.
    
     Patching...
     Target file: /Library/PreferencePanes/Tuxera NTFS.prefPane/Contents/MacOS/Tuxera NTFS
     Open file successfully!
     File size: 3669616 byte(s).
     Map file successfully!
     offset = 0x000000000002ec2a, writing data.....Patch is done.
     offset = 0x000000000014f05e, writing data.....Patch is done.
     offset = 0x0000000000284c40, writing data.....Patch is done.
     Modified: 3
    
     Target file: /Library/PreferencePanes/Tuxera NTFS.prefPane/Contents/Resources/WriteActivationData
     Open file successfully!
     File size: 3180416 byte(s).
     Map file successfully!
     offset = 0x000000000002366e, writing data.....Patch is done.
     offset = 0x000000000011eae6, writing data.....Patch is done.
     offset = 0x0000000000226c74, writing data.....Patch is done.
     Modified: 3
    
     Target file: /Library/PreferencePanes/Tuxera NTFS.prefPane/Contents/Resources/WriteActivationDataTiger
     Open file successfully!
     File size: 2132524 byte(s).
     Map file successfully!
     offset = 0x0000000000023c6b, writing data.....Patch is done.
     offset = 0x0000000000126c84, writing data.....Patch is done.
     Modified: 2
    
     Target file: /Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.4/ntfsck
     Open file successfully!
     File size: 3135728 byte(s).
     Map file successfully!
     offset = 0x0000000000099d07, writing data.....Patch is done.
     offset = 0x000000000021bd4c, writing data.....Patch is done.
     Modified: 2
    
     Target file: /Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.4/tuxera_ntfs
     Open file successfully!
     File size: 3005576 byte(s).
     Map file successfully!
     offset = 0x000000000008a747, writing data.....Patch is done.
     offset = 0x00000000001fc754, writing data.....Patch is done.
     Modified: 2
    
     Target file: /Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.5/ntfsck
     Open file successfully!
     File size: 6195032 byte(s).
     Map file successfully!
     offset = 0x0000000000098bc2, writing data.....Patch is done.
     offset = 0x000000000021d890, writing data.....Patch is done.
     offset = 0x0000000000379f0a, writing data.....Patch is done.
     offset = 0x00000000005057a0, writing data.....Patch is done.
     Modified: 4
    
     Target file: /Library/Filesystems/tuxera_ntfs.fs/Contents/Resources/Support/10.5/tuxera_ntfs
     Open file successfully!
     File size: 5958616 byte(s).
     Map file successfully!
     offset = 0x0000000000089382, writing data.....Patch is done.
     offset = 0x00000000001fe27c, writing data.....Patch is done.
     offset = 0x000000000034ec42, writing data.....Patch is done.
     offset = 0x00000000004cc178, writing data.....Patch is done.
     Modified: 4
    

    You will get tuxera_key.bin file at current directory.

  3. Re-codesign Tuxera NTFS. Because we made a patch to tuxera_ntfs.fs and Tuxera NTFS.prefPane, their original code signatures became invalid. So we have to re-codesign them. In console:

     $ sudo codesign -f -s "your code-sign certificate name" /Library/Filesystems/tuxera_ntfs.fs
     $ sudo codesign -f -s "your code-sign certificate name" /Library/PreferencePanes/Tuxera\ NTFS.prefPane
    

    NOTICE: "your code-sign certificate name" should be the name of your code-sign certificate, which is displayed in Keychain.app.

  4. Run TuxeraNTFS-keygen to generate the product key. In console:

     $ ./TuxeraNTFS-keygen ./tuxera_key.bin
    

    Example:

     $ ./TuxeraNTFS-keygen ./tuxera_key.bin
     -----secp112r1 Private Key-----
     Bin: 42 EE 5D 2C CD 53 0A 06 43 B9 9A 9E 29 B0
    
     -----secp112r1 Public Key-----
     Bin: X = C3 15 26 EC 75 DE AA 90 4C 70 7B 09 2B EC
     Bin: Y = 68 49 70 AA 04 3D 9F B3 DF 42 63 3D 55 FF
    
     Long product key: 4KPGHH-147M3Q-UHN3M2-C4DYAN-ENACL0
    
  5. Now you can see product key. Just use it to activate your Tuxera NTFS.