]> git.lizzy.rs Git - rust.git/commitdiff
std: make sure HashMap from_iter uses random initialization by default
authorErick Tryzelaar <erick.tryzelaar@gmail.com>
Mon, 23 Jun 2014 23:15:40 +0000 (19:15 -0400)
committerErick Tryzelaar <erick.tryzelaar@gmail.com>
Mon, 30 Jun 2014 13:57:05 +0000 (06:57 -0700)
It turns out that HashMap's from_iter implementation was being
initialized without the sip keys being randomized. This adds
a custom default hasher that should avoid this potential vulnerability.

src/libstd/collections/hashmap.rs
src/libstd/hash.rs [new file with mode: 0644]
src/libstd/lib.rs

index b94141748d57fe2561cc14a4a20fb43ace1338ca..be5c2e25141dec81e578256185be45e662a7cce6 100644 (file)
 use default::Default;
 use fmt::Show;
 use fmt;
-use hash::{Hash, Hasher, sip};
+use hash::{Hash, Hasher, RandomSipHasher};
 use iter::{Iterator, FilterMap, Chain, Repeat, Zip, Extendable};
 use iter::{range, range_inclusive, FromIterator};
 use iter;
 use mem::replace;
 use num;
 use option::{Some, None, Option};
-use rand::Rng;
-use rand;
 use result::{Ok, Err};
 
 mod table {
@@ -733,7 +731,7 @@ fn reserve(&mut self, new_capacity: uint) {
 /// }
 /// ```
 #[deriving(Clone)]
-pub struct HashMap<K, V, H = sip::SipHasher> {
+pub struct HashMap<K, V, H = RandomSipHasher> {
     // All hashes are keyed on these values, to prevent hash collision attacks.
     hasher: H,
 
@@ -1033,18 +1031,15 @@ fn pop(&mut self, k: &K) -> Option<V> {
 
 }
 
-impl<K: Hash + Eq, V> HashMap<K, V, sip::SipHasher> {
+impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> {
     /// Create an empty HashMap.
-    pub fn new() -> HashMap<K, V, sip::SipHasher> {
+    pub fn new() -> HashMap<K, V, RandomSipHasher> {
         HashMap::with_capacity(INITIAL_CAPACITY)
     }
 
     /// Creates an empty hash map with the given initial capacity.
-    pub fn with_capacity(capacity: uint) -> HashMap<K, V, sip::SipHasher> {
-        let mut r = rand::task_rng();
-        let r0 = r.gen();
-        let r1 = r.gen();
-        let hasher = sip::SipHasher::new_with_keys(r0, r1);
+    pub fn with_capacity(capacity: uint) -> HashMap<K, V, RandomSipHasher> {
+        let hasher = RandomSipHasher::new();
         HashMap::with_capacity_and_hasher(capacity, hasher)
     }
 }
@@ -1489,7 +1484,7 @@ fn extend<T: Iterator<(K, V)>>(&mut self, mut iter: T) {
 /// HashMap where the value is (). As with the `HashMap` type, a `HashSet`
 /// requires that the elements implement the `Eq` and `Hash` traits.
 #[deriving(Clone)]
-pub struct HashSet<T, H = sip::SipHasher> {
+pub struct HashSet<T, H = RandomSipHasher> {
     map: HashMap<T, (), H>
 }
 
@@ -1529,15 +1524,15 @@ fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) }
     fn remove(&mut self, value: &T) -> bool { self.map.remove(value) }
 }
 
-impl<T: Hash + Eq> HashSet<T, sip::SipHasher> {
+impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
     /// Create an empty HashSet
-    pub fn new() -> HashSet<T, sip::SipHasher> {
+    pub fn new() -> HashSet<T, RandomSipHasher> {
         HashSet::with_capacity(INITIAL_CAPACITY)
     }
 
     /// Create an empty HashSet with space for at least `n` elements in
     /// the hash table.
-    pub fn with_capacity(capacity: uint) -> HashSet<T, sip::SipHasher> {
+    pub fn with_capacity(capacity: uint) -> HashSet<T, RandomSipHasher> {
         HashSet { map: HashMap::with_capacity(capacity) }
     }
 }
diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs
new file mode 100644 (file)
index 0000000..fd1bab2
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Generic hashing support.
+
+pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip};
+
+use default::Default;
+use rand::Rng;
+use rand;
+
+/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes
+/// initialized with random keys.
+#[deriving(Clone)]
+pub struct RandomSipHasher {
+    hasher: sip::SipHasher,
+}
+
+impl RandomSipHasher {
+    /// Construct a new `RandomSipHasher` that is initialized with random keys.
+    #[inline]
+    pub fn new() -> RandomSipHasher {
+        let mut r = rand::task_rng();
+        let r0 = r.gen();
+        let r1 = r.gen();
+        RandomSipHasher {
+            hasher: sip::SipHasher::new_with_keys(r0, r1),
+        }
+    }
+}
+
+impl Hasher<sip::SipState> for RandomSipHasher {
+    #[inline]
+    fn hash<T: Hash<sip::SipState>>(&self, value: &T) -> u64 {
+        self.hasher.hash(value)
+    }
+}
+
+impl Default for RandomSipHasher {
+    #[inline]
+    fn default() -> RandomSipHasher {
+        RandomSipHasher::new()
+    }
+}
index f63e69f3cca0a17af6720d38f95608212ccee046..12ad1d64344b10ccc73bae8b1d75017020d4fab1 100644 (file)
 pub use alloc::owned;
 pub use alloc::rc;
 
-pub use core_collections::hash;
 pub use core_collections::slice;
 pub use core_collections::str;
 pub use core_collections::string;
@@ -236,6 +235,7 @@ fn start(argc: int, argv: *const *const u8) -> int {
 /* Common data structures */
 
 pub mod collections;
+pub mod hash;
 
 /* Tasks and communication */