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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! Cryptography in Rust.
//!
//! Mundane is a Rust cryptography library backed by BoringSSL that is difficult
//! to misuse, ergonomic, and performant (in that order).
//!
//! # Features
//!
//! By default, Mundane provides only high-level cryptographic primitives.
//! Unless you are implementing cryptographic protocols, these high-level
//! primitives should be all you need. However, if you are sure that you need
//! something lower level, Mundane provides features to enable a number of
//! different low level primitives.
//!
//! WARNING: Being low level, these primitives provide the programmer with more
//! degrees of freedom. There are more conditions that the programmer must meet
//! in order to guarantee security, and thus more ways for the programmer to
//! shoot themself in the foot. Please only use these primitives if you're aware
//! of the risks and are comfortable with the responsibility of using them
//! correctly!
//!
//! **Features**
//!
//! | Name         | Description              |
//! | ------------ | ------------------------ |
//! | `kdf`        | Key derivation functions |
//! | `rand-bytes` | Generate random bytes    |
//!
//! # Insecure Operations
//!
//! Mundane supports one additional feature not listed in the previous section:
//! `insecure`. This enables some cryptographic primitives which are today
//! considered insecure. These should only be used for compatibility with legacy
//! systems, but never in new systems! When the `insecure` feature is used, an
//! `insecure` module is added to the crate root. All insecure primitives are
//! exposed through this module.

#![doc(html_root_url = "https://joshlf.com/rustdoc/mundane")]
#![deny(missing_docs)]
#![deny(warnings)]
// just in case we forget to add #[forbid(unsafe_code)] on new module
// definitions
#![deny(unsafe_code)]
// NOTE(joshlf): This is the only feature we allow. It keeps us from working on
// stable Rust, but that's justified by the fact that it's important for
// ensuring the soundness of our unsafe code. Once this feature is stabilized,
// we will promise to work on stable going forward.
#![feature(try_from)]

#[macro_use]
mod macros;

// Forbid unsafe code except in the boringssl module.
#[allow(unsafe_code)]
mod boringssl;
#[forbid(unsafe_code)]
pub mod hash;
#[forbid(unsafe_code)]
pub mod hmac;
#[cfg(feature = "insecure")]
#[forbid(unsafe_code)]
pub mod insecure;
#[cfg(feature = "kdf")]
#[forbid(unsafe_code)]
pub mod kdf;
#[forbid(unsafe_code)]
pub mod password;
#[forbid(unsafe_code)]
pub mod public;
#[forbid(unsafe_code)]
mod util;

use std::fmt::{self, Debug, Display, Formatter};

use boringssl::BoringError;

/// Reads cryptographically-secure random bytes.
///
/// This is a low-level primitive often used to construct higher-level
/// protocols. Unless you're sure that this is what you need, you should
/// probably be using something else. For example, all key types can be randomly
/// generated using higher-level functions (e.g., [`EcPrivKey::generate`]),
/// scrypt nonces are generated using the [`scrypt_generate`] function, etc.
///
/// [`EcPrivKey::generate`]: ::public::ec::EcPrivKey::generate
/// [`scrypt_generate`]: ::password::scrypt::scrypt_generate
#[cfg(feature = "rand-bytes")]
pub fn rand_bytes(bytes: &mut [u8]) {
    boringssl::rand_bytes(bytes);
}

/// Errors generated by this crate.
///
/// `Error` represents two types of errors: errors generated by BoringSSL, and
/// errors generated by the Rust code in this crate. When printed (using either
/// `Display` or `Debug`), BoringSSL errors are of the form `boringssl:
/// <error>`, while errors generated by Rust code are of the form `<error>`.
pub struct Error(ErrorInner);

impl Error {
    fn new(s: String) -> Error {
        Error(ErrorInner::Mundane(s))
    }
}

#[doc(hidden)]
impl From<BoringError> for Error {
    fn from(err: BoringError) -> Error {
        Error(ErrorInner::Boring(err))
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        match &self.0 {
            ErrorInner::Mundane(err) => write!(f, "{}", err),
            ErrorInner::Boring(err) => write!(f, "boringssl: {}", err),
        }
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        match &self.0 {
            ErrorInner::Mundane(err) => write!(f, "{}", err),

            ErrorInner::Boring(err) => {
                if err.stack_depth() == 1 {
                    // Either there was no stack trace, or the stack trace only
                    // contained a single frame. In either case, don't bother
                    // printing a preceding newline.
                    write!(f, "boringssl: {:?}", err)
                } else {
                    // There's a multi-line stack trace, so print a preceding
                    // newline.
                    write!(f, "boringssl:\n{:?}", err)
                }
            }
        }
    }
}

impl std::error::Error for Error {}

enum ErrorInner {
    Mundane(String),
    Boring(BoringError),
}

#[cfg(test)]
mod tests {
    use super::Error;

    #[test]
    fn test_send() {
        fn assert_send<T: Send>() {}
        assert_send::<Error>();
    }

    #[test]
    fn test_sync() {
        fn assert_sync<T: Sync>() {}
        assert_sync::<Error>();
    }
}