1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! `cryptid` offers secure encoding and decoding of numbers into URL type safe strings and back,
//! and a generic field type to conveniently manage the process with Serde and Diesel.
//!
//! This library is primarily designed to encrypt raw database IDs in your API, and to transform
//! them into opaque, URL-safe identifiers. This process prevents the guessing of valid IDs,
//! enhancing security against attacks that exploit weak access controls by making object ID
//! enumeration difficult. You can still enjoy the performance benefits of using monotonically
//! increasing integers as your database keys.
//!
//! The encoded IDs include a customizable object type prefix, inspired by Stripe's API. This
//! prevents accidentally or intentionally mixing IDs of different types of objects.
//!
//! `cryptid` uses [format-preserving encryption (FPE)](https://en.wikipedia.org/wiki/Format-preserving_encryption)
//! with AES (FF1 with AES256) and HMAC (SHA256) for integrity checks.
//!
//! Please note that leaking the encryption key means you lose all the security benefits.
//! Anyone can then decrypt and encrypt your IDs, and you'll be just as (in)secure as using plain
//! integers in the first place. You also cannot change the encryption key, unless it's OK that
//! all exposed object identifiers change.
//!
//! # Usage
//!
//! ## Generic `Field` API (recommended)
//!
//! Use the generic `Field` type do define a type for each type of object you're exposing
//! in your public APIs. The `Field` type supports automatic encoding and decoding with Diesel
//! and Serde.
//!
//! ```
//! use cryptid_rs;
//! use serde::{Serialize, Deserialize};
//! use serde_json;
//!
//! // Define the ExampleId cryptid field type. The type marker defines the string prefix.
//! #[derive(Debug)]
//! pub struct ExampleIdMarker;
//! impl cryptid_rs::TypeMarker for ExampleIdMarker {
//! fn name() -> &'static str { "example" }
//! }
//!
//! type ExampleId = cryptid_rs::Field<ExampleIdMarker>;
//!
//! // The field can then be used in structs, and works automatically with Serde and Diesel.
//! #[derive(serde::Serialize)]
//! struct Example {
//! pub id: ExampleId,
//! }
//!
//! cryptid_rs::Config::set_global(cryptid_rs::Config::new(b"your-secure-key"));
//! let obj = Example {id: ExampleId::new(12345)};
//! let obj_str = serde_json::to_string(&obj).unwrap();
//! assert_eq!(obj_str, "{\"id\":\"example_VgwPy6rwatl\"}");
//! ```
//!
//! ## Low level API
//!
//! `Codec` provides a simple API to encode and decode integers.
//!
//! ```
//! use cryptid_rs::{Codec, Config};
//!
//! let codec = Codec::new("example", &Config::new(b"your-secure-key"));
//! let encoded = codec.encode(12345);
//! let decoded = codec.decode(&encoded).unwrap();
//! assert_eq!(encoded, "example_VgwPy6rwatl");
//! assert_eq!(decoded, 12345);
//! ```
//!
mod codec;
mod config;
mod field;
pub use codec::{Codec, Error};
pub use config::{Config, ConfigError};
pub use field::{Field, TypeMarker};