summaryrefslogtreecommitdiffstats
path: root/openpgp/src/crypto
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-06-27 13:44:52 +0200
committerJustus Winter <justus@sequoia-pgp.org>2019-06-27 15:18:37 +0200
commit2cabbfa80fc8bd7814b76a66ae916cba0b30c711 (patch)
tree3c2092ec1e6bd1bf96239591dfeeeb97206415e4 /openpgp/src/crypto
parent7c9198d6e5ba4b7e475185b496dcaeb3e4ec0498 (diff)
openpgp: Refactor memory protection.
- Create a new module for memory protection. Move common code from `Password` and `SessionKey` to a new type `Protected`.
Diffstat (limited to 'openpgp/src/crypto')
-rw-r--r--openpgp/src/crypto/aead.rs2
-rw-r--r--openpgp/src/crypto/mem.rs98
-rw-r--r--openpgp/src/crypto/mod.rs89
-rw-r--r--openpgp/src/crypto/mpis.rs5
4 files changed, 123 insertions, 71 deletions
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index 167a4f31..b6ca09d3 100644
--- a/openpgp/src/crypto/aead.rs
+++ b/openpgp/src/crypto/aead.rs
@@ -15,7 +15,7 @@ use conversions::{
use Error;
use Result;
use crypto::SessionKey;
-use super::secure_cmp;
+use crypto::mem::secure_cmp;
impl AEADAlgorithm {
/// Returns the digest size of the AEAD algorithm.
diff --git a/openpgp/src/crypto/mem.rs b/openpgp/src/crypto/mem.rs
new file mode 100644
index 00000000..77469209
--- /dev/null
+++ b/openpgp/src/crypto/mem.rs
@@ -0,0 +1,98 @@
+//! Memory protection.
+
+use std::cmp::{min, Ordering};
+use std::fmt;
+use std::ops::{Deref, DerefMut};
+
+use memsec;
+
+/// Holds a session key.
+///
+/// The session key is cleared when dropped.
+#[derive(Clone, Eq)]
+pub struct Protected(Box<[u8]>);
+
+impl PartialEq for Protected {
+ fn eq(&self, other: &Self) -> bool {
+ secure_cmp(&self.0, &other.0) == Ordering::Equal
+ }
+}
+
+impl Protected {
+ /// Converts to a buffer for modification.
+ pub unsafe fn into_vec(mut self) -> Vec<u8> {
+ std::mem::replace(&mut self.0, vec![].into()).into()
+ }
+}
+
+impl Deref for Protected {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl AsRef<[u8]> for Protected {
+ fn as_ref(&self) -> &[u8] {
+ &self.0
+ }
+}
+
+impl DerefMut for Protected {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ &mut self.0
+ }
+}
+
+impl From<Vec<u8>> for Protected {
+ fn from(v: Vec<u8>) -> Self {
+ Protected(v.into_boxed_slice())
+ }
+}
+
+impl From<Box<[u8]>> for Protected {
+ fn from(v: Box<[u8]>) -> Self {
+ Protected(v)
+ }
+}
+
+impl From<&[u8]> for Protected {
+ fn from(v: &[u8]) -> Self {
+ Vec::from(v).into()
+ }
+}
+
+impl Drop for Protected {
+ fn drop(&mut self) {
+ unsafe {
+ memsec::memzero(self.0.as_mut_ptr(), self.0.len());
+ }
+ }
+}
+
+impl fmt::Debug for Protected {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if cfg!(debug_assertions) {
+ write!(f, "{:?}", self.0)
+ } else {
+ f.write_str("[<Redacted>]")
+ }
+ }
+}
+
+/// Time-constant comparison.
+pub fn secure_cmp(a: &[u8], b: &[u8]) -> Ordering {
+ let ord1 = a.len().cmp(&b.len());
+ let ord2 = unsafe {
+ memsec::memcmp(a.as_ptr(), b.as_ptr(), min(a.len(), b.len()))
+ };
+ let ord2 = match ord2 {
+ 0 => Ordering::Equal,
+ a if a < 0 => Ordering::Less,
+ a if a > 0 => Ordering::Greater,
+ _ => unreachable!(),
+ };
+
+ if ord1 == Ordering::Equal { ord2 } else { ord1 }
+}
diff --git a/openpgp/src/crypto/mod.rs b/openpgp/src/crypto/mod.rs
index 63f32393..cc1bdc18 100644
--- a/openpgp/src/crypto/mod.rs
+++ b/openpgp/src/crypto/mod.rs
@@ -3,9 +3,7 @@
use std::io::Read;
use std::ops::{Deref, DerefMut};
use std::fmt;
-use std::cmp::{min, Ordering};
-use memsec;
use nettle::{self, Random, Yarrow};
use constants::HashAlgorithm;
@@ -17,6 +15,7 @@ pub(crate) mod ecdh;
mod hash;
mod keygrip;
pub use self::keygrip::Keygrip;
+pub(crate) mod mem;
pub mod mpis;
pub mod s2k;
pub mod sexp;
@@ -33,26 +32,20 @@ pub use self::hash::Hash;
/// Holds a session key.
///
/// The session key is cleared when dropped.
-#[derive(Clone, Eq)]
-pub struct SessionKey(Box<[u8]>);
-
-impl PartialEq for SessionKey {
- fn eq(&self, other: &Self) -> bool {
- secure_cmp(&self.0, &other.0) == Ordering::Equal
- }
-}
+#[derive(Clone, PartialEq, Eq)]
+pub struct SessionKey(mem::Protected);
impl SessionKey {
/// Creates a new session key.
pub fn new(rng: &mut Yarrow, size: usize) -> Self {
- let mut sk = vec![0; size];
+ let mut sk: mem::Protected = vec![0; size].into();
rng.random(&mut sk);
- sk.into()
+ Self(sk)
}
/// Converts to a buffer for modification.
- pub unsafe fn into_vec(mut self) -> Vec<u8> {
- std::mem::replace(&mut self.0, vec![].into()).into()
+ pub unsafe fn into_vec(self) -> Vec<u8> {
+ self.0.into_vec()
}
}
@@ -76,15 +69,21 @@ impl DerefMut for SessionKey {
}
}
+impl From<mem::Protected> for SessionKey {
+ fn from(v: mem::Protected) -> Self {
+ SessionKey(v)
+ }
+}
+
impl From<Vec<u8>> for SessionKey {
fn from(v: Vec<u8>) -> Self {
- SessionKey(v.into_boxed_slice())
+ SessionKey(v.into())
}
}
impl From<Box<[u8]>> for SessionKey {
fn from(v: Box<[u8]>) -> Self {
- SessionKey(v)
+ SessionKey(v.into())
}
}
@@ -94,35 +93,17 @@ impl From<&[u8]> for SessionKey {
}
}
-impl Drop for SessionKey {
- fn drop(&mut self) {
- unsafe {
- memsec::memzero(self.0.as_mut_ptr(), self.0.len());
- }
- }
-}
-
impl fmt::Debug for SessionKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- if cfg!(debug_assertions) {
- write!(f, "SessionKey ({:?})", self.0)
- } else {
- f.write_str("SessionKey ( <Redacted> )")
- }
+ write!(f, "SessionKey ({:?})", self.0)
}
}
/// Holds a password.
///
/// The password is cleared when dropped.
-#[derive(Clone, Eq)]
-pub struct Password(Box<[u8]>);
-
-impl PartialEq for Password {
- fn eq(&self, other: &Self) -> bool {
- secure_cmp(&self.0, &other.0) == Ordering::Equal
- }
-}
+#[derive(Clone, PartialEq, Eq)]
+pub struct Password(mem::Protected);
impl AsRef<[u8]> for Password {
fn as_ref(&self) -> &[u8] {
@@ -140,13 +121,13 @@ impl Deref for Password {
impl From<Vec<u8>> for Password {
fn from(v: Vec<u8>) -> Self {
- Password(v.into_boxed_slice())
+ Password(v.into())
}
}
impl From<Box<[u8]>> for Password {
fn from(v: Box<[u8]>) -> Self {
- Password(v)
+ Password(v.into())
}
}
@@ -168,21 +149,9 @@ impl From<&[u8]> for Password {
}
}
-impl Drop for Password {
- fn drop(&mut self) {
- unsafe {
- memsec::memzero(self.0.as_mut_ptr(), self.0.len());
- }
- }
-}
-
impl fmt::Debug for Password {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- if cfg!(debug_assertions) {
- write!(f, "Password ({:?})", self.0)
- } else {
- f.write_str("Password ( <Redacted> )")
- }
+ write!(f, "Password ({:?})", self.0)
}
}
@@ -240,19 +209,3 @@ fn hash_file_test() {
&::conversions::to_hex(&digest[..], false));
}
}
-
-/// Time-constant comparison.
-fn secure_cmp(a: &[u8], b: &[u8]) -> Ordering {
- let ord1 = a.len().cmp(&b.len());
- let ord2 = unsafe {
- memsec::memcmp(a.as_ptr(), b.as_ptr(), min(a.len(), b.len()))
- };
- let ord2 = match ord2 {
- 0 => Ordering::Equal,
- a if a < 0 => Ordering::Less,
- a if a > 0 => Ordering::Greater,
- _ => unreachable!(),
- };
-
- if ord1 == Ordering::Equal { ord2 } else { ord1 }
-}
diff --git a/openpgp/src/crypto/mpis.rs b/openpgp/src/crypto/mpis.rs
index c563ccb3..d93223ca 100644
--- a/openpgp/src/crypto/mpis.rs
+++ b/openpgp/src/crypto/mpis.rs
@@ -14,6 +14,7 @@ use constants::{
SymmetricAlgorithm,
};
use crypto::Hash;
+use crypto::mem::secure_cmp;
use serialize::Serialize;
use nettle;
@@ -443,7 +444,7 @@ impl fmt::Debug for SecretKey {
fn secure_mpi_cmp(a: &MPI, b: &MPI) -> Ordering {
let ord1 = a.bits.cmp(&b.bits);
- let ord2 = super::secure_cmp(&a.value, &b.value);
+ let ord2 = secure_cmp(&a.value, &b.value);
if ord1 == Ordering::Equal { ord2 } else { ord1 }
}
@@ -499,7 +500,7 @@ impl PartialOrd for SecretKey {
}
(&SecretKey::Unknown{ mpis: ref mpis1, rest: ref rest1 }
,&SecretKey::Unknown{ mpis: ref mpis2, rest: ref rest2 }) => {
- let o1 = super::secure_cmp(rest1, rest2);
+ let o1 = secure_cmp(rest1, rest2);
let on = mpis1.iter().zip(mpis2.iter()).map(|(a,b)| {
secure_mpi_cmp(a, b)
}).collect::<Vec<_>>();