|Title||Make a program register itself for a particular system in Visual Basic .NET|
|Description||This example shows how to make a program register itself for a particular system in Visual Basic .NET.|
|Keywords||cryptography, programs, register, registration, register program, Visual Basic .NET, VB.NET|
|Categories||Algorithms, Software Engineering|
This is a fairly simple technique. A determined hacker could circumvent it but for most programs it won't be worth the effort.
The idea is simple. When it starts, the program gets its disk drive serial number, encrypts it, and compares the result to a value stored on the computer. If the value matches, then the program is registered and starts normally.
If the value doesn't match or no value is yet saved on the computer, then the program displays a registration form giving the user a Product ID (the disk serial number) and asking the user to email this to Customer Support. Customer Support encrypts the serial number and sends it back for the user to enter into the registration form. The form then saves that value so the program can start normally in the future.
The following code shows how the main program checks whether it is properly registered.
' If the program isn't registered, exit.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal _
e As System.EventArgs) Handles MyBase.Load
' An arbitrary number to identify this program.
Const program_id As UInt32 = 2267918298
If (Not IsRegistered(program_id, False)) Then Me.Close()
This code simply calls the IsRegistered function, passing it a program id. This is simply an arbitrary number used to differentiate among different programs that might use the same registration procedure.
The following code shows how the IsRegistered function works.
' Return true if the program is properly registered.
Private Function IsRegistered(ByVal program_id As UInt32, _
ByVal default_value As Boolean) As Boolean
Dim volume_name As New StringBuilder(1024)
Dim file_system_name As New StringBuilder(1024)
Dim serial_number, max_component_length As UInt32
Dim file_system_flags As FileSystemFeature
' Get the startup directory's drive letter.
' Get the drive where the program is running.
Dim file_info As New FileInfo(Application.StartupPath)
Dim drive_letter As String = _
' Get the information. If we fail, return the default
If (GetVolumeInformation(drive_letter, volume_name, _
CUInt(volume_name.Capacity), serial_number, _
file_system_flags, file_system_name, _
CUInt(file_system_name.Capacity)) = 0) _
' Encrypt the serial number to get the product key.
Dim product_key As UInt32 = Encrypt(program_id, _
' If this matches the saved product key, then the
' program is registered.
If (My.Settings.ProductKey = product_key) Then Return _
' It's not registered properly.
' Display the registration form.
Dim frm As New RegistrationForm()
frm.txtProductNumber.Text = serial_number.ToString()
If (frm.ShowDialog() = DialogResult.Cancel) Then Return _
' See if the product key matches.
Dim entered_key As UInt32 = 0
entered_key = UInt32.Parse(frm.txtProductKey.Text)
If (entered_key = product_key) Then
My.Settings.ProductKey = entered_key
' No match. Give up.
MessageBox.Show("Incorrect product key.", "Invalid Key", _
The code the GetVolumeInformation API function to get information about the disk containing the program's startup path. It then encrypts the disk's serial number to get a Product Key. If that value matches the value stored in the ProductKey program setting, the program is registered so the function returns true.
(To create the ProductKey setting at design time, open the Project menu and select Properties. On the Settings tab, create a new setting named ProductKey with type uint.)
If the encrypted serial number doesn't match the ProductKey setting, the code displays a RegistrationForm. If the user enters a Product Key and clicks OK, the program parses the value and compares it to the encrypted serial number. If the values match, then the user has entered the correct product key so the function saves it and returns true.
The following code shows how the Encrypt function encrypts a UInt32.
' Simple encryption and decryption.
Private Function Encrypt(ByVal seed As UInt32, ByVal value _
As UInt32) As UInt32
Dim rand As New Random(CInt(seed \ 2))
Return (value Xor CUInt(UInt32.MaxValue * _
This function creates a new Random object, initializing it from a seed parameter. By using the same seed (in this case, the program ID), different programs can initialize the random number generator to the same state.
The function generates a random number between 0.0 and 1.0 and multiplies it by the largest possible UInt32 value. It then uses the XOR operator to combine that value with the value it is encrypting.
(Note that this method also decrypts. If you pass it an encrypted value and the seed that was used to encrypt it, it will generate the same pseudo-random number and XOR it with the encrypted value. That restores the original value. Note also that this property isn't necessary for this program. The program never decrypts any value.)
The final piece to the puzzle is the KeyMaker program that Customer Support uses to generate Product Keys. This program simply takes an entered Program ID and Product ID. It calls the same Encrypt function passing it the Program ID as the seed and the Product ID as the value to encrypt. The result is the Product Key, which Customer Support emails to the customer.
There are a few improvements you could make to this method.
- You could use stronger encryption. If you're really worried that hackers will break open your code, however, then you should consider stronger methods for verifying customers such as making the program validate itself with a Web Service every time it runs.
- You could obfuscate the Product ID so the user can't notice that it's just the disk serial number.
- You could reformat the Product ID and Product Key so they form groups of letters instead of a simple number.
- You could try using the serial number of the computer's CPU instead of the disk.