Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Secure Software Distributon SDK

0.00/5 (No votes)
25 Jul 2003 1  
SSD SDK provides security for your shareware programs through strong cryptographic techniques.

Index

Description

SSD SDK stands for "Secure Software Distribution SDK", and it offers several tools and code which will stop most cracking activities over your software. But first, we'll have a look on the most typical shareware schemes:

X Days/Uses trial scheme:

This scheme prevents your software to be used more than a defined number of days (usually 30) or executions. This kind of protection is easy to defeat because your software has to store the number of remaining days or uses in a secure place, and there is no secure place in any computer. These values can be encrypted or stored in "strange" locations, but it will only delay the inevitable, your trial period will be reset or extended to infinite.

Incomplete software releases:

It is very common to release two versions of the software, the full and the incomplete version. The full version is the one given to every user who has paid for the software. The incomplete version is freely released to the world, without caring about crackers, because they can't do anything against an incomplete software (well, they can write the absent pieces of code, but it would be a bit stupid...). Another issue is that malicious registered users can "lend" it to other users, violating the one-license-one-user distribution concept.

Unlocking software:

This kind of software has all the full-version characteristics but they are not available to the user, unless the user pays for an unlock code which unleashes all the power of the software. Under the commercial perspective, this is great, you only have to distribute a copy of the software, and wait till the unlock requests arrive. One simple e-mail with the unlock code will be enough to deliver your full software to any part of the world. Under the security and programming perspective, this is a hard problem... advanced tools such as low level-debuggers and disassemblers can be used to trace and analyze your applications and get the unlocking code generation algorithms, and also patch your application code to avoid the unlocking code protection.

SSD SDK has been developed to enhance the security of the applications using the third technique. It encrypts the non-public parts of your programs using strong cryptographic algorithms, and prevents the key sharing via asymmetric encryption.

Workflow

Well, you have in your hands the result of a lot of programming and debugging months... the final version of your software is ready, and you want to release it across the world through the World Wide Web. But you will not give it for free, what you want to do is to release it with a reduced functionality, and allow users to extend this functionality if they consider (after testing your program) that it is useful for them.

It's time to think a bit... when you create a software which unlocks itself, it only allows access to portions of code which have been there in every moment, so anybody can patch your software to avoid the security issues and run that code as usual. No matter if you use an external packer-compressor-protector... the program data and code will be in memory when it executes, so it can be dumped and rebuilt by an experimented cracker in a relative small amount of time. But... how can I protect my code in that case?!?!?!. The solution is to encrypt the code making it available only to registered users.

The encryption algorithms should be very carefully chosen. This will be discussed in the Algorithms and key lengths section.

Let's return to the first step, you have the software in your hand, for example, a MPEG compressor. This compressor features high speed compression and a fine audio/video quality, due to it's variety of compression algorithms, based on multiple hardware acceleration tricks, such as MMX, 3dnow! and SSE extended instruction sets.

You want to release your software allowing the user to take advantage of the MMX-based algorithms, but those who want to accelerate the compression using 3dnow! and SSE should upgrade to the full version. What you have to do, is to release your software with the extended algorithms encrypted. I will discuss later (in the Tools included section) about how to create a secure private key and encrypt your code using it.

Once your users have tested your software and know that they *need* 3dnow! and SSE extended algorithms, they should get the key to decrypt the code. This can be done in many ways, but the most common takes advantage of the public cryptography scheme, which allows to share private data between users without using secured channels to transmit private keys. Resuming, your user contacts you, sending a public key, which will be used to transmit the unlocking key. Finally, his "license file" is installed in the program directory and the security code verifies it and decrypts the code in memory. Every user has a different random public/private key pair. This ensures that your license will not be shared between different computers.

Compatibility

Your code is protected from the moment in that the executable file is processed and the code is encrypted. This step is done by an external tool which opens your executable file and looks in its section table for a section called .secure; this section contains your "protected" code and is fully encrypted.

This means that your compiler/linker should be able to place any code you want in a separate section with any name you want. At the moment of writing this article, only a compiler with this ability has been found, and it is Visual C++. If your know other compilers which can do this, please notify it to me.

Due to export restrictions, some encryption algorithms will not work in determinate countries. For example, a computer located in France using Windows 95, 98 or NT 4 will not encrypt data under some circumstances.

The API used (CryptoAPI 2.0) is available in Windows 95 OSR2 and later, so this code must work in "any" Microsoft 32-bit operating system.

Package contents

  • Command line tools: keygen.exe, licgen.exe and protect.exe. These tools help you create keys, protect your application and generate licenses.
  • Dynamic Link Library stub: ssdstub.dll. The file which should be carried out with your application. It looks for the license file and validates it every time your software is loaded.
  • C++ code files: ssdhelper.h and ssdhelper.cpp. Files including the functions defined in the Reference section.
  • C++ code sample: sample.cpp. Code including a simple application. You can use it to practice before protecting a "serious" project.

Tools included

The SSD SDK contains three tools. Quotes are required only when using spaced paths (i.e. c:\my docs\target.exe).

  • keygen.exe

    Creates a file with a random software key. The file must be securely stored in a safe place (i.e. CD-ROM, floppy, or an encrypted HD file). The command line arguments of this file are quite simple:

    keygen.exe "keyfile_path"

    If no file is specified, a file called private.key is created in the current working directory. Example:

    keygen.exe "c:\softwarekey.dat"
  • protect.exe

    Protects the specified executable using the specified key.

    protect.exe "executable_path" "secretkey_path"

    Example:

    protect.exe "c:\coding\project\project.exe" "c:\softwarekey.dat"
  • licgen.exe

    Creates the corresponding user license to the specified user public key and software key.

    licgen.exe "secretkey_path" "userkey_path" "output_path"

    Example:

    licgen.exe "c:\softwarekey.dat" "c:\userkeys\john.key" 
                                                   "c:\licenses\john.lic"

Reference

There is a final question to answer: How do my software create user keys, and validate licenses?... Don't worry about it, all this stuff is coded in a separate .dll file, you only have to call one of its simple functions to verify the security context. The functions are declared and implemented in a file contained in the same SDK package, so you only have to add these files to your project and include the header file everywhere you need it. The function specs are the following:

  • bool Initialize(const char *lpszApplicationName);

    Must be called as soon as possible in your program execution timeline (from the main function or the InitInstance CWinApp's member). This function verifies the licenses, if present, and decrypts the code if necessary. lpszApplicationName should be the same always for your application, if two different applications (or versions of the same application) use the same name, a key container conflict will occur and the result may be unpredictable. This function always checks for the license.key file, so do not use other names to the user license file.

  • void ExportKey(const char *lpszFilename);

    Creates a user public key file which should be sent to de developer to get the license key. You can send this file compressed using e-mail, or attach to the beginning (or the end) some user-related information, but remember that the license generator will not work if the header of the file has been corrupted, so strip its additional information before attempting to create any license from a given file. lpszFilename specifies the file to create the key.

  • bool IsUnlocked();

    Returns true if a license has been found and the software has been decrypted with it. Returns false if there is no license file or it is invalid.

Finally, you should know how to store your protected code in a separate section with a specified name. In the Visual C++ compiler/linker, this is done through the #pragma code_seg sentence, let's have a look on an easy example.

#pragma code_seg(push, r1, ".secure")
void CMyApplication::DoExtendedFunction() {
    // Do something cool ;)

}
#prgama code_seg(pop)

You can also store all the protected code in a separate file to avoid redundancy of #pragma code_seg declarations. This can be used also with non class member functions.

Algorithms and key lengths

All the tools and stub code described in this article have been coded using CryptoAPI 2.0. This API offers symmetric and asymmetric encryption routines, and also features key management, hashing and signing techniques. Used algorithms and key lengths are described in the following table:

Task Algorithm Key length
Code encryption RC4 Stream encryption algorithm 128 bits
Key sharing RSA Public-key exchange algorithm 1024 bits

As described in the excellent book "Handbook of applied cryptography", a secure encryption system bases its security in the key used to encrypt the message, and not in the privacy of the algorithm. In other words, no matter if the chosen algorithms have been published and tested for the scientific community around the world, its security resides in the extensive number of keys which can be used when encrypting. This ensures that it is necessary a large amount of resources (computer memory and clock cycles) to find a key which decrypts the message correctly.

Notes

This small SDK has been developed to show that it is not necessary to spend a lot of money to distribute our software under a good protection scheme. It is not perfect, but minor (or major) leaks and bugs will be covered in the future with other users' help.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here