remove all possible unsafe code in crypto (#1168)

* use #[repr(C)] for all hash types

* use a zeroed buffer in crypto::ec::sign

* eliminate most usages of unsafe in crypto::ecdh::agree

* eliminate all possible unsafety in crypto module
This commit is contained in:
Robert Habermeier 2016-05-28 21:48:42 +02:00 committed by Gav Wood
parent 87d0f09a44
commit ea08dd76a5
2 changed files with 33 additions and 22 deletions

View File

@ -38,13 +38,10 @@ lazy_static! {
impl Signature { impl Signature {
/// Create a new signature from the R, S and V componenets. /// Create a new signature from the R, S and V componenets.
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature { pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature {
use std::ptr;
let mut ret: Signature = Signature::new(); let mut ret: Signature = Signature::new();
unsafe { (&mut ret[0..32]).copy_from_slice(r);
let retslice: &mut [u8] = &mut ret; (&mut ret[32..64]).copy_from_slice(s);
ptr::copy(r.as_ptr(), retslice.as_mut_ptr(), 32);
ptr::copy(s.as_ptr(), retslice.as_mut_ptr().offset(32), 32);
}
ret[64] = v; ret[64] = v;
ret ret
} }
@ -145,7 +142,10 @@ impl KeyPair {
let (sec, publ) = try!(context.generate_keypair(&mut rng)); let (sec, publ) = try!(context.generate_keypair(&mut rng));
let serialized = publ.serialize_vec(context, false); let serialized = publ.serialize_vec(context, false);
let p: Public = Public::from_slice(&serialized[1..65]); let p: Public = Public::from_slice(&serialized[1..65]);
let s: Secret = unsafe { ::std::mem::transmute(sec) };
let mut s = Secret::new();
s.copy_from_slice(&sec[0..32]);
Ok(KeyPair { Ok(KeyPair {
secret: s, secret: s,
public: p, public: p,
@ -193,12 +193,14 @@ pub mod ec {
/// Returns siganture of message hash. /// Returns siganture of message hash.
pub fn sign(secret: &Secret, message: &H256) -> Result<Signature, CryptoError> { pub fn sign(secret: &Secret, message: &H256) -> Result<Signature, CryptoError> {
// TODO: allow creation of only low-s signatures. // TODO: allow creation of only low-s signatures.
use secp256k1::*; use secp256k1::{Message, key};
let context = &crypto::SECP256K1; let context = &crypto::SECP256K1;
// no way to create from raw byte array.
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec)); let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec));
let (rec_id, data) = s.serialize_compact(context); let (rec_id, data) = s.serialize_compact(context);
let mut signature: crypto::Signature = unsafe { ::std::mem::uninitialized() }; let mut signature = crypto::Signature::new();
signature.clone_from_slice(&data); signature.clone_from_slice(&data);
signature[64] = rec_id.to_i32() as u8; signature[64] = rec_id.to_i32() as u8;
@ -217,10 +219,12 @@ pub mod ec {
let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32)))); let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32))));
let sig = rsig.to_standard(context); let sig = rsig.to_standard(context);
let mut pdata: [u8; 65] = [4u8; 65]; let pdata: [u8; 65] = {
let ptr = pdata[1..].as_mut_ptr(); let mut temp = [4u8; 65];
let src = public.as_ptr(); (&mut temp[1..65]).copy_from_slice(public);
unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) }; temp
};
let publ = try!(key::PublicKey::from_slice(context, &pdata)); let publ = try!(key::PublicKey::from_slice(context, &pdata));
match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) { match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) {
Ok(_) => Ok(true), Ok(_) => Ok(true),
@ -252,21 +256,27 @@ pub mod ec {
/// ECDH functions /// ECDH functions
#[cfg_attr(feature="dev", allow(similar_names))] #[cfg_attr(feature="dev", allow(similar_names))]
pub mod ecdh { pub mod ecdh {
use crypto::*; use hash::FixedHash;
use crypto::{self}; use crypto::{self, Secret, Public, CryptoError};
/// Agree on a shared secret /// Agree on a shared secret
pub fn agree(secret: &Secret, public: &Public, ) -> Result<Secret, CryptoError> { pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, CryptoError> {
use secp256k1::*; use secp256k1::{ecdh, key};
let context = &crypto::SECP256K1; let context = &crypto::SECP256K1;
let mut pdata: [u8; 65] = [4u8; 65]; let pdata = {
let ptr = pdata[1..].as_mut_ptr(); let mut temp = [4u8; 65];
let src = public.as_ptr(); (&mut temp[1..65]).copy_from_slice(&public[0..64]);
unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) }; temp
};
let publ = try!(key::PublicKey::from_slice(context, &pdata)); let publ = try!(key::PublicKey::from_slice(context, &pdata));
// no way to create SecretKey from raw byte array.
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
let s: Secret = unsafe { ::std::mem::transmute(shared) };
let mut s = crypto::Secret::new();
s.copy_from_slice(&shared[0..32]);
Ok(s) Ok(s)
} }
} }

View File

@ -75,6 +75,7 @@ pub fn clean_0x(s: &str) -> &str {
macro_rules! impl_hash { macro_rules! impl_hash {
($from: ident, $size: expr) => { ($from: ident, $size: expr) => {
#[derive(Eq)] #[derive(Eq)]
#[repr(C)]
/// Unformatted binary data of fixed length. /// Unformatted binary data of fixed length.
pub struct $from (pub [u8; $size]); pub struct $from (pub [u8; $size]);