Android Tutorial Protect your Android application with the Licensing library

The licensing library allows you to use Android market licensing service to verify that the user is allowed to access your application.

Your applications sends a request to the local market application. The market application contacts the market server and returns the result. The result is cached based on the market rules.

It is recommended to go over Google's documentation related to the licensing method: Application Licensing | Android Developers

Configuring the licensing library is simple. You should first have a publisher account in the market.
The license key is available in Google Play developer console under Development tools - Services & APIs.

The licensing library and service will not prevent a dedicated hacker from hacking your application. It will however make it more difficult.

The first step is to initialize a LicenseChecker object:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim lc As LicenseChecker
   Dim p As PhoneId
   lc.Initialize("lc", p.GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
   lc.SetVariableAndValue("test_1", "some secret value")
   lc.CheckAccess
End Sub
The result of the licensing check is cached locally. The cache is encrypted with AES algorithm. In order to avoid users from tampering with the cache and copying the cache to different devices, the device id is used together with the package name as the password.

Note that the same user will be able to download your application to other devices running with the same user account.

PhoneId (from the Phone library) requires the READ_STATE permission. The protection will still work if you pass an arbitrary string. It will be weaker however.
The Salt parameter should be an array of bytes with some random values (the values should be the same on each run).

Edit: It is recommended to use the alternative id method as described here: http://www.b4x.com/forum/basic4andr...oid-device-unique-id-alternative-phoneid.html

The next step is to call lc.CheckAccess. This in turn calls the market application or the local cache and checks whether the user is allowed to access the program.
One of the following events will be raised when the result arrives: Allow, DontAllow or Error (ErrorCode As String).
It is up to you to handle the event subs as required.

LicenseChecker.SetVariableAndValue
A simple way to hack an application is to "jump over" the checking code. For example a hacker might remove the call to CheckAccess and instead call your Allow event sub.
In order to make it a bit more complicated you can call LicenseChecker.SetVariableAndValue.
For example:
B4X:
lc.SetVariableAndValue("test_1", "some secret value")
The above code will set the value of a process global string value in the main activity named test1 to "some secret value" if the check was successful. You should not use or test the value of test1 in the Allow event sub as it will be too obvious. Instead you should use it later in your program.
You can be creative and pass the name of the variable or the value by using BytesToString or some other way.
As this variable is accessed in a dynamic way it will fail when the code is obfuscated. Therefore you need to include an underscore in the variable name to prevent it from being obfuscated. For example: test_1.
Note that SetVariableAndValue method will fail when running in rapid debug mode as the variable is part of the "debugger engine".

A more complete example:
B4X:
Sub Process_Globals
   Dim publicKey As String
   publicKey = "MIIBIjANBgkqhAADSFEFEFkiG9w0BfW/cGhTbtIs6QIDAQAB..."
   Dim test_1 As String
End Sub
Sub Globals

End Sub
Sub Activity_Create(FirstTime As Boolean)
   Dim lc As LicenseChecker
   Dim p As PhoneId
   lc.Initialize("lc", p.GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
   lc.SetVariableAndValue("test1", "some secret value")
   lc.CheckAccess
End Sub
Sub lc_Allow
   Log("Allow")
End Sub
Sub lc_DontAllow
   Log("DontAllow")
   ToastMessageShow("Closing application.", True)
   Activity.Finish
End Sub
Sub lc_Error (ErrorCode As String)
   Log("error: " & ErrorCode)
   ToastMessageShow("Closing application.", True)
   Activity.Finish
End Sub
Sub Activity_Pause(UserClosed As Boolean)
 
End Sub
Sub Activity_Resume

End Sub

The library is available here: http://www.b4x.com/forum/additional-libraries-official-updates/11430-licensing-library.html
 
Last edited:

wheretheidivides

Active Member
Licensed User
Longtime User
Erel, is there any way you could update you 1st post with the code to use without the phone permission? You send use to another page for more code, but was wondering if you could post 1 example of how this works. Also, sense you say that devices without phones will fail, then could you just show the whole code? I am not sure how to get the e2nd example code to work with the first example code.



Thanks
 
Last edited:

MrKim

Well-Known Member
Licensed User
Longtime User
How Long does 'Lc_Allow' last

I think I am finally beginning to understand how all of this works, and some testing has shown that if an app is disallowed Android seems to recheck each time it is loaded.

If the app is allowed and the connection fails it is still allowed. My question is this. How long does Android continue to approve an app once it has been allowed?

Also, after testing a few times it seems to stop querying the server and giving the same answer over and over. Is there some limit on how often you cna query for the License Test Response?
 

NFOBoy

Active Member
Licensed User
Longtime User
*This post was in response to a question about where to find the license key, but I don't see the post anymore..."

Bryan,

I just went to my developer account (I'm using the new view) and clicked on "+Add New Application" button near the top of the page.

Then, I put in my new app's name, and clicked on "Prepare Store Listing"

Then I went to the Service and API's tab, and on that page is the Key required for my app if I want to use the licensing feature. Under "Your License Key for this application"

If I recall correctly, it sounds like you are using the old view method?
 
Last edited:

Bryan

Member
Licensed User
Longtime User
Sorry, I removed the post because I figured out how to get the key myself without actually uploading a APK to them. They make it sound like you have to actually upload one first before you can get a key.

Bryan
 

Bryan

Member
Licensed User
Longtime User
Well I have the Licensing part done for the Main Activity and it seems to be working fine. Tried on my device (Galaxy 5 Player). And it shows up licensed.
Installed to a different Android tablet and it comes up as not licensed which it should.

I didn't think about the Service Mod I created with the Main Activity which creates a Widget. How do I add licensing to that? I tried a similar approach
like I did with the main activity but for some reason the service unexpectantly shuts down giving an error on the screen of the device.

This is what I tried with a few non related things removed. Is this correct or am I way off here. Anyway to use the license check that is done in the Main Activity here? If so how?

B4X:
Sub Process_Globals
   Dim rv As RemoteViews
   Dim wavButton As MediaPlayer
              Dim publicKey As String
              publicKey = "MIIB....."
End Sub

Sub Service_Create
             Dim test_1 As String
             Dim lc As LicenseChecker
   rv = ConfigureHomeWidget("The_Widget", "rv", 0, "T_Widget")
   lc.Initialize("lc", GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
   lc.SetVariableAndValue("test_1", "123")
   lc.CheckAccess
              wavButton.Initialize
   wavButton.Looping = False
   wavButton.Load(File.DirAssets, "noise.mp3")
End Sub


Sub Service_Start (StartingIntent As Intent)
   If rv.HandleWidgetEvents(StartingIntent) Then Return
End Sub

Sub lc_Allow
Log("Allow")
ToastMessageShow("License Valid", True)
End Sub

Sub lc_DontAllow
Log("DontAllow")
ToastMessageShow("Not Licensed", True)
End Sub

Sub lc_Error (ErrorCode As String)
Log("error: " & ErrorCode)
ToastMessageShow("Error Closing application.", True)
End Sub


Sub GetDeviceId As String    
      Dim r As Reflector    
      Dim Api As Int    
      Api = r.GetStaticField("android.os.Build$VERSION", "SDK_INT")    
If Api < 9 Then       
If File.Exists(File.DirInternal, "__id") Then                    
      Return File.ReadString(File.DirInternal, "__id")            
      Else                    
     Dim id As Int                    
     id = Rnd(0x10000000, 0x7FFFFFFF)                    
     File.WriteString(File.DirInternal, "__id", id)                    
     Return id            
End If    
Else                   
     Return r.GetStaticField("android.os.Build", "SERIAL")    
End If
End Sub

Sub check
    Dim chkifnum As Int
    If IsNumber(test_1) = False Then   
       Msgbox("Failed License Check", "ERROR")
    End If
End Sub



Sub Button1_click
      check
      wavButton.Play
End Sub


Sub rv_RequestUpdate    
rv.UpdateWidget
End Sub

Sub rv_Disabled    
StopService("")
End Sub

Sub Service_Destroy
End Sub

Help is always appreciated.
Bryan


OK, think I have it working now. I replaced

lc.Initialize("lc", GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8")) with
lc.Initialize("lc", p.GetSettings("android_id"), publicKey, "kljdflkf".GetBytes("UTF8"))

and got rid of the GetDeviceId sub.



Well updating this post again. It seemed to work fine but after uninstalling it again and doing a new compile it is failing with an unexpected closing of the widget service. Back to drawing board.
 
Last edited:

Bryan

Member
Licensed User
Longtime User
Appears everything works up to the point of lc.CheckAccess. When this is called it looks for Sub lc_Allow (is allowed because it passes license check) and then the service mod will not start. Widget becomes non-functional and sometimes an get error displayed that the process cannot start.

If I remove Sub lc_Allow then the service mod continues, and is started, but generates an error it cannot find lc_allow, in the log. Which is expected.

License checking is working properly for the main Activity.

I am away from my computer at home right but will try to provide a log for you later.

Thanks,
Bryan

I didn't change anything, or do anything different then what I mentioned above and now its working again. Very strange. Same code as last night and it didn't work. Today I turn on my device and it's working. The service mod gets it's proper authorization and starts, displaying ToastMessageShow "License Valid".
I will probably need to investigate this more if it fails again.
 
Last edited:

palmzac

Active Member
Licensed User
Longtime User
Problem: License check with obfuscated

Hi,

I have a code with License Library that It work find on NORMAL RELEASE. There is problem that this code with obfuscated function does not work normally. Would you give me a sample code ? ( License check with obfuscated )

Thanks !
 

palmzac

Active Member
Licensed User
Longtime User
Hi,

This is my sample code. Would you help me ? Thanks !

//------------------------------

#Region Module Attributes
#FullScreen: False
#IncludeTitle: True
#ApplicationLabel: Sample Code
#VersionCode: 16
#VersionName:
#SupportedOrientations: portrait
#CanInstallToExternalStorage: False
#End Region

'Activity module
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim server As ServerSocket 'Add a reference to the network library
Dim networkOK As Int

'License Lib Use
Dim public_Key As String
public_Key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnOV9SgrW9iEFckScwAmVKW/1sJk+AYATodloVK+HWsOOYt0QWmizBOIGDrnlKj16F7VhWyqtHim6h4IRDWDLbfuX41guH5cDy6Mzeo1lHS/GJ2n9CMO5JDiUmgdAHvkZSRY7CUz+rHIDNKWfmyQGkSmSIcdAXI1e0PGg5jo7jwWVCdnf5YCwkbRGcxboOq1kK1Ysxv6+DMseR/HWnTzk65L/P7havhOml1ua9xWWtBKAUHVr+x2j6GWsEeTHJ/XqgmLt5SrYu9psPvmipLAGETGngA+X+8Km9hci3FG47MaIf/ya3BKn1QF7LONt96+KYDrN+C+HuiMK2145BzgUiQIDAQAB"
Dim sc_vvv1 As String
Dim pc_vvv1 As String
pc_vvv1 = "adg135piy"

Dim to_vvv1 As Boolean
' Test Only Flag
to_vvv1 = False

End Sub

Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.

End Sub

Sub Activity_Create(FirstTime As Boolean)

Activity.LoadLayout("loMain")
Activity.Title = "Sample Code"

' to_vvv1 = True

' Dim server As ServerSocket 'Add a reference to the network library
server.Initialize(0, "")
networkOK = 1 ' 1 is OK , 0 is failure
If server.GetMyIP = "127.0.0.1" Then 'this is the local host address
networkOK = 0
End If

' License Check
If FirstTime Then
Log("Check Market")
Dim lc_vvv1 As LicenseChecker
Dim p As PhoneId
Dim kljdflkf_88 As String
Dim pk_vvv1 As String
pk_vvv1 = public_Key
lc_vvv1.Initialize("lc_vvv1", p.GetDeviceId, pk_vvv1, "kljdflkf_88".GetBytes("UTF8"))
lc_vvv1.SetVariableAndValue("sc_vvv1", pc_vvv1 )
If to_vvv1 = False Then
lc_vvv1.CheckAccess
End If
End If
' End License

If to_vvv1 = True Then
sc_vvv1 = pc_vvv1
End If

End Sub

Sub lc_vvv1_Allow
Log("Allow !")
End Sub

Sub lc_vvv1_DontAllow
Log("DontAllow !")
ToastMessageShow("??? !", True)
Activity.Finish
End Sub

Sub lc_vvv1_Error (ErrorCode As String)
Log("error: " & ErrorCode)
ToastMessageShow("???", True)
Activity.Finish
End Sub

Sub Activity_Resume

server.Initialize(0, "")
networkOK = 1
If server.GetMyIP = "127.0.0.1" Then 'this is the local host address
'no connection
networkOK = 0
End If

If networkOK == 1 Then
Dim lc_vvv1 As LicenseChecker
Dim p As PhoneId
Dim kljdflkf_88 As String
Dim pk_vvv1 As String
pk_vvv1 = public_Key
lc_vvv1.Initialize("lc_vvv1", p.GetDeviceId, pk_vvv1, "kljdflkf_88".GetBytes("UTF8"))
lc_vvv1.SetVariableAndValue("sc_vvv1", pc_vvv1 )
If to_vvv1 = False Then
lc_vvv1.CheckAccess
End If
End If

End Sub

Sub Activity_Pause (UserClosed As Boolean)

If ( UserClosed = True ) Then
ExitApplication
End If

End Sub

Sub ButtonGo_Click
If ( ( networkOK == 1 ) AND ( sc_vvv1 == pc_vvv1 ) ) Then
StartActivity( Agree )
Else
Msgbox("????","Error")
End If
End Sub

// --------------------------------------------

In which way doesn't it work? If you are using SetVariableValue then you should make sure that the variable includes an underscore. See the first post.
 

palmzac

Active Member
Licensed User
Longtime User
Hi,

This is a dialog message. Thanks !

// -------------------------------

Error occurred

An error has occurred in sub: main_activity_create (java line:272 ) java.lang.illegalArgumentException: com.android.vending.licensing.util.Base64DecoderException: Bad Base64 input character at 0: 20 (decimal ) Continue ?

// ----------------------------------

Your code looks correct. Which error do you get?
 

palmzac

Active Member
Licensed User
Longtime User
Hi Erel,

Thank for your help ! ^_^ I will try.

But, it work fine on NORMAL RELEASE. Why ? Would you tell me more ?

regards,
Palmzac

The problem is that you checked "Do not overwrite manifest file". The VersionCode set in the IDE (and used by the obfuscator to obfuscate the strings) cannot be set in the manifest file. You should instead use the manifest editor.
 
Last edited:

peacemaker

Expert
Licensed User
Longtime User
Did anyone check lib work with the new Play Market 4 ?

Couple of my app end-users complaints that paid access by the in-app - does not work now... Before was working OK.
 
Top