You deploy a file with the user account information signed by the server. The public key used to verify the signature can be safely deployed along side. This allows the application to verify the signature, ensuring that the user account information was validated by the server.
Of course, the user could move the application along with all the necessary files and have it work in a different device, is that a concern?
You may want to include as account information some fingerprint of the platform (e.g. volume serial number). That way the application can check if it matches the current platform where it is running.
Of course, the user could trick the software by using a debugger or similar. Is that a concern?
There are solutions to detect if the application is running with a debugger attached (often used by expensive proprietary software).
I am also aware of Joanna Rutkowska work on detecting virtualization software (a.k.a the blue pill). I haven't seen it in the wild. Yet, you might be interested in how that works.
At the end, it all ends in a conditional jump somewhere in the code. All a crack needs to do is flip the conditional (deter with obfuscation), and any invalid credential will grant access. Is that a concern?
Something you can do to mitigate this is to sign the executable. Ern... Yes, the user can still run applications with an invalid signature... hmm...
You can store (premium) components of the application under a cipher, with a custom key derived from a hash of the account information. Then the software would hash the account information, perform the key derivation algorithm, and use the key to decipher the application components.
By doing this, the only way to use the application components is to have the right key. Alright, this is not perfect security either. The cracker would deploy already deciphered components and bypass the routine described above.
Expiration date?
You can store the expiration date along with the account information. That way the user cannot change it without making the signature fail. And (assuming the application has not been modified to do so) the application would reject account information with an invalid signature.
However, the user is in control of the system time. The application needs to check on given events the system time to make sure it is moving forward. Which also means that the application needs to store the last seen system time, so that changing the clock while it is not running does not trick it.
Oh, where does it store the last seen system time? The user could just modify that. If it is under a cipher or with a signature, the key must be on the machine... so, hmm... poker face. Actually, that is probably enough to deter most people.
I do not know what Spotify does. The following is a solution I have come up with. Have the server:
- Create a file. Optional: make the initial contents of the file a seed value.
- Generate a fixed size value.
- Append it to the file.
- Sign the content of the file with a private key.
- Append the signature to the file.
- Repeat from step 2.
You are going to do this a few hundred or thousand iterations. You should have a file of a few megabytes. I will refer to this file as a Cryptographic Countdown™.
Deploy the cryptographic countdown and the public key used to generate it along side the application. Each few minutes (say, 10 minutes of play time) or uses (say, play a song), the application will go to the cryptographic countdown and replace the last valid entry with random values (to make it harder for forensic tools to recover the countdown).
If you are counting time, you might have the server use date-time values (with some random padding) for the step 2. For uses, it can be fully random.
When the application starts, it can verify the Cryptographic Countdown using the public key. The number of valid entries tell you how much is remaining in the trial. It is also possible to store the number of the last valid entry for quick access, then the application can go directly to verify that one.
To prevent this cryptographic countdown from being used by another user, you can derive the seed from the the account information.
Oh, to by pass this, you need to back it up upon installation. When it runs out, restore the cryptographic countdown from your back up (and set back the system time, if it is time based). The application would let you in again. This process can be automated. It would be inconvenient, which is a deterrent.
Please note it is possible (given enough time and resources) to bypass the measures I mention here, creating a cracked version. And you only need one person to make the cracked version and deploy it to everybody.
The only way to truly prevent piracy is to have a server under your control.