Crates.io | portal-pc-license-key |
lib.rs | portal-pc-license-key |
version | 0.3.0 |
source | src |
created_at | 2024-10-10 22:55:02.600958 |
updated_at | 2024-10-10 23:22:17.289398 |
description | A license key system. |
homepage | |
repository | https://github.com/patriksvensson/license-key |
max_upload_size | |
id | 1404685 |
size | 41,181 |
A library for generating and verifying license keys without requiring an Internet connection. For further protection, you can of course validate the license key over the Internet.
For more information, read Implementing a Partial Serial Number Verification System in Delphi which this crate was based upon.
Every license key consists of a seed, a payload and a checksum. Each byte in the payload is an operation of the seed and an initialization vector. The 16-bit checksum is there to quickly check if the key is valid at all, while the seed is a 64-bit hash of something that identifies the license key owner such as an e-mail address or similar.
The size of the payload depends on how big the initialization vector is. In the example below, we are using a 5-byte intitialization vector which results in a 5-byte payload.
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│0x0│0x1│0x2│0x3│0x4│0x5│0x6│0x7│0x8│0x9│0xa│0xb│0xc│0xd│0xe│0xf│
├───┴───┴───┴───┴───┴───┴───┴───┴───┼───┴───┴───┴───┴───┼───┴───┤
│ SEED │ PAYLOAD │ CHECK │
│ │ │ SUM │
└───────────────────────────────────┴───────────────────┴───────┘
use license_key::*;
// Define a hasher that will hash the seed and a initialization vector.
// DON'T USE THIS ONE. It's only for demonstrational purposes.
struct DummyHasher { }
impl KeyHasher for DummyHasher {
fn hash(&self, seed: u64, a: u64, b: u64, c: u64) -> u8 {
((seed ^ a ^ b ^ c) & 0xFF) as u8
}
}
// Create a license generator
// We use only four triplets in our initialization vector,
// but in a real world scenario you would want to use a lot more.
let generator = Generator::new(
DummyHasher { },
vec![
// DON'T USE THIS ONE.
// Generate your own.
(114, 83, 170),
(60, 208, 27),
(69, 14, 202),
(61, 232, 54)
],
);
// Generate a license key using a seed.
// A seed is unique per license key, and could be a hash of an e-mail address or similar.
// You can later block individual seeds during verification.
let key = generator.generate(1234567891011121314_u64);
// Write the key in hex format to the console.
// This will output something like: 112210F4B2D230A229552341B2E723
println!("{}", key.serialize::<HexFormat>());
use license_key::*;
// Use the exact same hasher that we used when generating the key
struct DummyHasher { }
impl KeyHasher for DummyHasher {
fn hash(&self, seed: u64, a: u64, b: u64, c: u64) -> u8 {
((seed ^ a ^ b ^ c) & 0xFF) as u8
}
}
// Create the license key verifier
let mut verifier = Verifier::new(
DummyHasher { },
vec![
// Use the first byte (zero indexed) from the initialization vector.
// If a third-party key generator is created for the app, simply change this
// to another byte and any forged keys won't work anymore.
ByteCheck::new(0, (114, 83, 170)),
],
);
// Block a specific seed.
// You might want to do this if a key was leaked or the the
// license key owner requested a refund.
verifier.block(11111111_u64);
// Parse a key in hex format
let key = LicenseKey::parse::<HexFormat>("112210F4B2D230A229552341E723");
// Verify the license key
match verifier.verify(&key) {
Status::Valid => println!("Key is valid!"),
Status::Invalid => println!("Key is invalid!"),
Status::Blocked => println!("Key has been blocked!"),
Status::Forged => println!("Key has been forged!"),
}