Skip to content

Commit bfa51a5

Browse files
authored
Remove OpenSSL from PRF, replace with AES crate (#357)
* Remove OpenSSL dependency * Will it be faster?
1 parent 7281de5 commit bfa51a5

File tree

2 files changed

+32
-42
lines changed

2 files changed

+32
-42
lines changed

ciphercore-base/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ getrandom = { version = "0.2.9", features = ["js"] }
2020
typetag = "0.2.8"
2121
petgraph = "0.6.0"
2222
maplit = "1.0.2"
23-
openssl = "0.10"
2423
rand = "0.8"
2524
uuid = { version = "0.8.2", features = ["v4"] }
2625
chrono = "0.4.19"
@@ -33,6 +32,8 @@ arbitrary = { version = "1", optional = true, features = ["derive"] }
3332
pyo3 = { version = "0.17.1", optional = true, features = ["extension-module"] }
3433
anyhow = { version = "1.0.70", features = ["backtrace"] }
3534
tonic = { version = "0.8.3", optional = true }
35+
aes = "0.8.2"
36+
cipher = { version = "0.4.4", features = ["block-padding"] }
3637

3738
[dev-dependencies]
3839
serde_test = "1.0.130"

ciphercore-base/src/random.rs

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ use crate::data_types::{get_size_in_bits, get_types_vector, Type, UINT64};
33
use crate::data_values::Value;
44
use crate::errors::Result;
55

6-
use openssl::symm::{Cipher, Crypter, Mode};
6+
use aes::cipher::KeyInit;
7+
use aes::cipher::{generic_array::GenericArray, BlockEncrypt};
8+
use aes::Aes128;
9+
use cipher::block_padding::NoPadding;
710
use rand::rngs::OsRng;
811
use rand::RngCore;
912

13+
const BLOCK_SIZE: usize = 16;
14+
1015
/// It is possible that when used during early boot
1116
/// the first call to OsRng will block until the system’s RNG is initialised.
1217
/// It is also possible (though highly unlikely) for OsRng to fail on some platforms,
@@ -34,14 +39,13 @@ const INITIAL_BUFFER_SIZE: usize = 64;
3439
/// The empirical randomness properties of AES output is shown in "Empirical Evidence Concerning AES"
3540
/// by Peter Hellekalek and Stefan Wegenkittl.
3641
pub struct PRNG {
37-
aes: Crypter,
42+
aes: Aes128,
3843
random_source: PrfSession,
3944
}
4045
/// The following implementation is not thread-safe as several copies of PRNG
4146
/// can concurrently access the system random generator
4247
impl PRNG {
4348
pub fn new(seed: Option<[u8; SEED_SIZE]>) -> Result<PRNG> {
44-
let err = |_| runtime_error!("Crypter didn't initialize");
4549
let bytes = match seed {
4650
Some(bytes) => bytes,
4751
None => {
@@ -50,18 +54,16 @@ impl PRNG {
5054
bytes
5155
}
5256
};
53-
let mut c =
54-
Crypter::new(Cipher::aes_128_ecb(), Mode::Encrypt, &bytes, None).map_err(err)?;
55-
c.pad(false);
57+
let aes = aes::Aes128::new(GenericArray::from_slice(&bytes));
5658
Ok(PRNG {
57-
aes: c,
59+
aes,
5860
random_source: PrfSession::new(0, BUFFER_SIZE)?,
5961
})
6062
}
6163

6264
pub fn get_random_bytes(&mut self, n: usize) -> Result<Vec<u8>> {
6365
self.random_source
64-
.generate_random_bytes(&mut self.aes, n as u64)
66+
.generate_random_bytes(&self.aes, n as u64)
6567
}
6668

6769
fn get_random_key(&mut self) -> Result<[u8; SEED_SIZE]> {
@@ -129,33 +131,30 @@ impl PRNG {
129131
/// PRF(Prf) output is extended by computing AES_k(0|input)|...|AES_k(n-1|input)
130132
/// (see e.g. p.16 of [Kolesnikov et al.](https://eprint.iacr.org/2016/799.pdf)).
131133
pub(super) struct Prf {
132-
aes: Crypter,
134+
aes: Aes128,
133135
}
134136

135137
impl Prf {
136138
pub fn new(key: Option<[u8; SEED_SIZE]>) -> Result<Prf> {
137-
let err = |_| runtime_error!("Crypter didn't initialize");
138139
let key_bytes = match key {
139140
Some(bytes) => bytes,
140141
None => {
141142
let mut gen = PRNG::new(None)?;
142143
gen.get_random_key()?
143144
}
144145
};
145-
let mut c =
146-
Crypter::new(Cipher::aes_128_ecb(), Mode::Encrypt, &key_bytes, None).map_err(err)?;
147-
c.pad(false);
148-
Ok(Prf { aes: c })
146+
let aes = aes::Aes128::new(GenericArray::from_slice(&key_bytes));
147+
Ok(Prf { aes })
149148
}
150149

151150
#[cfg(test)]
152151
fn output_bytes(&mut self, input: u64, n: u64) -> Result<Vec<u8>> {
153152
let initial_buffer_size = usize::min(BUFFER_SIZE, n as usize);
154-
PrfSession::new(input, initial_buffer_size)?.generate_random_bytes(&mut self.aes, n)
153+
PrfSession::new(input, initial_buffer_size)?.generate_random_bytes(&self.aes, n)
155154
}
156155

157156
pub(super) fn output_value(&mut self, input: u64, t: Type) -> Result<Value> {
158-
PrfSession::new(input, INITIAL_BUFFER_SIZE)?.recursively_generate_value(&mut self.aes, t)
157+
PrfSession::new(input, INITIAL_BUFFER_SIZE)?.recursively_generate_value(&self.aes, t)
159158
}
160159

161160
pub(super) fn output_permutation(&mut self, input: u64, n: u64) -> Result<Value> {
@@ -168,7 +167,7 @@ impl Prf {
168167
let mut session = PrfSession::new(input, initial_buffer_size)?;
169168
let mut a: Vec<u64> = (0..n).collect();
170169
for i in 1..n {
171-
let j = session.generate_u32_in_range(&mut self.aes, i as u32 + 1)?;
170+
let j = session.generate_u32_in_range(&self.aes, i as u32 + 1)?;
172171
a.swap(i as usize, j as usize);
173172
}
174173
Value::from_flattened_array_u64(&a, UINT64)
@@ -189,39 +188,31 @@ struct PrfSession {
189188

190189
impl PrfSession {
191190
pub fn new(input: u64, initial_buffer_size: usize) -> Result<Self> {
192-
// Round up to the nearest multiple of 16.
193-
let initial_buffer_size = (initial_buffer_size + 15) / 16 * 16;
191+
// Round up to the nearest multiple of BLOCK_SIZE.
192+
let initial_buffer_size = (initial_buffer_size + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE;
194193
Ok(Self {
195194
input: (input as u128) << 64,
196195
// Note: we'll drop the "leftover" bytes when PrfSession is destroyed. They are not useful, but if there
197196
// are many small PRFs, this can be wasteful.
198-
buffer: vec![0u8; initial_buffer_size + Cipher::aes_128_cbc().block_size()],
197+
buffer: vec![0u8; initial_buffer_size],
199198
next_byte: initial_buffer_size,
200199
current_buffer_size: initial_buffer_size,
201200
next_buffer_size: initial_buffer_size,
202201
})
203202
}
204203

205-
fn generate_one_batch(&mut self, aes: &mut Crypter) -> Result<()> {
204+
fn generate_one_batch(&mut self, aes: &Aes128) -> Result<()> {
206205
let mut i_bytes = vec![0u8; self.next_buffer_size];
207206
for i in (0..i_bytes.len()).step_by(16) {
208207
i_bytes[i..i + 16].copy_from_slice(&self.input.to_le_bytes());
209208
self.input = self.input.wrapping_add(1);
210209
}
211-
let buffer_len = self.next_buffer_size + Cipher::aes_128_cbc().block_size();
210+
let buffer_len = self.next_buffer_size;
212211
if buffer_len != self.buffer.len() {
213212
self.buffer.resize(buffer_len, 0);
214213
}
215-
let count = aes
216-
.update(&i_bytes, &mut self.buffer)
217-
.map_err(|_| runtime_error!("Crypter didn't manage to update"))?;
218-
// finalization of Crypter is unnecessary since padding is turned off
219-
// check here https://www.openssl.org/docs/manmaster/man3/EVP_CipherUpdate.html
220-
if count != self.next_buffer_size {
221-
return Err(runtime_error!(
222-
"AES encryption returned a wrong number of bytes"
223-
));
224-
}
214+
aes.encrypt_padded_b2b::<NoPadding>(&i_bytes, &mut self.buffer)
215+
.map_err(|e| runtime_error!("Encryption error: {e:?}"))?;
225216
self.current_buffer_size = self.next_buffer_size;
226217
if self.next_buffer_size < BUFFER_SIZE {
227218
self.next_buffer_size = usize::min(BUFFER_SIZE, self.next_buffer_size * 2);
@@ -230,13 +221,13 @@ impl PrfSession {
230221
Ok(())
231222
}
232223

233-
fn generate_random_bytes(&mut self, aes: &mut Crypter, n: u64) -> Result<Vec<u8>> {
224+
fn generate_random_bytes(&mut self, aes: &Aes128, n: u64) -> Result<Vec<u8>> {
234225
let mut bytes = vec![0u8; n as usize];
235226
self.fill_random_bytes(aes, bytes.as_mut_slice())?;
236227
Ok(bytes)
237228
}
238229

239-
fn fill_random_bytes(&mut self, aes: &mut Crypter, mut buff: &mut [u8]) -> Result<()> {
230+
fn fill_random_bytes(&mut self, aes: &Aes128, mut buff: &mut [u8]) -> Result<()> {
240231
while !buff.is_empty() {
241232
let need_bytes = buff.len();
242233
let ready_bytes = &self.buffer[self.next_byte..self.current_buffer_size];
@@ -254,7 +245,7 @@ impl PrfSession {
254245
Ok(())
255246
}
256247

257-
fn recursively_generate_value(&mut self, aes: &mut Crypter, tp: Type) -> Result<Value> {
248+
fn recursively_generate_value(&mut self, aes: &Aes128, tp: Type) -> Result<Value> {
258249
match tp {
259250
Type::Scalar(_) | Type::Array(_, _) => {
260251
let bit_size = get_size_in_bits(tp)?;
@@ -283,13 +274,11 @@ impl PrfSession {
283274
// Generates a random number from 0..2^(8 * NEED_BYTES).
284275
fn generate_random_number_const<const NEED_BYTES: usize>(
285276
&mut self,
286-
aes: &mut Crypter,
277+
aes: &Aes128,
287278
) -> Result<u64> {
288279
let mut res = [0u8; 8];
289-
// Note: sometimes we copy garbage bytes, but they are discarded later.
290-
res.copy_from_slice(&self.buffer[self.next_byte..self.next_byte + 8]);
291-
292280
let use_bytes = std::cmp::min(self.current_buffer_size - self.next_byte, NEED_BYTES);
281+
res[..use_bytes].copy_from_slice(&self.buffer[self.next_byte..self.next_byte + use_bytes]);
293282
if use_bytes == NEED_BYTES {
294283
self.next_byte += use_bytes;
295284
} else {
@@ -306,7 +295,7 @@ impl PrfSession {
306295
}
307296

308297
// Generates a random number from 0..2^(8 * need_bytes).
309-
fn generate_random_number(&mut self, aes: &mut Crypter, need_bytes: usize) -> Result<u64> {
298+
fn generate_random_number(&mut self, aes: &Aes128, need_bytes: usize) -> Result<u64> {
310299
match need_bytes {
311300
1 => self.generate_random_number_const::<1>(aes),
312301
2 => self.generate_random_number_const::<2>(aes),
@@ -320,7 +309,7 @@ impl PrfSession {
320309
}
321310
}
322311

323-
fn generate_u32_in_range(&mut self, aes: &mut Crypter, modulus: u32) -> Result<u32> {
312+
fn generate_u32_in_range(&mut self, aes: &Aes128, modulus: u32) -> Result<u32> {
324313
let modulus = modulus as u64;
325314
// Generate one extra byte of randomness to have reasonably low resampling probability.
326315
let need_bytes = (modulus.next_power_of_two().trailing_zeros() + 7) / 8 + 1;

0 commit comments

Comments
 (0)