Click here to Skip to main content
Click here to Skip to main content

RPN Dynamic Registration Model

, 5 Mar 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
An article implementing RPN in a Pocket PC application.

Introduction

When developing and marketing software for the mobile community, the most common registration model used is RPN (Reverse Polish Notation) or Dynamic Registration. Just how to implement this is sometimes confusing so I would like to make it simple. In a nutshell, Reverse Polish Notation uses a formula in the form of a string that you provide to the distributor. When a customer purchases your application, they provide the distributor with the C/DUI of the device for which the application is to be installed. The C/DUI is a unique device identifier, and it varies between platforms.

  • Pocket PC: Owner's first and last name or some variation.
  • Symbian OS: IMEI in the following format, including hyphens: 350443-61-001241-9.
  • Palm OS: Palm user name.

In this article, we will only discuss the Pocket PC application of this registration model.

About the model

The RPN string that you provide to the distributor looks something like this:

"i 0 == m_nVariant * key + c 5 * +"

m_nVariant is a number you use to make the result differ from anyone else's who is using the same formula. In the sample, we will use 111 as a variant:

"i 0 == 111 * key + c 2 * +"

The only three variables allowed in an RPN string: key, i, and c. There is no variable for RPN string length.

Dynamic registration code generation is done using 32-bit signed integers, and the final result is converted to a 16-bit unsigned integer. The 32-bit signed integer result is converted to a 16-bit unsigned integer by masking off all but the lowest order 16 bits. For example, if the final result is -3 (0xFFFFFFFD), then the last or lowest order 16 bits would be 0xFFFD HEX which is unsigned decimal 65533. The variable c is considered to be an unsigned 8-bit integer. The smallest possible registration code is 0, and the largest possible registration code is 2^16 - 1 = 65535. If a registration code is fewer than five digits, 0s are added to the front to make it five digits. So, 763 becomes 00763. Because only integers are used in the dynamic registration code generation, 763 / 10 = 76, and not 76.3. Consequently, decimals never appear in a dynamic registration code.

Also, the program that processes RPN strings puts a limit on the number of characters processed. If a handheld device ID exceeds 10 characters, only the first five and last five characters are used to generate the unlock code.

Don Laverdure is 13 letters (including the space), so the first and last 5 are used: "Don Lrdure".

Non-cumulative operations are evaluated from left to right, so 7 3 - = 4 (not -4).

Currently, 16-bit characters such as Japanese, Chinese, Greek, or Hebrew characters are not supported in this process as the variable c is treated as an 8-bit unsigned integer.

We convert each character of the C/DUI to ASCII value. For example, "Will P":

W = 87 decimal
i = 105 decimal
l = 108 decimal
l = 108 decimal
[space] = 32 decimal
P = 80 decimal

We apply the RPN string to the ASCII value of each character in the C/DUI. In the formula, 'i' is the position of the character in the C/DUI starting at 0, and 'c' is the ASCII value of the character in the C/DUI.

For "Will P":

87 + 105 + 108 + 108 + 32 + 80 = 520; 520 * 2 = 1040;
1040 + 111 = 1151

An RPN string of "i 0 == 111 * key + c 3 * +" would add up the ASCII values of all the characters in the C/DUI. Multiply that by 3 and add 111 to that.

So, for "Will P":

520*3=1560; 1560 + 111 = 1671

An RPN string of "i 0 == 987 * key + c +" would add up the ASCII values of all the characters in the C/DUI and add 987 to that.

So for "Will P":

520 + 987 = 1507

RPN strings can be much more complex than this. Just about any operator is allowed:

  • Logical operators such as &&, ||, !, ==, >=
  • Bitwise operators such as << (shift left), >> (shift right), ~ (invert), & (AND), | (OR)
  • Arithmetic operators such as +, -, *, /, % (modulo)

Using the code

First, we need to obtain the C/DUI from the Pocket PC. The owner name is stored in the registry key HKEY_CURRENT_USER\ControlPanel\Owner:

//Many Registry classes can be found elsewhere on 
//the code project

CString OwnerName; // This will hold the C/DUI

DWORD dwR2;
unsigned char Owner[255];
if (!reg.Open(HKEY_CURRENT_USER, 
        _T("ControlPanel\\Owner"),false))
   {
      AfxMessageBox(_T("Can't find Owner, ") 
           _T("error detected, Attempting to correct."));
      // Error handling for no
      // registry key present goes here
   }

if(reg.GetLength(_T("Owner"),dwR2))
   {
      reg.Read(_T("Owner"),Owner,dwR2);
      OwnerName.Format(_T("%s"),&Owner);
   }

//

Once we have the C/DUI, usually during the initialization of your project, we will check it against the RPN to see if the application is already registered.

When the user enters the RPN obtained from the distributor, write it to the registry or an ini file so that it can be retrieved every time the application starts.

CString m_strMyKey;
m_strMyKey=pApp->GetProfileString(_T("Initialize"), 
                                     _T("Key"));

CString RPNString;
// Run the owner's name through the RPN
// evaluation and assign the 5 digit result.
RPNString.Format(_T("%-.5d"), 
                (int)EvaluateRPN(OwnerName,111));
if(RPNString.Find(m_strMyKey)==0)
// Compare the C/DUI RPN to the RPN in the registry
{
   Registered=TRUE;
}
else
{
   AfxMessageBox(_T("Unregistered"));
   Registered=FALSE;
}

The evaluation is done like this:

double CMyApplication::EvaluateRPN(CString strRPN, double m_nVariant) 
{
    // RPN = "i 0 == m_nVariant * key + c 5 * +" 
    CString m_strRPN;
    double m_nStringValue=0;
    int StringPos=0;

    if(strRPN.GetLength()>10)
    {
        m_strRPN=strRPN.Left(5) + strRPN.Right(5);
    }
    else m_strRPN=strRPN;

    do
    {
        m_nStringValue += (double)m_strRPN.GetAt(StringPos);
        StringPos++;
    }while(StringPos <= m_strRPN.GetLength());


    m_nStringValue=m_nStringValue*5; // c5*

    m_nStringValue+=m_nVariant;

    return m_nStringValue;
}
// This code evaluates the string using
// the sample formula, more complex formulas
// will require more complex evaluation code.

Points of interest

Dynamic registration protects you, the author, because the dynamic registration code that the user must enter to unlock your application depends on what the C/DUI on their handheld device is. Since different users select different C/DUIs for some handheld devices, a dynamic registration code that unlocks your application on one handheld device probably won't work on another handheld device. The only way the same dynamic registration code will work on two different handheld devices is if those two handheld devices have the same C/DUI. As you can see, this helps prevent piracy because the only way a pirate could copy your software from his friend would be to make sure that the C/DUI on his handheld device is the same as the C/DUI on his friend's. It becomes more tedious and impractical for the pirate to change his C/DUI each time he wants to run a different application.

Combating hackers is a full-time-job for some people, and like they say, "Locks only keep the honest people out", so this easy to implement code will "keep the honest people buying your applications" without you having to spend more time securing your app than writing it.

History

  • 28th Feb, 2006 - Article first published.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Don Laverdure
Software Developer
Canada Canada
I develop truck and automotive diagnostic software

Comments and Discussions

 
GeneralRPN Gotchas Pinmemberjaybonomad25-Mar-06 12:22 
Thanks for helping to elucidate this rather murky subject. I'd like to add my own experiences with RPN Registration, and especially the gotchas you may encounter due to poor vendor implementations.
 
1. Vendors/Distributors calculate RPN codes differently.
The issue seems to be mostly related to whether 16 or 32 bit intermediate results are used inside the RPN computation loop. In particular:
 
Handango - 32 bit intermediate computations
PDATopSoft - 16 bit intermediate
Mobile2Day - 16 bit intermediate (but watch out for "key": requires "key" not "k")
PocketLand - 16 bit intermediate
Pocketgear - 16 bit, but current version (V2) overflows differently than other vendors, so don't use large left shifts or other operations which create large RPN values.
 
Yes, this is a nightmare!
 
As a work-around, my own implementation allows you to set a flag to use either 16 or 32 bit intermediate results when computing the RPN code, and both versions are tried when validating a user code.
 
Another work-around might be selection of RPN strings which always keep generated values under the 16-bit threshold, but I don't know the reliability of this route.
 

2. As you mentioned in your article, Unicode support is not defined. This is a major problem for international customers who often use Unicode to enter their registered names. Currently, no vendor allows entry of Unicode so RPN Registration is basically broken for international customers.
 
For my own site, and in my own RPN implementation, I've simply taken the least significant 8 bits of each Unicode character, and I'd like to propose that this extenstion be widely adopted. Although not ideal in terms of cryptographic complexity, it seems adequate for the purposes of RPN Registration.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411028.1 | Last Updated 5 Mar 2006
Article Copyright 2006 by Don Laverdure
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid