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:
CString OwnerName;
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."));
}
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;
RPNString.Format(_T("%-.5d"),
(int)EvaluateRPN(OwnerName,111));
if(RPNString.Find(m_strMyKey)==0)
{
Registered=TRUE;
}
else
{
AfxMessageBox(_T("Unregistered"));
Registered=FALSE;
}
The evaluation is done like this:
double CMyApplication::EvaluateRPN(CString strRPN, double m_nVariant)
{
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;
m_nStringValue+=m_nVariant;
return m_nStringValue;
}
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.