libpasta 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +41 -0
  9. data/Rakefile +37 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/ext/Rakefile +9 -0
  13. data/ext/pasta-bindings/.gitmodules +3 -0
  14. data/ext/pasta-bindings/Makefile +84 -0
  15. data/ext/pasta-bindings/README.md +54 -0
  16. data/ext/pasta-bindings/libpasta/.gitignore +2 -0
  17. data/ext/pasta-bindings/libpasta/.travis.yml +60 -0
  18. data/ext/pasta-bindings/libpasta/Cargo.toml +42 -0
  19. data/ext/pasta-bindings/libpasta/LICENSE.md +21 -0
  20. data/ext/pasta-bindings/libpasta/Makefile +27 -0
  21. data/ext/pasta-bindings/libpasta/README.md +78 -0
  22. data/ext/pasta-bindings/libpasta/benches/bench.rs +125 -0
  23. data/ext/pasta-bindings/libpasta/examples/alternate_key_source.rs +33 -0
  24. data/ext/pasta-bindings/libpasta/examples/config.rs +10 -0
  25. data/ext/pasta-bindings/libpasta/examples/config_hmac.rs +25 -0
  26. data/ext/pasta-bindings/libpasta/examples/hash_password.rs +10 -0
  27. data/ext/pasta-bindings/libpasta/examples/migrate_password.rs +47 -0
  28. data/ext/pasta-bindings/libpasta/examples/verify_password.rs +24 -0
  29. data/ext/pasta-bindings/libpasta/libpasta-capi/Cargo.toml +12 -0
  30. data/ext/pasta-bindings/libpasta/libpasta-capi/ctest/compile +6 -0
  31. data/ext/pasta-bindings/libpasta/libpasta-capi/ctest/test +0 -0
  32. data/ext/pasta-bindings/libpasta/libpasta-capi/ctest/test.c +12 -0
  33. data/ext/pasta-bindings/libpasta/libpasta-capi/include/pasta.h +6 -0
  34. data/ext/pasta-bindings/libpasta/libpasta-capi/src/lib.rs +80 -0
  35. data/ext/pasta-bindings/libpasta/src/bench.rs +39 -0
  36. data/ext/pasta-bindings/libpasta/src/config.rs +358 -0
  37. data/ext/pasta-bindings/libpasta/src/hashing/de.rs +284 -0
  38. data/ext/pasta-bindings/libpasta/src/hashing/mod.rs +161 -0
  39. data/ext/pasta-bindings/libpasta/src/hashing/ser.rs +67 -0
  40. data/ext/pasta-bindings/libpasta/src/key/mod.rs +66 -0
  41. data/ext/pasta-bindings/libpasta/src/lib.rs +468 -0
  42. data/ext/pasta-bindings/libpasta/src/primitives/argon2.rs +180 -0
  43. data/ext/pasta-bindings/libpasta/src/primitives/bcrypt.rs +165 -0
  44. data/ext/pasta-bindings/libpasta/src/primitives/hmac.rs +134 -0
  45. data/ext/pasta-bindings/libpasta/src/primitives/mod.rs +312 -0
  46. data/ext/pasta-bindings/libpasta/src/primitives/pbkdf2.rs +272 -0
  47. data/ext/pasta-bindings/libpasta/src/primitives/scrypt.rs +144 -0
  48. data/ext/pasta-bindings/libpasta/src/sod.rs +46 -0
  49. data/ext/pasta-bindings/libpasta/tests/.libpasta.yaml +8 -0
  50. data/ext/pasta-bindings/libpasta/tests/common/mod.rs +37 -0
  51. data/ext/pasta-bindings/libpasta/tests/test_argon2.rs +8 -0
  52. data/ext/pasta-bindings/libpasta/tests/test_bcrypt.rs +8 -0
  53. data/ext/pasta-bindings/libpasta/tests/test_from_file.rs +13 -0
  54. data/ext/pasta-bindings/libpasta/tests/test_hmac.rs +26 -0
  55. data/ext/pasta-bindings/libpasta/tests/test_pbkdf2.rs +8 -0
  56. data/ext/pasta-bindings/libpasta/tests/test_ringpbkdf2.rs +8 -0
  57. data/ext/pasta-bindings/libpasta/tests/test_scrypt.rs +8 -0
  58. data/ext/pasta-bindings/pasta.i +31 -0
  59. data/ext/pasta-bindings/tests/Makefile +38 -0
  60. data/ext/pasta-bindings/tests/pasta_test.go +12 -0
  61. data/ext/pasta-bindings/tests/test.php +7 -0
  62. data/ext/pasta-bindings/tests/test.py +7 -0
  63. data/ext/pasta-bindings/tests/test.rb +5 -0
  64. data/lib/libpasta.rb +2 -0
  65. data/lib/libpasta/version.rb +3 -0
  66. data/libpasta.gemspec +52 -0
  67. data/spec/libpasta_spec.rb +11 -0
  68. data/spec/spec_helper.rb +11 -0
  69. metadata +183 -0
@@ -0,0 +1,312 @@
1
+ //! `Primitive` in `libpasta` refers to the raw hashing algorithms as
2
+ //! implemented in many libraries.
3
+ //!
4
+ //! The main algorithms here are re-exported for general use.
5
+ //! Each algorithm has a `new` and `default` function. The former can
6
+ //! be provided parameters and creates a new dynamic instance of that
7
+ //! parameter set. Whereas the latter refers to a statically referenced
8
+ //! parameter set.
9
+ //!
10
+ //! All implementations are wrapped in a `Primitive` struct,
11
+ //! which in effect works like a trait, since it derefs to a `PrimitiveImpl`.
12
+ //! This means that whether using a new or default parameter set, the overall
13
+ //! behaviour is equivalent.
14
+
15
+
16
+ /// `Argon2` implementations
17
+ ///
18
+ /// Currently only a native Rust implementation through `argon2rs`.
19
+ mod argon2;
20
+ pub use self::argon2::Argon2;
21
+
22
+ /// `Bcrypt` implementations
23
+ ///
24
+ /// Currently uses `rust_crypto`s `bcrypt` algorithm.
25
+ mod bcrypt;
26
+ pub use self::bcrypt::Bcrypt;
27
+
28
+ /// `HMAC` implementations
29
+ ///
30
+ /// Uses `ring::hmac` to provide an HMAC implementation. Key must either be
31
+ /// passed using `Hmac::with_key` or will be generated randomly with `Hmac::new`.
32
+ /// Still need to consider the best way to maintain keys for an application.
33
+ /// Perhaps need some kind of "key service" module.
34
+ mod hmac;
35
+ pub use self::hmac::Hmac;
36
+
37
+ /// `PBKDF2` implementations.
38
+ ///
39
+ /// Implementations are from both `ring` and the C `fastpbkdf2` implementations.
40
+ /// The latter is currently in use.
41
+ mod pbkdf2;
42
+ pub use self::pbkdf2::{Pbkdf2, RingPbkdf2};
43
+
44
+ /// `Scrypt` implementations.
45
+ ///
46
+ /// Currently uses `ring_pwhash` for the implementation.
47
+ mod scrypt;
48
+ pub use self::scrypt::Scrypt;
49
+
50
+
51
+ use sod::Sod;
52
+
53
+ use config;
54
+
55
+ use itertools::Itertools;
56
+ use itertools::FoldWhile::{Continue, Done};
57
+ use num_traits;
58
+ use num_traits::FromPrimitive;
59
+ use ring::{constant_time, digest};
60
+ use serde_mcf::{Hashes, Map, Value};
61
+
62
+ use std::cmp::Ordering;
63
+ use std::fmt;
64
+ use std::fmt::Write;
65
+ use std::ops::Deref;
66
+ use std::sync::Arc;
67
+
68
+ /// Password hashing primitives
69
+ ///
70
+ /// Each variant is backed up by different implementation.
71
+ /// Internally, primitives can either be static values, for example,
72
+ /// the `lazy_static` generated value `DEFAULT_PRIM`, or dynamically allocated
73
+ /// variables, which are `Arc<Box<...>>`.
74
+ ///
75
+ /// Most operations are expected to be performed using the static functions,
76
+ /// since most use the default algorithms. However, the flexibilty to support
77
+ /// arbitrary parameter sets is essential.
78
+ #[derive(Clone, PartialEq, PartialOrd)]
79
+ pub struct Primitive(pub Sod<PrimitiveImpl>);
80
+
81
+
82
+ impl fmt::Debug for Primitive {
83
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84
+ write!(f, "{:?}", self.0.deref())
85
+ }
86
+ }
87
+ /// Trait defining the functionality of a hashing primitive.
88
+ pub trait PrimitiveImpl: fmt::Debug + Send + Sync {
89
+ /// Compute the output of the primitive with input `password` and `salt`.
90
+ fn compute(&self, password: &[u8], salt: &[u8]) -> Vec<u8>;
91
+
92
+ /// Verify the password and salt against the hash.
93
+ ///
94
+ /// In many cases, this just checks whether
95
+ /// `compute(password, salt) == hash`.
96
+ fn verify(&self, password: &[u8], salt: &[u8], hash: &[u8]) -> bool {
97
+ constant_time::verify_slices_are_equal(&self.compute(password, salt), hash).is_ok()
98
+ }
99
+
100
+ /// Output the parameters of the primitive as a list of tuples.
101
+ fn params_as_vec(&self) -> Vec<(&'static str, String)>;
102
+
103
+ /// Return algorithm type as a MCF-compatible hash identifier.
104
+ fn hash_id(&self) -> Hashes;
105
+
106
+ /// Use the supplied `Config` to update the current `Primitive` with
107
+ /// a new key source.
108
+ fn update_key(&self, _config: &config::Config) -> Option<Primitive> {
109
+ None
110
+ }
111
+ }
112
+
113
+ impl<P: PrimitiveImpl + 'static> From<P> for Primitive {
114
+ fn from(other: P) -> Self {
115
+ Primitive(Sod::Dynamic(Arc::new(Box::new(other))))
116
+ }
117
+ }
118
+
119
+ impl PartialEq<PrimitiveImpl> for PrimitiveImpl {
120
+ fn eq(&self, other: &PrimitiveImpl) -> bool {
121
+ self.hash_id() == other.hash_id() && self.params_as_vec() == other.params_as_vec()
122
+ }
123
+ }
124
+
125
+ /// Compare two primitive parameterisations by first checking for equality of
126
+ /// the hash identifiers, and then attempting to compare the parameters
127
+ /// numerically.
128
+ impl PartialOrd<PrimitiveImpl> for PrimitiveImpl {
129
+ fn partial_cmp(&self, other: &PrimitiveImpl) -> Option<Ordering> {
130
+ if self.hash_id() == other.hash_id() {
131
+ self.params_as_vec()
132
+ .iter()
133
+ .zip(other.params_as_vec().iter())
134
+ .map(|(x, y)| if x == y {
135
+ Some(Ordering::Equal)
136
+ } else if x.0 != y.0 {
137
+ None
138
+ } else if let Ok(x) = x.1.parse::<f64>() {
139
+ if let Ok(y) = y.1.parse::<f64>() {
140
+ x.partial_cmp(&y)
141
+ } else {
142
+ None
143
+ }
144
+ } else {
145
+ None
146
+ })
147
+ .fold_while(None, |acc, c| if acc.is_none() {
148
+ Continue(c)
149
+ } else if c == acc || c == Some(Ordering::Equal) {
150
+ Continue(acc)
151
+ } else {
152
+ Done(None)
153
+ })
154
+ .into_inner()
155
+ } else {
156
+ None
157
+ }
158
+ }
159
+ }
160
+
161
+
162
+ impl Deref for Primitive {
163
+ type Target = Sod<PrimitiveImpl>;
164
+
165
+ fn deref(&self) -> &Sod<PrimitiveImpl> {
166
+ &self.0
167
+ }
168
+ }
169
+
170
+ #[derive(Debug, PartialEq, PartialOrd)]
171
+ pub(crate) struct Poisoned;
172
+
173
+ impl PrimitiveImpl for Poisoned {
174
+ fn compute(&self, _password: &[u8], _salt: &[u8]) -> Vec<u8> {
175
+ unreachable!()
176
+ }
177
+
178
+ fn verify(&self, _password: &[u8], _salt: &[u8], _hash: &[u8]) -> bool {
179
+ unreachable!()
180
+ }
181
+
182
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
183
+ vec![("poisoned", "".to_string())]
184
+ }
185
+
186
+ fn hash_id(&self) -> Hashes {
187
+ Hashes::Custom
188
+ }
189
+ }
190
+
191
+ /// Helper macro to unwrap the value or early return with `Poisoned`.
192
+ /// Necessary until `TryFrom` stabilises.
193
+ macro_rules! try_or_poisoned {
194
+ ($f:expr) => (
195
+ match $f {
196
+ Some(x) => x,
197
+ None => return Poisoned.into()
198
+ }
199
+ )
200
+ }
201
+
202
+ /// This will be `TryFrom` when it stabilises.
203
+ /// For now we just return a `Poisoned`
204
+ impl<'a> From<(&'a Hashes, &'a Map<String, Value>)> for Primitive {
205
+ fn from(other: (&Hashes, &Map<String, Value>)) -> Self {
206
+ match *other.0 {
207
+ Hashes::Argon2i | Hashes::Argon2d => {
208
+ let passes = try_or_poisoned!(other.1.get("t").and_then(value_as_int));
209
+ let lanes = try_or_poisoned!(other.1.get("p").and_then(value_as_int));
210
+ let kib = try_or_poisoned!(other.1.get("m").and_then(value_as_int));
211
+ Argon2::new(passes, lanes, kib)
212
+ }
213
+ Hashes::BcryptMcf => {
214
+ let cost = try_or_poisoned!(other.1.get("cost").and_then(value_as_int));
215
+ Bcrypt::new(cost)
216
+ }
217
+ Hashes::Hmac => {
218
+ let hash_id = try_or_poisoned!(other.1.get("h").and_then(Value::as_str));
219
+ let key_id = try_or_poisoned!(other.1.get("key_id").and_then(Value::as_str));
220
+ Hmac::with_key_id(hash_from_id(hash_id), key_id)
221
+ }
222
+ ref x @ Hashes::Pbkdf2Sha1 |
223
+ ref x @ Hashes::Pbkdf2Sha256 |
224
+ ref x @ Hashes::Pbkdf2Sha512 => {
225
+ let iterations = try_or_poisoned!(other.1.get("n").and_then(value_as_int));
226
+ match *x {
227
+ Hashes::Pbkdf2Sha1 => pbkdf2::Pbkdf2::new(iterations, &digest::SHA1),
228
+ Hashes::Pbkdf2Sha256 => pbkdf2::Pbkdf2::new(iterations, &digest::SHA256),
229
+ Hashes::Pbkdf2Sha512 => pbkdf2::Pbkdf2::new(iterations, &digest::SHA512),
230
+ _ => Poisoned.into() // not actually be possible due to previous matching,
231
+ }
232
+ }
233
+ Hashes::Scrypt => {
234
+ let log_n = try_or_poisoned!(other.1.get("ln").and_then(value_as_int));
235
+ let r = try_or_poisoned!(other.1.get("r").and_then(value_as_int));
236
+ let p = try_or_poisoned!(other.1.get("p").and_then(value_as_int));
237
+ Scrypt::new(log_n, r, p)
238
+ }
239
+ _ => Poisoned.into(),
240
+ }
241
+ }
242
+ }
243
+
244
+ fn value_as_int<T>(val: &Value) -> Option<T>
245
+ where T: num_traits::Num + FromPrimitive
246
+ {
247
+ match *val {
248
+ Value::Number(ref x) => {
249
+ if let Some(x) = x.as_u64() {
250
+ T::from_u64(x)
251
+ } else {
252
+ None
253
+ }
254
+ }
255
+ Value::String(ref s) => T::from_str_radix(s.as_str(), 10).ok(),
256
+ _ => None,
257
+ }
258
+ }
259
+
260
+ impl<'a> From<&'a Primitive> for (Hashes, Map<String, Value>) {
261
+ fn from(other: &Primitive) -> Self {
262
+ let mut map = Map::new();
263
+ for (key, value) in other.0.params_as_vec() {
264
+ let _ = map.insert(key.to_string(), Value::String(value));
265
+ }
266
+ (other.0.hash_id(), map)
267
+ }
268
+ }
269
+
270
+ fn hash_to_id(algorithm: &'static digest::Algorithm) -> String {
271
+ let mut name = String::new();
272
+ #[allow(use_debug)]
273
+ write!(&mut name, "{:?}", algorithm).expect("error writing to String");
274
+ name
275
+ }
276
+
277
+ fn hash_from_id(id: &str) -> &'static digest::Algorithm {
278
+ match id {
279
+ "SHA1" => &digest::SHA1,
280
+ "SHA256" => &digest::SHA256,
281
+ "SHA384" => &digest::SHA384,
282
+ "SHA512" => &digest::SHA512,
283
+ "SHA512_256" => &digest::SHA512_256,
284
+ _ => panic!("Unknown digest algorithm"),
285
+ }
286
+ }
287
+
288
+
289
+ #[cfg(test)]
290
+ mod test {
291
+ use super::*;
292
+
293
+ #[test]
294
+ fn test_comparisons() {
295
+ let bcrypt = Bcrypt::new(10);
296
+ let bcrypt_better = Bcrypt::new(20);
297
+
298
+ let scrypt = Scrypt::new(10, 8, 1);
299
+ let scrypt_better = Scrypt::new(14, 8, 1);
300
+ let scrypt_diff = Scrypt::new(15, 4, 1);
301
+
302
+ assert_eq!(bcrypt, bcrypt);
303
+ assert_eq!(scrypt, scrypt);
304
+
305
+ assert_eq!(bcrypt.partial_cmp(&bcrypt_better), Some(Ordering::Less));
306
+ assert!(scrypt < scrypt_better);
307
+
308
+ assert_eq!(scrypt.partial_cmp(&scrypt_diff), None);
309
+ assert_eq!(scrypt_better.partial_cmp(&scrypt_diff), None);
310
+ assert_eq!(scrypt.partial_cmp(&bcrypt), None);
311
+ }
312
+ }
@@ -0,0 +1,272 @@
1
+ /// Native Rust implementation of scrypt.
2
+ pub use self::fastpbkdf2::Pbkdf2;
3
+ pub use self::ring_pbkdf2::Pbkdf2 as RingPbkdf2;
4
+
5
+ /// Native Rust implementation of scrypt.
6
+ mod ring_pbkdf2 {
7
+ use primitives::{Primitive, PrimitiveImpl};
8
+ use sod::Sod;
9
+
10
+ use ring::{digest, pbkdf2};
11
+ use serde_mcf::Hashes;
12
+
13
+ use std::fmt;
14
+ use std::sync::Arc;
15
+
16
+ use super::super::hash_to_id;
17
+
18
+ /// Struct holding `PBKDF2` parameters.
19
+ ///
20
+ /// This implementation is backed by `ring`.
21
+ pub struct Pbkdf2 {
22
+ iterations: u32,
23
+ algorithm: &'static digest::Algorithm,
24
+ }
25
+
26
+
27
+ impl Pbkdf2 {
28
+ /// Create a new PBKDF2 instance using defaults.
29
+ pub fn default() -> Primitive {
30
+ Primitive(Sod::Dynamic(Arc::clone(&DEFAULT)))
31
+ }
32
+
33
+ /// Create a new PBKDF2 instance.
34
+ pub fn new(iterations: u32, algorithm: &'static digest::Algorithm) -> Primitive {
35
+ Self::new_impl(iterations, algorithm).into()
36
+ }
37
+
38
+ fn new_impl(iterations: u32, algorithm: &'static digest::Algorithm) -> Self {
39
+ Self {
40
+ iterations: iterations,
41
+ algorithm: algorithm,
42
+ }
43
+ }
44
+ }
45
+
46
+ lazy_static! {
47
+ static ref DEFAULT: Arc<Box<PrimitiveImpl>> = {
48
+ Arc::new(Box::new(Pbkdf2::new_impl(10_000, &digest::SHA256)))
49
+ };
50
+ }
51
+
52
+ impl ::primitives::PrimitiveImpl for Pbkdf2 {
53
+ /// Compute the scrypt hash
54
+ fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
55
+ let mut hash = vec![0_u8; 32];
56
+ pbkdf2::derive(self.algorithm, self.iterations, salt, password, &mut hash);
57
+ hash
58
+ }
59
+
60
+ /// Convert parameters into a vector of (key, value) tuples
61
+ /// for serializing.
62
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
63
+ vec![("n", self.iterations.to_string())]
64
+ }
65
+
66
+ fn hash_id(&self) -> Hashes {
67
+ match hash_to_id(self.algorithm).as_ref() {
68
+ "SHA1" => Hashes::Pbkdf2Sha1,
69
+ "SHA256" => Hashes::Pbkdf2Sha256,
70
+ "SHA512" => Hashes::Pbkdf2Sha512,
71
+ _ => panic!("unexpected digest algorithm"),
72
+ }
73
+ }
74
+ }
75
+
76
+ impl fmt::Debug for Pbkdf2 {
77
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
78
+ write!(f,
79
+ "PBKDF2-{:?}, iterations: {}",
80
+ self.algorithm,
81
+ self.iterations)
82
+ }
83
+ }
84
+ }
85
+
86
+
87
+ /// Native Rust implementation of scrypt.
88
+ mod fastpbkdf2 {
89
+ extern crate fastpbkdf2;
90
+ use self::fastpbkdf2::*;
91
+
92
+ use primitives::{Primitive, PrimitiveImpl};
93
+ use sod::Sod;
94
+
95
+ use ring::digest;
96
+ use serde_mcf::Hashes;
97
+
98
+ use std::fmt;
99
+ use std::sync::Arc;
100
+
101
+ use super::super::hash_to_id;
102
+
103
+ /// Struct holding `PBKDF2` parameters.
104
+ ///
105
+ /// This implementation is backed by `fastpbkdf2`.
106
+ pub struct Pbkdf2 {
107
+ iterations: u32,
108
+ algorithm: fn(&[u8], &[u8], u32, &mut [u8]),
109
+ alg_id: &'static str,
110
+ }
111
+
112
+ lazy_static! {
113
+ static ref DEFAULT: Arc<Box<PrimitiveImpl>> = {
114
+ Arc::new(Box::new(Pbkdf2::new_impl(10_000, &digest::SHA256)))
115
+ };
116
+ }
117
+
118
+ impl Pbkdf2 {
119
+ /// Create a new PBKDF2 instance using defaults.
120
+ pub fn default() -> Primitive {
121
+ Primitive(Sod::Dynamic(Arc::clone(&DEFAULT)))
122
+ }
123
+
124
+ /// Create a new PBKDF2 instance.
125
+ pub fn new(iterations: u32, algorithm: &'static digest::Algorithm) -> Primitive {
126
+ Self::new_impl(iterations, algorithm).into()
127
+ }
128
+
129
+ fn new_impl(iterations: u32, algorithm: &'static digest::Algorithm) -> Self {
130
+ match hash_to_id(algorithm).as_ref() {
131
+ "SHA1" => {
132
+ Self {
133
+ iterations: iterations,
134
+ algorithm: pbkdf2_hmac_sha1,
135
+ alg_id: "SHA1",
136
+ }
137
+ }
138
+ "SHA256" => {
139
+ Self {
140
+ iterations: iterations,
141
+ algorithm: pbkdf2_hmac_sha256,
142
+ alg_id: "SHA256",
143
+ }
144
+ }
145
+ "SHA512" => {
146
+ Self {
147
+ iterations: iterations,
148
+ algorithm: pbkdf2_hmac_sha512,
149
+ alg_id: "SHA512",
150
+ }
151
+ }
152
+ _ => panic!("unexpected digest algorithm"),
153
+ }
154
+ }
155
+ }
156
+
157
+ impl ::primitives::PrimitiveImpl for Pbkdf2 {
158
+ /// Compute the scrypt hash
159
+ fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
160
+ let mut hash = vec![0_u8; 32];
161
+ (self.algorithm)(password, salt, self.iterations, &mut hash);
162
+ hash
163
+ }
164
+
165
+ /// Convert parameters into a vector of (key, value) tuples
166
+ /// for serializing.
167
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
168
+ vec![("n", self.iterations.to_string())]
169
+ }
170
+
171
+ fn hash_id(&self) -> Hashes {
172
+ match self.alg_id {
173
+ "SHA1" => Hashes::Pbkdf2Sha1,
174
+ "SHA256" => Hashes::Pbkdf2Sha256,
175
+ "SHA512" => Hashes::Pbkdf2Sha512,
176
+ _ => panic!("unexpected digest algorithm"),
177
+ }
178
+ }
179
+ }
180
+
181
+ impl fmt::Debug for Pbkdf2 {
182
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
183
+ write!(f,
184
+ "PBKDF2-{:?}, iterations: {}",
185
+ self.alg_id,
186
+ self.iterations)
187
+ }
188
+ }
189
+ }
190
+
191
+
192
+ #[cfg(test)]
193
+ mod test {
194
+ use ::hashing::*;
195
+ use ring::digest;
196
+ use serde_mcf;
197
+
198
+ #[test]
199
+ fn sanity_check() {
200
+ let password = "hunter2";
201
+ let params = super::Pbkdf2::default();
202
+ println!("{:?}", params);
203
+ let salt = ::get_salt();
204
+ let hash = params.compute(password.as_bytes(), &salt);
205
+ let hash2 = params.compute(password.as_bytes(), &salt);
206
+ assert_eq!(hash, hash2);
207
+ let out = Output {
208
+ alg: Algorithm::Single(params.into()),
209
+ salt: salt,
210
+ hash: hash,
211
+ };
212
+ println!("{:?}", serde_mcf::to_string(&out).unwrap());
213
+ }
214
+
215
+ #[test]
216
+ fn sanity_check_ring() {
217
+ let password = "hunter2";
218
+ let params = super::RingPbkdf2::default();
219
+ println!("{:?}", params);
220
+ let salt = ::get_salt();
221
+ let hash = params.compute(password.as_bytes(), &salt);
222
+ let hash2 = params.compute(password.as_bytes(), &salt);
223
+ assert_eq!(hash, hash2);
224
+ let out = Output {
225
+ alg: Algorithm::Single(params.into()),
226
+ salt: salt,
227
+ hash: hash,
228
+ };
229
+ println!("{:?}", serde_mcf::to_string(&out).unwrap());
230
+ }
231
+
232
+ macro_rules! primitive_round_trip {
233
+ ($prim:expr) => (
234
+ let hash = serde_mcf::to_string(&$prim.hash(&"hunter2")).unwrap();
235
+ let _output: Output = serde_mcf::from_str(&hash).unwrap();
236
+ )
237
+ }
238
+
239
+ #[test]
240
+ fn pbkdf2_params() {
241
+ let params = Algorithm::Single(super::Pbkdf2::new(1_000, &digest::SHA1));
242
+ primitive_round_trip!(params);
243
+
244
+ let params = Algorithm::Single(super::Pbkdf2::new(1_000, &digest::SHA256));
245
+ primitive_round_trip!(params);
246
+
247
+ let params = Algorithm::Single(super::Pbkdf2::new(1_000, &digest::SHA512));
248
+ primitive_round_trip!(params);
249
+
250
+ let params = Algorithm::Single(super::RingPbkdf2::new(1_000, &digest::SHA1));
251
+ primitive_round_trip!(params);
252
+
253
+ let params = Algorithm::Single(super::RingPbkdf2::new(1_000, &digest::SHA256));
254
+ primitive_round_trip!(params);
255
+
256
+ let params = Algorithm::Single(super::RingPbkdf2::new(1_000, &digest::SHA512));
257
+ primitive_round_trip!(params);
258
+
259
+ }
260
+ }
261
+
262
+ #[cfg(features = "bench")]
263
+ mod ring_bench {
264
+ use super::*;
265
+ benches!(RingPbkdf2);
266
+ }
267
+
268
+ #[cfg(features = "bench")]
269
+ mod fast_bench {
270
+ use super::*;
271
+ benches!(Pbkdf2);
272
+ }