libpasta 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,180 @@
1
+ pub use self::native::Argon2;
2
+
3
+ mod native {
4
+ extern crate argon2rs;
5
+
6
+ use primitives::Primitive;
7
+ use sod::Sod;
8
+
9
+ use serde_mcf::Hashes;
10
+
11
+ use std::fmt;
12
+
13
+ /// Parameter set for Argon2.
14
+ ///
15
+ /// This implementation is backed by the `argon2rs` crate.
16
+ pub struct Argon2 {
17
+ algorithm: argon2rs::Argon2,
18
+ }
19
+
20
+ impl ::primitives::PrimitiveImpl for Argon2 {
21
+ fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
22
+ let mut hash = [0_u8; 32];
23
+ self.algorithm.hash(&mut hash, password, salt, &[], &[]);
24
+ hash.to_vec()
25
+ }
26
+
27
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
28
+ let (_, kib, passes, lanes) = self.algorithm.params();
29
+ vec![("m", kib.to_string()), ("t", passes.to_string()), ("p", lanes.to_string())]
30
+ }
31
+
32
+ fn hash_id(&self) -> Hashes {
33
+ Hashes::Argon2i
34
+ }
35
+ }
36
+
37
+ lazy_static! {
38
+ pub static ref DEFAULT: Argon2 = {
39
+ Argon2 {
40
+ algorithm: argon2rs::Argon2::default(argon2rs::Variant::Argon2i)
41
+ }
42
+ };
43
+ }
44
+
45
+ impl Argon2 {
46
+ /// Get the default Argon2i parameter set
47
+ pub fn default() -> Primitive {
48
+ Primitive(Sod::Static(&*DEFAULT))
49
+ }
50
+
51
+ fn new_impl(passes: u32, lanes: u32, kib: u32) -> Self {
52
+ Self {
53
+ algorithm: argon2rs::Argon2::new(passes, lanes, kib, argon2rs::Variant::Argon2i)
54
+ .expect("invalid Argon2 parameters"),
55
+ }
56
+ }
57
+
58
+ /// Creates a new Argon2i instance
59
+ pub fn new(passes: u32, lanes: u32, kib: u32) -> Primitive {
60
+ Self::new_impl(passes, lanes, kib).into()
61
+ }
62
+ }
63
+
64
+ impl fmt::Debug for Argon2 {
65
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
66
+ write!(f, "Argon2i: {:?}", self.algorithm.params())
67
+ }
68
+ }
69
+ }
70
+
71
+
72
+ benches!(Argon2);
73
+
74
+ #[cfg(test)]
75
+ mod test {
76
+ use data_encoding::HEXLOWER;
77
+ use serde_mcf;
78
+ use super::*;
79
+ use hashing::*;
80
+
81
+ #[test]
82
+ fn sanity_check() {
83
+ let password = "hunter2";
84
+ let params = super::Argon2::default();
85
+ println!("{:?}", params);
86
+ let salt = ::get_salt();
87
+ let hash = params.compute(password.as_bytes(), &salt);
88
+ let hash2 = params.compute(password.as_bytes(), &salt);
89
+ assert_eq!(hash, hash2);
90
+ let out = Output {
91
+ alg: Algorithm::Single(params.into()),
92
+ salt: salt,
93
+ hash: hash,
94
+ };
95
+ println!("{:?}", serde_mcf::to_string(&out).unwrap());
96
+ }
97
+
98
+ fn hashtest(passes: u32,
99
+ m: u32,
100
+ lanes: u32,
101
+ password: &str,
102
+ salt: &str,
103
+ hexpected: &str,
104
+ encoded: &str) {
105
+ let alg = Argon2::new(passes, lanes, 1 << m);
106
+ let hash = alg.compute(password.as_bytes(), salt.as_bytes());
107
+ assert_eq!(HEXLOWER.encode(&hash), hexpected);
108
+ assert_eq!(serde_mcf::from_str::<Output>(encoded).unwrap().hash, hash);
109
+ let output = Output {
110
+ alg: Algorithm::Single(alg.into()),
111
+ hash: hash,
112
+ salt: salt.as_bytes().to_vec(),
113
+ };
114
+ assert_eq!(&serde_mcf::to_string(&output).unwrap()[1..], encoded);
115
+ }
116
+
117
+ #[test]
118
+ fn argon2i_ref_tests() {
119
+ hashtest(2,
120
+ 8,
121
+ 1,
122
+ "password",
123
+ "somesalt",
124
+ "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06",
125
+ "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ\
126
+ $/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY");
127
+ hashtest(2,
128
+ 8,
129
+ 2,
130
+ "password",
131
+ "somesalt",
132
+ "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb",
133
+ "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ\
134
+ $tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs");
135
+ hashtest(1,
136
+ 16,
137
+ 1,
138
+ "password",
139
+ "somesalt",
140
+ "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2",
141
+ "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ\
142
+ $gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI");
143
+ hashtest(4,
144
+ 16,
145
+ 1,
146
+ "password",
147
+ "somesalt",
148
+ "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b",
149
+ "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ\
150
+ $8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs");
151
+ hashtest(2,
152
+ 16,
153
+ 1,
154
+ "differentpassword",
155
+ "somesalt",
156
+ "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3",
157
+ "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ\
158
+ $6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM");
159
+ hashtest(2,
160
+ 16,
161
+ 1,
162
+ "password",
163
+ "diffsalt",
164
+ "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497",
165
+ "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ\
166
+ $eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc");
167
+ }
168
+
169
+ #[test] #[cfg(feature = "long_tests")]
170
+ fn argon2i_ref_tests() {
171
+ hashtest(2,
172
+ 18,
173
+ 1,
174
+ "password",
175
+ "somesalt",
176
+ "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467",
177
+ "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ\
178
+ $Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc");
179
+ }
180
+ }
@@ -0,0 +1,165 @@
1
+ pub use self::native::Bcrypt;
2
+
3
+ mod native {
4
+ #![allow(shadow_reuse)]
5
+
6
+ extern crate crypto;
7
+ use self::crypto::bcrypt::bcrypt;
8
+
9
+ use primitives::{Primitive, PrimitiveImpl};
10
+ use sod::Sod;
11
+
12
+ use serde_mcf::Hashes;
13
+
14
+ use std::fmt;
15
+ use std::sync::Arc;
16
+
17
+ /// `bcrypt` parameter set.
18
+ ///
19
+ /// Holds the cost value.
20
+ /// This implementation is backed by `rust-crypto`.
21
+ #[derive(Clone, Deserialize, Serialize)]
22
+ pub struct Bcrypt {
23
+ cost: u32,
24
+ }
25
+
26
+ lazy_static! {
27
+ static ref DEFAULT: Arc<Box<PrimitiveImpl>> = {
28
+ Arc::new(Box::new(Bcrypt::new_impl(12)))
29
+ };
30
+ }
31
+
32
+ impl PrimitiveImpl for Bcrypt {
33
+ fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
34
+ let mut hash = [0_u8; 24];
35
+ let mut pw = [0_u8; 72];
36
+ // Bcrypt inputs need to be at most 72 bytes
37
+ // with a trailing zero byte only if < 72 bytes
38
+ let pw = if password.len() > 71 {
39
+ pw[..72].copy_from_slice(&password[..72]);
40
+ &pw[..]
41
+ } else {
42
+ pw[..password.len()].copy_from_slice(password);
43
+ &pw[..password.len() + 1]
44
+ };
45
+ bcrypt(self.cost, salt, pw, &mut hash);
46
+ hash[..23].to_vec()
47
+ }
48
+
49
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
50
+ vec![("cost", self.cost.to_string())]
51
+ }
52
+
53
+ fn hash_id(&self) -> Hashes {
54
+ Hashes::BcryptMcf
55
+ }
56
+ }
57
+
58
+
59
+ impl fmt::Debug for Bcrypt {
60
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
61
+ write!(f, "Bcrypt, cost: {:?}", self.cost)
62
+ }
63
+ }
64
+
65
+ impl Bcrypt {
66
+ /// Construct a new `Bcrypt` parameter set.
67
+ pub fn new(cost: u32) -> Primitive {
68
+ Self::new_impl(cost).into()
69
+ }
70
+
71
+ fn new_impl(cost: u32) -> Self {
72
+ Self { cost: cost }
73
+ }
74
+
75
+ /// Get the default `Bcrypt` parameter set.
76
+ pub fn default() -> Primitive {
77
+ Primitive(Sod::Dynamic(Arc::clone(&DEFAULT)))
78
+ }
79
+ }
80
+ }
81
+
82
+ benches!(Bcrypt);
83
+
84
+ #[cfg(test)]
85
+ mod bcrypt_test {
86
+ use hashing::*;
87
+ use serde_mcf as mcf;
88
+
89
+ #[test]
90
+ fn sanity_check() {
91
+ let password = "hunter2";
92
+ let params = super::Bcrypt::default();
93
+ println!("{:?}", params);
94
+ let salt = ::get_salt();
95
+ let hash = params.compute(password.as_bytes(), &salt);
96
+ let hash2 = params.compute(password.as_bytes(), &salt);
97
+ assert_eq!(hash, hash2);
98
+ let out = Output {
99
+ alg: Algorithm::Single(params.into()),
100
+ salt: salt,
101
+ hash: hash,
102
+ };
103
+ println!("{:?}", mcf::to_string(&out).unwrap());
104
+ }
105
+
106
+ #[test]
107
+ fn verifies_bcrypt_hashes() {
108
+ let password = "hunter2";
109
+ let hash = "$2a$10$ckjEeyTD6estWyoofn4EROM9Ik2PqVcfcrepX.uGp6.aqRdCMN/Oe";
110
+ assert!(::verify_password(&hash, password));
111
+ }
112
+
113
+ fn openwall_test(hash: &str, password: &[u8]) {
114
+ let pwd_hash: Output = mcf::from_str(&hash).unwrap();
115
+ assert_eq!(pwd_hash.hash,
116
+ pwd_hash.alg.hash_with_salt(password, &pwd_hash.salt));
117
+ }
118
+
119
+ // Test the internal Bcrypt implementation against the openwall test vectors.
120
+ // Note that we currently are non compatible with "2x" variant hashes.
121
+ #[test]
122
+ fn openwall_test_vectors() {
123
+ openwall_test("$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
124
+ b"U*U");
125
+ openwall_test("$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
126
+ b"U*U*");
127
+ openwall_test("$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
128
+ b"U*U*U");
129
+ openwall_test("$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
130
+ b"");
131
+ openwall_test("$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
132
+ b"0123456789abcdefghijklmnopqrstuvwxyz\
133
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\
134
+ chars after 72 are ignored");
135
+ // openwall_test("$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", b"\xa3");
136
+ openwall_test("$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
137
+ b"\xa3");
138
+ // openwall_test("$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS", b"\xd1\x91");
139
+ // openwall_test("$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS", b"\xd0\xc1\xd2\xcf\xcc\xd8");
140
+ openwall_test("$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
141
+ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
142
+ \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
143
+ \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
144
+ \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
145
+ \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
146
+ \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
147
+ chars after 72 are ignored as usual");
148
+ openwall_test("$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
149
+ b"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
150
+ \xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
151
+ \xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
152
+ \xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
153
+ \xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
154
+ \xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55");
155
+ openwall_test("$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
156
+ b"");
157
+ openwall_test("$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
158
+ b"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
159
+ \x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
160
+ \x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
161
+ \x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
162
+ \x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
163
+ \x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff");
164
+ }
165
+ }
@@ -0,0 +1,134 @@
1
+ pub use self::hmac_ring::Hmac;
2
+
3
+ mod hmac_ring {
4
+ use config;
5
+ use errors::*;
6
+ use key;
7
+ use key::Store;
8
+ use primitives::Primitive;
9
+
10
+ use ring::{digest, hkdf, hmac, rand};
11
+ use serde_mcf::Hashes;
12
+
13
+ use std::fmt;
14
+
15
+ /// Password storage strengthening using HMAC.
16
+ ///
17
+ /// This struct holds the parameters used.
18
+ /// Represents the `ring` implementation.
19
+ pub struct Hmac {
20
+ h: &'static digest::Algorithm,
21
+ key: Option<hmac::SigningKey>,
22
+ key_id: String,
23
+ }
24
+
25
+ impl Hmac {
26
+ /// Construct a new `Hmac` instance with a specified key identifier
27
+ pub fn with_key_id(h: &'static digest::Algorithm, key_id: &str) -> Primitive {
28
+ Self {
29
+ h: h,
30
+ key: key::get_global().get_key(key_id).map(|k| hmac::SigningKey::new(h, &k)),
31
+ key_id: key_id.to_string(),
32
+ }.into()
33
+ }
34
+
35
+ /// Gets a default HMAC instance, generating a fresh new key.
36
+ pub fn default() -> Primitive {
37
+ Self::new().into()
38
+ }
39
+
40
+ fn new() -> Self {
41
+ let rng = rand::SystemRandom::new();
42
+ let mut key_bytes = [0_u8; 32];
43
+ let key = hmac::SigningKey::generate_serializable(&digest::SHA256, &rng, &mut key_bytes)
44
+ .expect("could not generate random bytes for key");
45
+ let key_id = key::get_global().insert(&key_bytes);
46
+ Self {
47
+ h: &digest::SHA256,
48
+ key: Some(key),
49
+ key_id: key_id,
50
+ }
51
+ }
52
+ }
53
+
54
+ impl ::primitives::PrimitiveImpl for Hmac {
55
+ /// Compute the scrypt hash
56
+ fn compute(&self, password: &[u8], _salt: &[u8]) -> Vec<u8> {
57
+ let mut hash = vec![0_u8; 32];
58
+ let key = self.key.as_ref().expect_report("key not found");
59
+ hkdf::extract_and_expand(key, password, b"libpasta password hashing", &mut hash);
60
+ hash
61
+ }
62
+
63
+ /// Convert parameters into a vector of (key, value) tuples
64
+ /// for serializing.
65
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
66
+ vec![("key_id", self.key_id.clone()),
67
+ ("h", super::super::hash_to_id(self.h))]
68
+ }
69
+
70
+ fn hash_id(&self) -> Hashes {
71
+ Hashes::Hmac
72
+ }
73
+
74
+ fn update_key(&self, config: &config::Config) -> Option<Primitive> {
75
+ Some(Self {
76
+ h: self.h,
77
+ key: config.get_key(&self.key_id).map(|k| hmac::SigningKey::new(self.h, &k)),
78
+ key_id: self.key_id.clone(),
79
+ }.into())
80
+ }
81
+ }
82
+
83
+ impl fmt::Debug for Hmac {
84
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85
+ write!(f,
86
+ "Hmac, KeyID: {}, Hash: {}",
87
+ self.key_id,
88
+ super::super::hash_to_id(self.h))
89
+ }
90
+ }
91
+ }
92
+
93
+
94
+ #[cfg(test)]
95
+ mod test {
96
+ use ::hashing::*;
97
+ use serde_mcf;
98
+
99
+ #[test]
100
+ fn sanity_check() {
101
+ let password = "hunter2";
102
+ let hmac_params = super::Hmac::default();
103
+ println!("{:?}", hmac_params);
104
+ let inner_params = ::primitives::scrypt::Scrypt::default();
105
+ let salt = ::get_salt();
106
+ let hash = hmac_params.compute(&inner_params.compute(password.as_bytes(), &salt), &salt);
107
+ let hash2 = hmac_params.compute(&inner_params.compute(password.as_bytes(), &salt), &salt);
108
+ let params = Algorithm::Nested {
109
+ outer: hmac_params.into(),
110
+ inner: Box::new(Algorithm::Single(inner_params.into())),
111
+ };
112
+ assert_eq!(hash, hash2);
113
+ let out = Output {
114
+ alg: params,
115
+ salt: salt,
116
+ hash: hash,
117
+ };
118
+ println!("{:?}", serde_mcf::to_string(&out).unwrap());
119
+ }
120
+
121
+ #[test]
122
+ fn hash_verify_works() {
123
+ let password = "hunter2";
124
+ let algorithm = Algorithm::Nested {
125
+ outer: super::Hmac::default().into(),
126
+ inner: Box::new(Algorithm::Single(::primitives::Scrypt::default())),
127
+ };
128
+ let hash = algorithm.hash(&password);
129
+ assert!(hash.verify(&password));
130
+ }
131
+
132
+ }
133
+
134
+ benches!(Hmac);