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,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);