Skip to main content

license_key/
lib.rs

1/*!
2A library for generating and verifying license keys without requiring
3an Internet connection. For further protection, you can of course
4validate the license key over the Internet.
5
6# Features
7
8* Does not require an Internet connection.
9* Easy to revoke specific license keys in a software update.
10* Not possible to disassemble an application to gain
11  insight into how to generate a 100% working key since 
12  the verification process doesn't check the whole license key.
13
14For more information, read [`Implementing a Partial Serial Number Verification System in Delphi`]
15by Brandon Staggs, which this crate was based upon.
16
17# Anatomy of a license key
18
19Every license key consists of a seed, a payload and a checksum.
20Each byte in the payload is an operation of the seed and an
21initialization vector. The 16-bit checksum is there to quickly check if
22the key is valid at all, while the seed is a 64-bit hash of something
23that identifies the license key owner such as an e-mail address or similar.  
24
25The size of the payload depends on how big the initialization vector is.
26In the example below, we are using a 5-byte intitialization vector which
27results in a 5-byte payload.
28
29```text
30┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
31│0x0│0x1│0x2│0x3│0x4│0x5│0x6│0x7│0x8│0x9│0xa│0xb│0xc│0xd│0xe│0xf│
32├───┴───┴───┴───┴───┴───┴───┴───┴───┼───┴───┴───┴───┴───┼───┴───┤
33│ SEED                              │ PAYLOAD           │ CHECK │
34│                                   │                   │  SUM  │
35└───────────────────────────────────┴───────────────────┴───────┘
36```
37
38# Generating a license key
39
40```rust
41use license_key::*;
42
43// Define a hasher that will hash the seed and a initialization vector.
44// DON'T USE THIS ONE. It's only for demonstrational purposes.
45struct DummyHasher { }
46impl KeyHasher for DummyHasher {
47    fn hash(&self, seed: u64, a: u64, b: u64, c: u64) -> u8 {
48        ((seed ^ a ^ b ^ c) & 0xFF) as u8
49    }
50}
51
52// Create a license generator
53// We use only four triplets in our initialization vector,
54// but in a real world scenario you would want to use a lot more.
55let generator = Generator::new(
56    DummyHasher { },
57    vec![
58        // DON'T USE THIS ONE.
59        // Generate your own.
60        (114, 83, 170),
61        (60, 208, 27),
62        (69, 14, 202),
63        (61, 232, 54)
64     ],
65);
66
67// Generate a license key using a seed.
68// A seed is unique per license key, and could be a hash of an e-mail address or similar.
69// You can later block individual seeds during verification.
70let key = generator.generate(1234567891011121314_u64);
71
72// Write the key in hex format to the console.
73// This will output something like: 112210F4B2D230A229552341B2E723
74println!("{}", key.serialize::<HexFormat>());
75```
76
77# Verifying a license key
78
79```rust
80use license_key::*;
81
82// Use the exact same hasher that we used when generating the key
83struct DummyHasher { }
84impl KeyHasher for DummyHasher {
85    fn hash(&self, seed: u64, a: u64, b: u64, c: u64) -> u8 {
86        ((seed ^ a ^ b ^ c) & 0xFF) as u8
87    }
88}
89
90// Create the license key verifier
91let mut verifier = Verifier::new(
92    DummyHasher { },
93    vec![
94        // Use the first byte (zero indexed) from the initialization vector.
95        // If a third-party key generator is created for the app, simply change this
96        // to another byte and any forged keys won't work anymore.
97        ByteCheck::new(0, (114, 83, 170)),
98    ],
99);
100
101// Block a specific seed.
102// You might want to do this if a key was leaked or the the 
103// license key owner requested a refund.
104verifier.block(11111111_u64);
105
106// Parse a key in hex format
107let key = LicenseKey::parse::<HexFormat>("112210F4B2D230A229552341E723");
108
109// Verify the license key
110match verifier.verify(&key) {
111    Status::Valid => println!("Key is valid!"),
112    Status::Invalid => println!("Key is invalid!"),
113    Status::Blocked => println!("Key has been blocked!"),
114    Status::Forged => println!("Key has been forged!"),
115}
116```
117
118[`Implementing a Partial Serial Number Verification System in Delphi`]: 
119https://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi
120*/
121
122use std::convert::TryInto;
123
124const SEED_BYTE_LENGTH: u8 = 8;
125const CHECKSUM_BYTE_LENGTH: u8 = 2;
126const SEGMENT_BYTE_LENGTH: u8 = 1;
127
128/// Represent a hasher that turns the seed and a part of the
129/// initialization vector into a license key byte.
130pub trait KeyHasher {
131    fn hash(&self, seed: u64, a: u64, b: u64, c: u64) -> u8;
132}
133
134/// Represents a license key serializer.
135pub trait Serializer {
136    /// Serializes a license key to a string.
137    fn serialize(key: &LicenseKey) -> String;
138
139    /// Deserializes a license key into a byte vector.
140    fn deserialize(input: &str) -> Vec<u8>;
141}
142
143/// License key serializer for hex strings.
144pub struct HexFormat {}
145impl Serializer for HexFormat {
146    fn serialize(key: &LicenseKey) -> String {
147        hex::encode(key.get_bytes())
148    }
149
150    fn deserialize(input: &str) -> Vec<u8> {
151        hex::decode(input).unwrap()
152    }
153}
154
155/// Represents a generated or parsed license key.
156#[derive(Debug, Clone)]
157pub struct LicenseKey {
158    bytes: Vec<u8>,
159}
160
161impl LicenseKey {
162    pub(crate) fn new(bytes: Vec<u8>) -> Self {
163        Self { bytes }
164    }
165
166    /// Deserializes a [`&str`] into a license key by using the
167    /// provided [`Serializer`].
168    ///
169    /// [`&str`]: https://doc.rust-lang.org/std/primitive.str.html
170    /// [`Serializer`]: trait.Serializer.html
171    pub fn parse<T : Serializer>(input: &str) -> LicenseKey {
172        LicenseKey::new(T::deserialize(input))
173    }
174
175    /// Serializes the license key into a [`String`] by using the 
176    /// provided [`Serializer`].
177    ///
178    /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
179    /// [`Serializer`]: trait.Serializer.html
180    pub fn serialize<T: Serializer>(&self) -> String {
181        T::serialize(&self)
182    }
183
184    /// Gets the individual bytes that makes up the license key.
185    pub fn get_bytes(&self) -> Vec<u8> {
186        self.bytes.clone()
187    }
188
189    pub(crate) fn get_byte(&self, ordinal: usize) -> Option<u8> {
190        let index = SEED_BYTE_LENGTH as usize + (ordinal * SEGMENT_BYTE_LENGTH as usize);
191        if index > self.bytes.len() - 3 {
192            return None;
193        }
194        Some(self.bytes[index])
195    }
196
197    pub(crate) fn get_checksum(&self) -> &[u8] {
198        &self.bytes[self.bytes.len() - CHECKSUM_BYTE_LENGTH as usize..]
199    }
200
201    pub(crate) fn get_seed(&self) -> u64 {
202        u64::from_be_bytes(self.bytes[0..SEED_BYTE_LENGTH as usize].try_into().unwrap())
203    }
204
205    pub(crate) fn calculate_checksum(&self) -> [u8; 2] {
206        calculate_checksum(&self.bytes[0..self.bytes.len() - CHECKSUM_BYTE_LENGTH as usize])
207    }
208}
209
210/// The license key generator.
211#[derive(Debug)]
212pub struct Generator<T: KeyHasher> {
213    hasher: T,
214    iv: Vec<(u64, u64, u64)>,
215}
216
217impl<T: KeyHasher> Generator<T> {
218    /// Creates a new license key generator.
219    pub fn new(hasher: T, iv: Vec<(u64, u64, u64)>) -> Self {
220        Self { hasher, iv }
221    }
222
223    /// Creates a new license key with the specified seed.
224    pub fn generate(&self, seed: u64) -> LicenseKey {
225        // Get the license key as a byte array
226        let mut input = seed.to_be_bytes().to_vec();
227        for iv in self.iv.iter() {
228            for byte in self
229                .hasher
230                .hash(seed, iv.0, iv.1, iv.2)
231                .to_be_bytes()
232                .to_vec()
233            {
234                input.push(byte);
235            }
236        }
237
238        // Calculate the checksum for the license key
239        let checksum = calculate_checksum(&input);
240        for byte in checksum.iter() {
241            input.push(*byte);
242        }
243
244        LicenseKey::new(input)
245    }
246}
247
248/// Representation of a license key status.
249#[derive(Debug, PartialEq)]
250pub enum Status {
251    /// The license is valid.
252    Valid,
253    /// The license is invalid.
254    Invalid,
255    /// The license has been blocked.
256    Blocked,
257    /// The license has been forged.
258    Forged,
259}
260
261/// Represents a license key byte check
262/// that should be used during validation.
263#[derive(Debug)]
264pub struct ByteCheck {
265    pub ordinal: u8,
266    pub a: u64,
267    pub b: u64,
268    pub c: u64,
269}
270
271impl ByteCheck {
272    /// Creates a new byte check.
273    pub fn new(ordinal: u8, iv: (u64, u64, u64)) -> Self {
274        Self {
275            ordinal,
276            a: iv.0,
277            b: iv.1,
278            c: iv.2,
279        }
280    }
281}
282
283/// The license key verifier.
284#[derive(Debug)]
285pub struct Verifier<T: KeyHasher> {
286    hasher: T,
287    checks: Vec<ByteCheck>,
288    blocklist: Vec<u64>,
289}
290
291impl<T: KeyHasher> Verifier<T> {
292    /// Creates a new license key verifier.
293    pub fn new(hasher: T, checks: Vec<ByteCheck>) -> Self {
294        Self {
295            hasher,
296            checks,
297            blocklist: Vec::new(),
298        }
299    }
300
301    /// Blocks the specified seed from being used.
302    pub fn block(&mut self, seed: u64) {
303        self.blocklist.push(seed)
304    }
305
306    /// Perform verification on the provided license key.
307    pub fn verify(&self, key: &LicenseKey) -> Status {
308        // Validate the checksum
309        let checksum = key.calculate_checksum().to_vec();
310        if checksum != key.get_checksum() {
311            return Status::Invalid;
312        }
313
314        // Blocked key?
315        let seed = key.get_seed();
316        for blocked_seed in self.blocklist.iter() {
317            if seed == *blocked_seed {
318                return Status::Blocked;
319            }
320        }
321
322        for check in self.checks.iter() {
323            match key.get_byte(check.ordinal as usize) {
324                Some(value) => {
325                    if value != self.hasher.hash(seed, check.a, check.b, check.c) {
326                        // Values did not match, but the checksum
327                        // was correct, so this is a forged license key
328                        return Status::Forged;
329                    }
330                }
331                None => {
332                    // If we couldn't get the byte from the license
333                    // the license is invalid.
334                    return Status::Invalid;
335                }
336            }
337        }
338
339        Status::Valid
340    }
341}
342
343fn calculate_checksum(key: &[u8]) -> [u8; 2] {
344    let mut left = 0x56_u16;
345    let mut right = 0xAF_u16;
346
347    for byte in key.iter() {
348        right += *byte as u16;
349        if right > 0xFF {
350            right -= 0xFF;
351        }
352        left += right;
353        if left > 0xFF {
354            left -= 0xFF;
355        }
356    }
357    ((left << 8) + right).to_be_bytes()
358}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363    use crate::KeyHasher;
364    use crate::Generator;
365
366    #[derive(Default)]
367    pub struct TestHasher {}
368    impl KeyHasher for TestHasher {
369        fn hash(&self, seed: u64, a: u64, b: u64, c: u64) -> u8 {
370            ((seed ^ a ^ b ^ c) & 0xFF) as u8
371        }
372    }
373
374    pub fn generate_key(seed: u64) -> LicenseKey {
375        let generator = Generator::new(
376            TestHasher::default(),
377            vec![(114, 83, 170), (60, 208, 27), (69, 14, 202), (61, 232, 54)],
378        );
379        generator.generate(seed)
380    }
381
382    pub fn create_verifier() -> Verifier<TestHasher> {
383        Verifier::new(
384            TestHasher::default(),
385            vec![
386                ByteCheck::new(0, (114, 83, 170)),
387                ByteCheck::new(2, (69, 14, 202)),
388            ],
389        )
390    }
391
392    #[test]
393    pub fn valid_key_should_be_valid() {
394        // Given
395        let key = generate_key(12345);
396        let verifier = create_verifier();
397
398        // When
399        let result = verifier.verify(&key);
400
401        // Then
402        assert_eq!(Status::Valid, result);
403    }
404
405    #[test]
406    pub fn valid_but_blocked_key_should_return_error() {
407        // Given
408        let key = generate_key(12345);
409        let mut verifier = create_verifier();
410        verifier.block(12345);
411
412        // When
413        let result = verifier.verify(&key);
414
415        // Then
416        assert_eq!(Status::Blocked, result);
417    }
418}