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