All posts

How to add licence keys with an HWID lock to a C++ Windows app

Add licence keys, a one-PC lock and a live kill switch to a native C++17 Windows program with the free PWF Auth client: two files on WinHTTP and Windows CNG, a sign-in, the heartbeat and moving a licence to a new PC

3 min read

Native C++ programs are often the ones worth protecting most: tools, game utilities, plugins. The PWF Auth C++ client gives them licence keys, a lock to one PC and a kill switch, with no runtime to install. It is plain C++17 on Windows' own building blocks: WinHTTP for HTTPS, Windows CNG for the encryption, and nlohmann-json from vcpkg

Step 1: create the application

Sign in to your panel, open Applications and press New application. Give it a name: the app secret is made for you

Step 2: add the client to your project

Download the latest release and copy four files into your project:

  • PwfClient.h and PwfClient.cpp: the client itself
  • ServerPublicKey.h: the public key the client checks every server reply with
  • ProductionPolicy.h: the server addresses the client may talk to

Add nlohmann-json with vcpkg (the sample project's vcpkg.json does it on the first build) and build with C++17 in Visual Studio

Put the app secret in at build time and never commit a real secret to a public repository

Step 3: sign in and start the heartbeat

#include "PwfClient.h"

PwfClient client(appSecret);

client.SetSessionEndedCallback([](const std::string& code, const std::string& message) {
    // banned, paused, expired, reset, ended from the panel, or no server for 90 seconds
    PostQuitMessage(0);
});

PwfResponse login = client.Login(licenseKey);
if (!login.Success()) {
    ShowError(login.Message());   // written for the customer
    return;
}

client.StartHeartbeat();   // the kill switch: never skip it

StartHeartbeat() checks in with the server every 30 seconds. Ban, pause or expire the key in your panel and the callback runs on the next check-in. Three check-ins in a row without an encrypted answer end the session with NETWORK_LOST, so blocking the server in a firewall doesn't keep a banned copy running

Step 4: move a licence to a new PC

A key is bound to the first PC that signs in with it. When it is used on another PC, the sign-in answers HWID_MISMATCH (or DEVICE_LIMIT for a key allowed on several PCs). Offer to move it:

if (login.ErrorCode() == "HWID_MISMATCH" || login.ErrorCode() == "DEVICE_LIMIT") {
    PwfResponse moved = client.ResetHardwareId(licenseKey, "Moved to a new PC");
    if (moved.Success())
        login = client.Login(licenseKey);
    else
        ShowError(moved.Message());   // for example the waiting time between two moves
}

You decide in the panel whether customers may move keys themselves, and how long they wait between two moves

Customer accounts

Turn customer accounts on for the app and your customers can sign in with a username and a password instead of a key:

PwfResponse made = client.RegisterAccount("alice", "a-strong-password", "alice@example.com");
PwfResponse login = client.AccountLogin("alice", "a-strong-password");
if (login.Success()) client.StartHeartbeat();

// later: a key bought from a reseller adds its time to the account
PwfResponse added = client.RedeemKey("XXXXX-XXXXX-XXXXX-XXXXX");

Built to resist a fake server

Every request carries a fresh random value, and every reply must carry the server's RSA signature over that exact request and reply. Knowing your app secret is not enough to fake an answer, and an unsigned or altered reply is refused before it is even read. A wrong PC clock repairs itself: when the server refuses the time, the client takes the server's clock and tries once more

The hardware ID is the same one the .NET, Python and Node.js packages use, so one PC counts as one device whatever language your apps use

The client on GitHub

Protect your app for free

Licence keys, customer accounts and the kill switch, in every language. Make an account and sign in with your first key in a few minutes

Create a free account