diff --git a/Cargo.toml b/Cargo.toml index 3bbb495..fd1fc92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ byteorder = "1.2.3" errno = "0.2.4" failure = "0.1" init_with = "1.1.0" +lazy_static = "1.1.0" log = "0.4.1" memsec = "0.5.4" pairing = { version = "0.14.2", features = ["u128-support"] } diff --git a/src/lib.rs b/src/lib.rs index 7bcbdf4..0eda80d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,8 @@ extern crate errno; extern crate failure; extern crate init_with; #[macro_use] +extern crate lazy_static; +#[macro_use] extern crate log; extern crate memsec; extern crate pairing; @@ -26,6 +28,7 @@ mod into_fr; pub mod poly; pub mod serde_impl; +use std::env; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem::size_of_val; @@ -37,13 +40,30 @@ use init_with::InitWith; use memsec::{memzero, mlock, munlock}; use pairing::bls12_381::{Bls12, Fr, G1, G1Affine, G2, G2Affine}; use pairing::{CurveAffine, CurveProjective, Engine, Field}; -use rand::{ChaChaRng, OsRng, Rng, Rand, SeedableRng}; +use rand::{ChaChaRng, OsRng, Rand, Rng, SeedableRng}; use tiny_keccak::sha3_256; use error::{Error, Result}; use into_fr::IntoFr; use poly::{Commitment, Poly}; +lazy_static! { + // Sets whether or not `mlock`ing is enabled. Memory locking is enabled by default; it can be + // disabled by setting the environment variable `MLOCK_SECRETS=false`. This is useful when you + // are running on a system where you do not have the ability to increase the systems locked + // memory limit (which can be found using the Unix command: `ulimit -l`). For example, we + // disable `mlock`ing of secrets when testing crates that depend on `threshold_crypto` when + // running in Travis CI because Travis has a locked memory limit of 64kb, which we may exceed + // while running `cargo test`. Disabling `mlock`ing for secret values allows secret keys to be + // swapped/core-dumped to disk, resulting in unmanaged copies of secrets to hang around in + // memory; this is significantly less secure than enabling memory locking (the default). Only + // set `MLOCK_SECRETS=false` in development/testing. + pub(crate) static ref SHOULD_MLOCK_SECRETS: bool = match env::var("MLOCK_SECRETS") { + Ok(s) => s.parse().unwrap_or(true), + _ => true, + }; +} + /// Marks a type as containing one or more secret prime field elements. pub(crate) trait ContainsSecret { /// Calls the `mlock` system call on the region of memory allocated for the secret prime field @@ -299,6 +319,9 @@ impl fmt::Debug for SecretKey { impl ContainsSecret for SecretKey { fn mlock_secret_memory(&self) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let ptr = &*self.0 as *const Fr as *mut u8; let n_bytes = size_of_val(&*self.0); let mlock_succeeded = unsafe { mlock(ptr, n_bytes) }; @@ -315,6 +338,9 @@ impl ContainsSecret for SecretKey { } fn munlock_secret_memory(&self) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let ptr = &*self.0 as *const Fr as *mut u8; let n_bytes = size_of_val(&*self.0); let munlock_succeeded = unsafe { munlock(ptr, n_bytes) }; diff --git a/src/poly.rs b/src/poly.rs index e177a78..f986f0c 100644 --- a/src/poly.rs +++ b/src/poly.rs @@ -28,7 +28,7 @@ use pairing::bls12_381::{Fr, G1, G1Affine}; use pairing::{CurveAffine, CurveProjective, Field}; use rand::Rng; -use super::{ContainsSecret, Error, IntoFr, Result}; +use super::{ContainsSecret, Error, IntoFr, Result, SHOULD_MLOCK_SECRETS}; /// A univariate polynomial in the prime field. #[derive(Serialize, Deserialize, PartialEq, Eq)] @@ -288,6 +288,9 @@ impl Drop for Poly { impl ContainsSecret for Poly { fn mlock_secret_memory(&self) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let ptr = self.coeff.as_ptr() as *mut u8; let n_bytes = size_of_val(self.coeff.as_slice()); if n_bytes == 0 { @@ -307,6 +310,9 @@ impl ContainsSecret for Poly { } fn munlock_secret_memory(&self) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let ptr = self.coeff.as_ptr() as *mut u8; let n_bytes = size_of_val(self.coeff.as_slice()); if n_bytes == 0 { @@ -510,6 +516,9 @@ impl Poly { // Removes the `mlock` for `len` elements that have been truncated from the `coeff` vector. fn truncate_mlock(&self, len: usize) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let n_bytes_truncated = len * size_of::(); if n_bytes_truncated == 0 { return Ok(()); @@ -532,6 +541,9 @@ impl Poly { // Extends the `mlock` on the `coeff` vector when `len` new elements are added. fn extend_mlock(&self, len: usize) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let n_bytes_extended = len * size_of::(); if n_bytes_extended == 0 { return Ok(()); @@ -684,6 +696,9 @@ impl Debug for BivarPoly { impl ContainsSecret for BivarPoly { fn mlock_secret_memory(&self) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let ptr = self.coeff.as_ptr() as *mut u8; let n_bytes = size_of_val(self.coeff.as_slice()); if n_bytes == 0 { @@ -703,6 +718,9 @@ impl ContainsSecret for BivarPoly { } fn munlock_secret_memory(&self) -> Result<()> { + if !*SHOULD_MLOCK_SECRETS { + return Ok(()); + } let ptr = self.coeff.as_ptr() as *mut u8; let n_bytes = size_of_val(self.coeff.as_slice()); if n_bytes == 0 {