licenses_pro 0.3.0

A crate for pro-level licenses.
Documentation
//! This crate allows you to verify and generate licenses.
//!
//! # Example usage
//! ```
//! use licenses_pro::gen::*;
//! use licenses_pro::LicenseStructParameters;
//! let generator=AdminGenerator::new_with_random_ivs(LicenseStructParameters::default());
//! // This generates a license with a seed, which should be constant length unique identifier.
//! // This example just uses some random bytes as a seed. The seed should be the same length as specified in the LicenseStructParameters
//! let license=generator.generate_license(vec![5, 100, 42, 69, 3,90]).unwrap();
//! println!("{}",license.to_human_readable()); // BWQq-RQNa-kDp6-mJn8-SSEh-UStw-p9+q-krw1-KDH4-mw
//! ```
//! Meanwhile on the client side
//! ```
//! use licenses_pro::check::*;
//! use licenses_pro::LicenseStructParameters;
//! let parsed=License::from_human_readable("BWQq-RQNa-kDp6-mJn8-SSEh-UStw-p9+q-krw1-KDH4-mw".to_string(),LicenseStructParameters::default()).unwrap();
//! let verify_result=verify_license(parsed,LicenseCheckInfo {
//!        known_iv: vec![43, 194, 247, 127, 168, 171, 16],
//!        iv_index: 0,
//!    },licenses_pro::blockers::NoBlock);
//! // Go ahead and match this!
//! ```
/// Block compromised licenses
pub mod blockers;
/// Check licenses generated by the generator
pub mod check;
const CHECKSUM_LEN: usize = 2;

/// Information about the structure of your license.
/// This must be shared between your generator and checker.
pub struct LicenseStructParameters {
    // seed length in bytes
    pub seed_length: usize,

    // payload length in chunks
    pub payload_length: usize,
    // chunk size in bytes
    pub chunk_size: usize,
}

impl Default for LicenseStructParameters {
    fn default() -> Self {
        Self {
            seed_length: 6,
            payload_length: 10,
            chunk_size: 2,
        }
    }
}
fn generate_checksum(seed: &[u8], payload: &[Vec<u8>]) -> Vec<u8> {
    let mut context = digest::Context::new(&digest::SHA256);
    let to_verify = &[seed, &payload.concat()].concat();
    context.update(to_verify);
    context.finish().as_ref()[..CHECKSUM_LEN].to_owned()
}
use ring::digest::{self, Context, SHA256};
fn generate_key_chunk(iv: &[u8], seed: &Vec<u8>, chunk_size: usize) -> Vec<u8> {
    let mut context = Context::new(&SHA256);
    context.update(&[iv, &seed].concat());
    let binding = context.finish();
    let hash = &binding.as_ref()[..chunk_size];
    hash.to_owned()
}
/// Generate valid licenses
pub mod gen;
#[cfg(test)]
mod tests {
    use crate::check::{LicenseCheckInfo, LicenseVerifyError};

    use self::{
        blockers::NoBlock,
        check::{verify_license, License},
        gen::AdminGenerator,
    };

    use super::*;
    #[test]
    fn checksum_works_for_valid() {
        new_test_license().verify_checksum().unwrap()
    }
    #[test]
    fn checksum_detects_invalid() {
        let mut license = new_test_license();
        license.payload[0][0] += 1;
        if let Ok(_) = license.verify_checksum() {
            panic!("Checksum should not be valid")
        }
    }
    #[test]
    fn license_works() {
        let genner = new_test_genner();
        let license = genner
            .generate_license(vec![5, 100, 42, 69, 3, 90])
            .unwrap();
        println!("{}", license.clone().to_human_readable());
        println!("{:?}", genner.ivs[0]);
        assert_eq!(
            verify_license(
                license,
                LicenseCheckInfo {
                    known_iv: genner.ivs[0].clone(),
                    iv_index: 0
                },
                NoBlock
            ),
            Ok(())
        );
    }
    #[test]
    fn forgery_detected() {
        let genner = new_test_genner();
        let license = genner
            .generate_license(vec![5, 100, 42, 69, 3, 90])
            .unwrap();
        if let Err(LicenseVerifyError::LicenseForged) = verify_license(
            license,
            LicenseCheckInfo {
                known_iv: vec![182, 34],
                iv_index: 0,
            },
            NoBlock,
        ) {
        } else {
            panic!("Bad license detected as good")
        }
    }
    fn new_test_genner() -> AdminGenerator {
        let params = LicenseStructParameters {
            seed_length: 6,
            payload_length: 10,
            chunk_size: 2,
        };
        let genner = AdminGenerator::new_with_random_ivs(params);
        genner
    }
    fn new_test_license() -> License {
        let genner = new_test_genner();
        genner
            .generate_license(vec![5, 100, 42, 69, 3, 90])
            .unwrap()
    }
}