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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! This crate implements the NTRU encryption library in Rust. It is an interface to libntru, even
//! though many of the methods are being implemented in pure Rust. The plan is to gradually
//! implement the library natively. It uses this library since it has proven to be faster than the
//! original NTRU encryption implementation. In any case, it is much faster than usual encryption /
//! decryption mecanisms, and quantum-proof. More on NTRU encryption
//! [here](https://en.wikipedia.org/wiki/NTRUEncrypt).
//!
//! To use it you only need to include the following in your crate:
//!
//! ```
//! extern crate ntru;
//! ```
//!
//! NTRU encryption uses its own keys, that must be generated with the included random key
//! generator, and must not be used for other applications such as NTRU signing or NTRUNMLS.
//!
//! # Examples
//!
//! ```
//! use ntru::rand::RNG_DEFAULT;
//! use ntru::encparams::DEFAULT_PARAMS_256_BITS;
//!
//! let rand_ctx = ntru::rand::init(&RNG_DEFAULT).unwrap();
//! let kp = ntru::generate_key_pair(&DEFAULT_PARAMS_256_BITS, &rand_ctx).unwrap();
//! ```
//!
//! This creates a key pair that can be uses to encrypt and decrypt messages:
//!
//! ```
//! # use ntru::rand::RNG_DEFAULT;
//! use ntru::encparams::DEFAULT_PARAMS_256_BITS;
//! #
//! # let rand_ctx = ntru::rand::init(&RNG_DEFAULT).unwrap();
//! # let kp = ntru::generate_key_pair(&DEFAULT_PARAMS_256_BITS, &rand_ctx).unwrap();
//!
//! let msg = b"Hello from Rust!";
//! let encrypted = ntru::encrypt(msg, kp.get_public(), &DEFAULT_PARAMS_256_BITS,
//!                               &rand_ctx).unwrap();
//! let decrypted = ntru::decrypt(&encrypted, &kp, &DEFAULT_PARAMS_256_BITS).unwrap();
//!
//! assert_eq!(&msg[..], &decrypted[..]);
//! ```

#![forbid(missing_docs, warnings)]
#![deny(deprecated, improper_ctypes, non_shorthand_field_patterns, overflowing_literals,
    plugin_as_library, private_no_mangle_fns, private_no_mangle_statics, stable_features,
    unconditional_recursion, unknown_lints, unused, unused_allocation, unused_attributes,
    unused_comparisons, unused_features, unused_parens, while_true)]
#![warn(trivial_casts, trivial_numeric_casts, unused, unused_extern_crates, unused_import_braces,
    unused_qualifications, unused_results, variant_size_differences)]

extern crate libc;

pub mod types;
pub mod rand;
pub mod encparams;
mod ffi;

use types::{KeyPair, PrivateKey, PublicKey, Error};
use encparams::EncParams;
use rand::RandContext;

/// Key generation
///
/// Generates a NTRU encryption key pair. If a deterministic RNG is used, the key pair will be
/// deterministic for a given random seed; otherwise, the key pair will be completely random.
pub fn generate_key_pair(params: &EncParams, rand_context: &RandContext) -> Result<KeyPair, Error> {
    let mut kp: KeyPair = Default::default();
    let result = unsafe { ffi::ntru_gen_key_pair(params, &mut kp, rand_context) };
    if result == 0 {
        Ok(kp)
    } else {
        Err(Error::from(result))
    }
}

/// Key generation with multiple public keys
///
/// Generates `num_pub` Ntru encryption key pairs. They all share a private key but their public
/// keys differ. The private key decrypts messages encrypted for any of the public keys. Note that
/// when decrypting, the public key of the key pair passed into `ntru_decrypt()` must match the
/// public key used for encrypting the message. If a deterministic RNG is used, the key pair will
/// be deterministic for a given random seed; otherwise, the key pair will be completely random.
pub fn generate_multiple_key_pairs(params: &EncParams,
                                   rand_context: &RandContext,
                                   num_pub: usize)
                                   -> Result<(PrivateKey, Box<[PublicKey]>), Error> {
    let mut private: PrivateKey = Default::default();
    let mut public: Vec<PublicKey> = Vec::with_capacity(num_pub);
    for _ in 0..num_pub {
        public.push(Default::default());
    }
    let result = unsafe {
        ffi::ntru_gen_key_pair_multi(params,
                                     &mut private,
                                     &mut public[0],
                                     rand_context,
                                     num_pub as u32)
    };
    if result == 0 {
        Ok((private, public.into_boxed_slice()))
    } else {
        Err(Error::from(result))
    }
}

/// New public key
///
/// Generates a new public key for an existing private key. The new public key can be used
/// interchangeably with the existing public key(s). Generating n keys via
/// `ntru::generate_multiple_key_pairs()` is more efficient than generating one and then calling
/// `ntru_gen_pub()` n-1 times, so if the number of public keys needed is known beforehand and if
/// speed matters, `ntru_gen_key_pair_multi()` should be used. Note that when decrypting, the public
/// key of the key pair passed into `ntru_decrypt()` must match the public key used for encrypting
/// the message. If a deterministic RNG is used, the key will be deterministic for a given random
/// seed; otherwise, the key will be completely random.
pub fn generate_public(params: &EncParams,
                       private: &PrivateKey,
                       rand_context: &RandContext)
                       -> Result<PublicKey, Error> {
    let mut public: PublicKey = Default::default();
    let result = unsafe { ffi::ntru_gen_pub(params, private, &mut public, rand_context) };
    if result == 0 {
        Ok(public)
    } else {
        Err(Error::from(result))
    }
}

/// Encrypts a message
///
/// If a deterministic RNG is used, the encrypted message will also be deterministic for a given
/// combination of plain text, key, and random seed. See P1363.1 section 9.2.2.
/// The parameters needed are the following:
/// * `msg`: The message to encrypt as an ```u8``` slice.
/// * `public`: The public key to encrypt the message with.
/// * `params`: The NTRU encryption parameters to use.
/// * `and_ctx`: An initialized random number generator.
pub fn encrypt(msg: &[u8],
               public: &PublicKey,
               params: &EncParams,
               rand_ctx: &RandContext)
               -> Result<Box<[u8]>, Error> {
    let mut enc = vec![0u8; params.enc_len() as usize];
    let result = unsafe {
        ffi::ntru_encrypt(if msg.len() > 0 {
                              &msg[0]
                          } else {
                              std::ptr::null()
                          },
                          msg.len() as u16,
                          public,
                          params,
                          rand_ctx,
                          &mut enc[0])
    };

    if result == 0 {
        Ok(enc.into_boxed_slice())
    } else {
        Err(Error::from(result))
    }
}

/// Decrypts a message.
///
/// See P1363.1 section 9.2.3. The parameters needed are the following:
/// * enc: The message to decrypt as an ```u8``` slice.
/// * kp: A key pair that contains the public key the message was encrypted with, and the
///       corresponding private key.
/// * params: Parameters the message was encrypted with
pub fn decrypt(enc: &[u8], kp: &KeyPair, params: &EncParams) -> Result<Box<[u8]>, Error> {
    let mut dec = vec![0u8; params.max_msg_len() as usize];
    let mut dec_len = 0u16;
    let result = unsafe { ffi::ntru_decrypt(&enc[0], kp, params, &mut dec[0], &mut dec_len) };

    if result == 0 {
        let mut final_dec = Vec::with_capacity(dec_len as usize);
        final_dec.extend(dec.into_iter().take(dec_len as usize));
        Ok(final_dec.into_boxed_slice())
    } else {
        Err(Error::from(result))
    }
}