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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#![cfg_attr(feature = "nightly_allocator_api", feature(allocator_api))]
#![cfg_attr(feature = "nightly_core_intrinsics", feature(core_intrinsics))]
#![cfg_attr(feature = "nightly_stdsimd", feature(stdsimd))]
#![cfg_attr(feature = "nightly_strict_provenance", feature(strict_provenance))]
#![cfg_attr(
    feature = "nightly_strict_provenance",
    deny(fuzzy_provenance_casts, lossy_provenance_casts)
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(rust_2018_compatibility, unsafe_op_in_unsafe_fn)]
#![deny(future_incompatible, rust_2018_idioms)]
#![warn(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
// FIXME: disable when strict provenance is stabilised
#![allow(unstable_name_collisions)]
//! `secmem-alloc` is a crate designed allocate private/secret memory. It is
//! intended to be used for storing cryptographic secrets in memory. This crate
//! provides custom allocators using various techniques to improve secrecy of
//! the memory, most notably zeroization on deallocation.
//!
//! # Examples
//! For example, we read in a secret password from standard-in, which we want to
//! zeroize on drop (deallocation). Note that this code does leave the password
//! visible on the prompt; it is only to give an idea of how to use this crate.
//!
//! ```
//! #![feature(allocator_api)]
//! // requires `nightly_allocator_api` crate feature to be enabled and a nightly compiler
//! use secmem_alloc::allocator_api::Allocator;
//! use secmem_alloc::zeroizing_alloc::ZeroizeAlloc;
//! use std::alloc::Global;
//!
//! fn read_password<A: Allocator>(buf: &mut Vec<u8, A>) {
//!     // query password from the user and put it in `buf`
//! }
//!
//! fn main() {
//!     println!("Please enter your password: ");
//!     let mut stdin = std::io::stdin();
//!     let allocator = ZeroizeAlloc::new(Global);
//!     let mut password = Vec::new_in(allocator);
//!     read_password(&mut password);
//!
//!     // use `password` however you like
//!     // you can even grow and shrink the vector `password` and if it needs to be reallocated, the
//!     // old allocation is immediately zeroized
//!
//!     // password is automatically zeroized on drop (deallocation)
//! }
//! ```
//!
//! As a second example assume you have a cryptographic secret key of 256 bytes,
//! which should be zeroized on drop. In addition, we don't want the key to be
//! written to swap.
//!
//! ```
//! // requires no crate features and works on stable
//! // if you enable the `nightly_allocator_api` crate feature, the following line is necessary
//! #![feature(allocator_api)]
//!
//! use secmem_alloc::allocator_api::Allocator;
//! use secmem_alloc::boxed::Box;
//! use secmem_alloc::sec_alloc::SecStackSinglePageAlloc;
//!
//! fn get_secret_key<A: Allocator>(buf: &mut Box<[u8; 256], A>) {
//!     // fill `buf` with the bytes of the secret key
//! }
//!
//! fn main() {
//!     let allocator: SecStackSinglePageAlloc =
//!         SecStackSinglePageAlloc::new().expect("could not create allocator");
//!     let mut key = Box::new_in([0_u8; 256], &allocator);
//!     get_secret_key(&mut key);
//!
//!     // use `key` however you like
//!     // `key` will not be written to swap except possibly on hibernation
//!
//!     // `key` is automatically zeroized on drop (deallocation)
//! }
//! ```
//!
//!
//! # Cargo features
//! - `std` (default): Enable functionality that requires `std`. Currently only
//!   required for `Error` implements and required for tests. This feature is
//!   enabled by default.
//! - `nightly_allocator_api` (requires nightly): Use the nightly allocator api
//!   from the standard library (actually the `core` crate), gated behind the
//!   nightly-only feature `allocator_api`. When disabled, a copy of the
//!   allocator api included in this crate, available through
//!   `secmem_alloc::allocator_api`, will be used. This feature requires a
//!   nightly compiler.
//! - `nightly_core_intrinsics` (requires nightly): Use the intrinsics from the
//!   standard library (actually the `core` crate), gated behind the
//!   nightly-only feature `core_intrinsics`. This enables the extremely fast
//!   `VolatileMemsetZeroizer` zeroizer, and various other small optimisations.
//!   This feature requires a nightly compiler.
//! - `nightly_stdsimd` (requires nightly): Required for avx512 simd API in the
//!   standard libary, but currently unused. This feature requires a nightly
//!   compiler.
//! - `nightly_strict_provenance` (requires nightly): Enable strict provenance
//!   lints and (mostly) use strict provenance API provided by the standard
//!   library instead of the one from `sptr`. (Will still depend on and in a few
//!   places even use `sptr`.)
//! - `nightly` (requires nightly): Enable all nightly-only features (i.e. the
//!   above two). Enabling this feature is highly recommended when a nightly
//!   compiler is available. This feature requires a nightly compiler.
//! - `dev` (requires nightly): This feature enables all features required to
//!   run the test-suite, and should only be enabled for that purpose. This
//!   feature currently requires a nightly compiler.

extern crate alloc;

mod internals;
mod macros;
mod util;

#[cfg(not(feature = "nightly_allocator_api"))]
pub mod allocator_api;
#[cfg(feature = "nightly_allocator_api")]
/// Nightly allocator api, imported from the standard library.
pub mod allocator_api {
    pub use core::alloc::{AllocError, Allocator};
}

pub mod boxed;
pub mod sec_alloc;
pub mod zeroize;
pub mod zeroizing_alloc;

#[cfg(test)]
mod tests {
    /// > Freedom is the freedom to say that two plus two makes four.
    ///
    /// Nineteen Eighty-Four, George Orwell
    #[test]
    fn freedom() {
        assert_ne!(2 + 2, 5);
        assert_eq!(2 + 2, 4);
    }
}