Skip to content

Commit 505556b

Browse files
authored
Clear secrets when dropped (#183)
closes #171
1 parent 10d7e84 commit 505556b

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ serde = "1"
2222
serde_derive = "1"
2323
failure = "0.1"
2424
merlin = "0.4"
25+
clear_on_drop = "0.2.3"
2526

2627
[dev-dependencies]
2728
hex = "0.3"

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ extern crate digest;
1010
extern crate rand;
1111
extern crate sha3;
1212

13+
extern crate clear_on_drop;
1314
extern crate curve25519_dalek;
1415
extern crate merlin;
1516
extern crate subtle;

src/range_proof/party.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
1414
use curve25519_dalek::scalar::Scalar;
1515
use curve25519_dalek::traits::MultiscalarMul;
1616

17+
use clear_on_drop::clear::Clear;
1718
use errors::MPCError;
1819
use generators::{BulletproofGens, PedersenGens};
1920
use rand;
@@ -129,6 +130,14 @@ impl<'a> PartyAwaitingPosition<'a> {
129130
}
130131
}
131132

133+
/// Overwrite secrets with null bytes when they go out of scope.
134+
impl<'a> Drop for PartyAwaitingPosition<'a> {
135+
fn drop(&mut self) {
136+
self.v.clear();
137+
self.v_blinding.clear();
138+
}
139+
}
140+
132141
/// A party which has committed to the bits of its value
133142
/// and is waiting for the aggregated value challenge from the dealer.
134143
pub struct PartyAwaitingBitChallenge<'a> {
@@ -206,6 +215,28 @@ impl<'a> PartyAwaitingBitChallenge<'a> {
206215
}
207216
}
208217

218+
/// Overwrite secrets with null bytes when they go out of scope.
219+
impl<'a> Drop for PartyAwaitingBitChallenge<'a> {
220+
fn drop(&mut self) {
221+
self.v.clear();
222+
self.v_blinding.clear();
223+
self.a_blinding.clear();
224+
self.s_blinding.clear();
225+
226+
// Important: due to how ClearOnDrop auto-implements InitializableFromZeroed
227+
// for T: Default, calling .clear() on Vec compiles, but does not
228+
// clear the content. Instead, it only clears the Vec's header.
229+
// Clearing the underlying buffer item-by-item will do the job, but will
230+
// keep the header as-is, which is fine since the header does not contain secrets.
231+
for e in self.s_L.iter_mut() {
232+
e.clear();
233+
}
234+
for e in self.s_R.iter_mut() {
235+
e.clear();
236+
}
237+
}
238+
}
239+
209240
/// A party which has committed to their polynomial coefficents
210241
/// and is waiting for the polynomial challenge from the dealer.
211242
pub struct PartyAwaitingPolyChallenge {
@@ -252,3 +283,17 @@ impl PartyAwaitingPolyChallenge {
252283
})
253284
}
254285
}
286+
287+
/// Overwrite secrets with null bytes when they go out of scope.
288+
impl Drop for PartyAwaitingPolyChallenge {
289+
fn drop(&mut self) {
290+
self.v_blinding.clear();
291+
self.a_blinding.clear();
292+
self.s_blinding.clear();
293+
self.t_1_blinding.clear();
294+
self.t_2_blinding.clear();
295+
296+
// Note: polynomials r_poly, l_poly and t_poly
297+
// are cleared within their own Drop impls.
298+
}
299+
}

src/util.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![deny(missing_docs)]
22
#![allow(non_snake_case)]
33

4+
use clear_on_drop::clear::Clear;
45
use curve25519_dalek::scalar::Scalar;
56
use inner_product_proof::inner_product;
67

@@ -87,6 +88,25 @@ impl Poly2 {
8788
}
8889
}
8990

91+
impl Drop for VecPoly1 {
92+
fn drop(&mut self) {
93+
for e in self.0.iter_mut() {
94+
e.clear();
95+
}
96+
for e in self.1.iter_mut() {
97+
e.clear();
98+
}
99+
}
100+
}
101+
102+
impl Drop for Poly2 {
103+
fn drop(&mut self) {
104+
self.0.clear();
105+
self.1.clear();
106+
self.2.clear();
107+
}
108+
}
109+
90110
/// Raises `x` to the power `n` using binary exponentiation,
91111
/// with (1 to 2)*lg(n) scalar multiplications.
92112
/// TODO: a consttime version of this would be awfully similar to a Montgomery ladder.
@@ -220,4 +240,49 @@ mod tests {
220240
assert_eq!(sum_of_powers_slow(&x, 5), Scalar::from(11111u64));
221241
assert_eq!(sum_of_powers_slow(&x, 6), Scalar::from(111111u64));
222242
}
243+
244+
#[test]
245+
fn vec_of_scalars_clear_on_drop() {
246+
let mut v = vec![Scalar::from(24u64), Scalar::from(42u64)];
247+
248+
for e in v.iter_mut() {
249+
e.clear();
250+
}
251+
252+
fn flat_slice<T>(x: &[T]) -> &[u8] {
253+
use core::mem;
254+
use core::slice;
255+
256+
unsafe { slice::from_raw_parts(x.as_ptr() as *const u8, mem::size_of_val(x)) }
257+
}
258+
259+
assert_eq!(flat_slice(&v.as_slice()), &[0u8; 64][..]);
260+
assert_eq!(v[0], Scalar::zero());
261+
assert_eq!(v[1], Scalar::zero());
262+
}
263+
264+
#[test]
265+
fn tuple_of_scalars_clear_on_drop() {
266+
let mut v = Poly2(
267+
Scalar::from(24u64),
268+
Scalar::from(42u64),
269+
Scalar::from(255u64),
270+
);
271+
272+
v.0.clear();
273+
v.1.clear();
274+
v.2.clear();
275+
276+
fn as_bytes<T>(x: &T) -> &[u8] {
277+
use core::mem;
278+
use core::slice;
279+
280+
unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) }
281+
}
282+
283+
assert_eq!(as_bytes(&v), &[0u8; 96][..]);
284+
assert_eq!(v.0, Scalar::zero());
285+
assert_eq!(v.1, Scalar::zero());
286+
assert_eq!(v.2, Scalar::zero());
287+
}
223288
}

0 commit comments

Comments
 (0)