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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Sam Scott
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,27 @@
1
+ VERSION = 0.0.5
2
+
3
+ all: libpasta.so libpasta.a
4
+
5
+ clean:
6
+ rm -rf build/
7
+
8
+ force:
9
+ cargo clean --manifest-path libpasta-capi/Cargo.toml
10
+ make clean
11
+ make default
12
+
13
+ libpasta: Cargo.toml libpasta-capi/Cargo.toml
14
+ cargo build --release --manifest-path libpasta-capi/Cargo.toml
15
+
16
+ libpasta.%: libpasta
17
+ mkdir -p build
18
+ cp libpasta-capi/target/release/$@ build/$@
19
+
20
+ install: libpasta.so
21
+ sudo install -D -m0755 build/libpasta.so /usr/lib/libpasta.so.${VERSION}
22
+ sudo ln -sf /usr/lib/libpasta.so.${VERSION} /usr/lib/libpasta.so
23
+
24
+ uninstall:
25
+ sudo rm /usr/lib/libpasta.so.$(VERSION)
26
+
27
+ .PHONY: clean uninstall
@@ -0,0 +1,78 @@
1
+ libpasta - Password Storage Algorithms
2
+ ===================================
3
+
4
+ [![Build Status][build_badge]][build_status]
5
+ [![Code Coverage][coverage_badge]][coverage_report]
6
+
7
+ #### _Making Password Painless_
8
+
9
+ This library aims to be a all-in-one solution for password storage. In
10
+ particular, we aim to provide:
11
+
12
+ - Easy-to-use password storage with sane defaults.
13
+ - Tools to provide parameter tuning for different use cases.
14
+ - Automatic migration of password hashes to new algorithms.
15
+
16
+
17
+ ## Introduction
18
+
19
+ libpasta is designed to be as simple to use as possible. Most users would rather
20
+ not have to choose which password algorithm to use, nor understand what
21
+ are the best parameter choices.
22
+
23
+ Therefore, we take great care to make this all opaque to the user:
24
+
25
+ ```rust
26
+ let password = "hunter2".owned();
27
+ let hash = hash_password(password);
28
+ // store hash in database
29
+ // ... time passes, user returns ...
30
+ let password = "hunter2".owned();
31
+ if verify_password(password, &hash) {
32
+ // do something
33
+ }
34
+ ```
35
+
36
+ ## Installation
37
+
38
+ To build the `libpasta` system library, simply run `make`. This outputs
39
+ a `build/libpasta.so` file (or system-appropriate filename).
40
+
41
+ You can also try running `make install` to automatically move it to the correct
42
+ location.
43
+
44
+ The library is generated as a result of building [libpasta-capi](libpasta-capi/),
45
+ which is a C-API wrapper built around the Rust code.
46
+
47
+ ### The rest of this README is dedicated to developing the code. For more about the library, and examples, please see: https://libpasta.github.io/ or the [documentation](https://docs.rs/libpasta/).
48
+
49
+ ## Roadmap
50
+
51
+ libpasta is still currently in development. The current version is `0.0.1`
52
+ representing a pre-release. After gathering some initial feedback we will
53
+ move to `0.1.0` release, at which point libpasta will be ready to use in
54
+ test environments. We are targetting a stable `1.0.0` release once the API
55
+ is stable, and testing reveals no major issues.
56
+
57
+ ## Contributing
58
+
59
+ libpasta is still in its infancy, and the best way to contribute right now is
60
+ to start testing it in new projects.
61
+
62
+ Please feel free to open new issues or pull requests for any bugs found, feature
63
+ requests, or general suggestions.
64
+
65
+ We very much welcome any contributions, and simply ask for patience and civility
66
+ when dealing with any disagreements or problems.
67
+
68
+ ## License
69
+
70
+ libpasta is licensed under the MIT license: [License](license).
71
+
72
+
73
+ [build_badge]: https://travis-ci.org/libpasta/libpasta.svg?branch=master
74
+ [build_status]: https://travis-ci.org/libpasta/libpasta
75
+ [coverage_badge]: https://codecov.io/gh/libpasta/libpasta/graph/badge.svg
76
+ [coverage_report]: https://codecov.io/gh/libpasta/libpasta/
77
+ [documentation]: https://libpasta.github.io/doc/libpasta/
78
+ [license]: LICENSE.md
@@ -0,0 +1,125 @@
1
+ #![feature(test)]
2
+
3
+ extern crate argon2rs;
4
+ extern crate cargon;
5
+ extern crate libpasta;
6
+ extern crate serde_mcf;
7
+ extern crate test;
8
+ extern crate time;
9
+ use test::Bencher;
10
+
11
+
12
+ use libpasta::primitives::{Argon2, Scrypt, Primitive};
13
+ use libpasta::hashing::Algorithm;
14
+
15
+ #[bench]
16
+ fn empty(b: &mut Bencher) {
17
+ b.iter(|| 1)
18
+ }
19
+
20
+ use std::fs::File;
21
+
22
+ #[bench]
23
+ fn raw_argon2(_b: &mut Bencher) {
24
+ let _f1 = File::create("native.txt").unwrap();
25
+ let _f2 = File::create("ffi.txt").unwrap();
26
+ let reps = 10;
27
+ let password = [0; 16];
28
+ let salt = [1; 16];
29
+ let t_cost = 3;
30
+ let thread_test = [1, 2, 4, 8];
31
+ let mut out = [0u8; 32];
32
+ let mut m_cost = 1 << 10;
33
+ while m_cost <= 1 << 22 {
34
+ for threads in &thread_test {
35
+ let alg = argon2rs::Argon2::new(t_cost, *threads, m_cost, argon2rs::Variant::Argon2i)
36
+ .unwrap();
37
+ let mut alg_ffi = mk_cargon(&alg, &mut out, &password, &salt, &[], &[]);
38
+ let prim: Primitive = Argon2::new(t_cost, *threads, m_cost);
39
+ let pastalg = Algorithm::Single(prim);
40
+
41
+ let start = time::precise_time_ns();
42
+ for _ in 0..reps {
43
+ alg.hash(&mut out, &password, &salt, &[], &[]);
44
+ }
45
+ let end = time::precise_time_ns();
46
+ let native = (end - start) as f64;
47
+
48
+ let start = time::precise_time_ns();
49
+ for _ in 0..reps {
50
+ unsafe {
51
+ cargon::argon2_ctx(&mut alg_ffi, argon2rs::Variant::Argon2i as usize);
52
+ }
53
+ }
54
+ let end = time::precise_time_ns();
55
+ let ffi = (end - start) as f64;
56
+
57
+ let start = time::precise_time_ns();
58
+ for _ in 0..reps {
59
+ let _ = serde_mcf::to_string(&pastalg.hash("hunter2"));
60
+ }
61
+ let end = time::precise_time_ns();
62
+ let libp = (end - start) as f64;
63
+
64
+ println!("{} {} iterations {} MiB {} threads ... {} reps",
65
+ "Argon2i",
66
+ t_cost,
67
+ m_cost / 1024,
68
+ threads,
69
+ reps);
70
+ println!("Native: {:.4} seconds", native / 1_000_000_000f64);
71
+ println!("libpasta: {:.4} seconds", libp / 1_000_000_000f64);
72
+ println!("FFI: {:.4} seconds\n", ffi / 1_000_000_000f64);
73
+ }
74
+ m_cost <<= 1;
75
+
76
+ }
77
+ }
78
+
79
+
80
+ #[bench]
81
+ fn pasta_hash_static(b: &mut Bencher) {
82
+ let password = "hunter2";
83
+ b.iter(|| libpasta::hash_password(password))
84
+ }
85
+
86
+ #[bench]
87
+ fn pasta_hash_dyn(b: &mut Bencher) {
88
+ let password = "hunter2";
89
+ let alg = Algorithm::Single(Scrypt::new(14, 8, 1));
90
+ b.iter(|| {
91
+ alg.hash(password)
92
+ })
93
+ }
94
+
95
+ use std::ptr;
96
+ fn mk_cargon(a2: &argon2rs::Argon2,
97
+ out: &mut [u8],
98
+ p: &[u8],
99
+ s: &[u8],
100
+ k: &[u8],
101
+ x: &[u8])
102
+ -> cargon::CargonContext {
103
+ let (_, kib, passes, lanes) = a2.params();
104
+ cargon::CargonContext {
105
+ out: out.as_mut_ptr(),
106
+ outlen: out.len() as u32,
107
+ pwd: p.as_ptr(),
108
+ pwdlen: p.len() as u32,
109
+ salt: s.as_ptr(),
110
+ saltlen: s.len() as u32,
111
+ secret: k.as_ptr(),
112
+ secretlen: k.len() as u32,
113
+ ad: x.as_ptr(),
114
+ adlen: x.len() as u32,
115
+
116
+ t_cost: passes,
117
+ m_cost: kib,
118
+ lanes: lanes,
119
+ threads: lanes,
120
+ version: 0x13,
121
+ allocate_fptr: ptr::null(),
122
+ deallocate_fptr: ptr::null(),
123
+ flags: cargon::ARGON2_FLAG_CLEAR_MEMORY,
124
+ }
125
+ }
@@ -0,0 +1,33 @@
1
+ extern crate libpasta;
2
+ extern crate ring;
3
+
4
+ use libpasta::key;
5
+ use ring::digest;
6
+
7
+ #[derive(Debug)]
8
+ struct StaticSource(&'static [u8; 16]);
9
+ static STATIC_SOURCE: StaticSource = StaticSource(b"ThisIsAStaticKey");
10
+
11
+ impl key::Store for StaticSource {
12
+ /// Insert a new key into the `Store`.
13
+ fn insert(&self, _key: &[u8]) -> String {
14
+ "StaticKey".to_string()
15
+ }
16
+
17
+ /// Get a key from the `Store`.
18
+ fn get_key(&self, _id: &str) -> Option<Vec<u8>> {
19
+ Some(self.0.to_vec())
20
+ }
21
+ }
22
+
23
+ fn main() {
24
+ let mut config = libpasta::Config::default();
25
+ config.set_key_source(&STATIC_SOURCE);
26
+
27
+ // Construct an HMAC instance and use this as the outer configuration
28
+ let keyed_function = libpasta::primitives::Hmac::with_key_id(&digest::SHA256, "StaticKey");
29
+ config.set_keyed_hash(keyed_function);
30
+
31
+ let hash = config.hash_password("hunter2");
32
+ println!("Computed hash: {:?}", hash);
33
+ }
@@ -0,0 +1,10 @@
1
+ extern crate libpasta;
2
+
3
+ use libpasta::primitives::Bcrypt;
4
+
5
+ fn main() {
6
+ let config = libpasta::Config::with_primitive(Bcrypt::new(15));
7
+ let password_hash = config.hash_password("hunter2");
8
+ println!("The hashed password is: '{}'", password_hash);
9
+ // Prints bcrypt hash
10
+ }
@@ -0,0 +1,25 @@
1
+ extern crate libpasta;
2
+ extern crate ring;
3
+
4
+ use ring::digest;
5
+
6
+ fn main() {
7
+ // Use scrypt as the default inner hash
8
+ let hash_primitive = libpasta::primitives::Scrypt::default();
9
+ let mut config = libpasta::Config::with_primitive(hash_primitive);
10
+
11
+ // Some proper way of getting a key
12
+ let key = b"yellow submarine";
13
+ let key_id = config.add_key(key);
14
+ // Construct an HMAC instance and use this as the outer configuration
15
+ let keyed_function = libpasta::primitives::Hmac::with_key_id(&digest::SHA256, &key_id);
16
+ config.set_keyed_hash(keyed_function);
17
+
18
+ let hash = config.hash_password("hunter2");
19
+ println!("Computed hash: {:?}", hash);
20
+ // Outputs:
21
+ // Computed hash: "$!$hmac$key_id=LNMhDy...,h=SHA256$$scrypt$ln=14,r=8,p=1$ZJ5EY...$grlNA...."
22
+
23
+ assert!(hash.starts_with("$!$hmac"));
24
+ assert!(hash.contains("scrypt"));
25
+ }
@@ -0,0 +1,10 @@
1
+ extern crate libpasta;
2
+
3
+ // We re-export the rpassword crate for CLI password input.
4
+ use libpasta::rpassword::*;
5
+
6
+ fn main() {
7
+ let password = prompt_password_stdout("Please enter your password:").unwrap();
8
+ let password_hash = libpasta::hash_password(&password);
9
+ println!("The hashed password is: '{}'", password_hash);
10
+ }
@@ -0,0 +1,47 @@
1
+ extern crate libpasta;
2
+ use libpasta::rpassword::*;
3
+
4
+ #[derive(Debug)]
5
+ struct User {
6
+ // ...
7
+ password_hash: String,
8
+ }
9
+
10
+ fn migrate_users(users: &mut [User]) {
11
+ // Step 1: Wrap old hash
12
+ for user in users {
13
+ libpasta::migrate_hash(&mut user.password_hash);
14
+ }
15
+ }
16
+
17
+ fn auth_user(user: &mut User) {
18
+ // Step 2: Update algorithm during log in
19
+ let password = prompt_password_stdout("Enter password:").unwrap();
20
+ if libpasta::verify_password_update_hash(&mut user.password_hash, &password) {
21
+ println!("Password correct, new hash: \n{}", user.password_hash);
22
+ } else {
23
+ println!("Password incorrect, hash unchanged: \n{}",
24
+ user.password_hash);
25
+ }
26
+ }
27
+
28
+ fn main() {
29
+ let mut users = vec![User { password_hash: deprected_hash("hunter2") },
30
+ User { password_hash: deprected_hash("hunter3") },
31
+ User { password_hash: deprected_hash("letmein") },
32
+ User { password_hash: deprected_hash("password") }];
33
+
34
+ migrate_users(&mut users);
35
+ println!("Passwords migrated: {:?}", users);
36
+ auth_user(&mut users[0]);
37
+ }
38
+
39
+ // Do not use this code as a good example of how to do hashing.
40
+ // This is intentionally awkward
41
+ use libpasta::{hashing, primitives};
42
+ extern crate serde_mcf;
43
+
44
+ fn deprected_hash(password: &str) -> String {
45
+ let alg = hashing::Algorithm::Single(primitives::Bcrypt::default());
46
+ serde_mcf::to_string(&alg.hash(password)).unwrap()
47
+ }
@@ -0,0 +1,24 @@
1
+ extern crate libpasta;
2
+ use libpasta::rpassword::*;
3
+
4
+ struct User {
5
+ // ...
6
+ password_hash: String,
7
+ }
8
+
9
+ fn auth_user(user: &User) {
10
+ let password = prompt_password_stdout("Enter password:").unwrap();
11
+ if libpasta::verify_password(&user.password_hash, &password) {
12
+ println!("The password is correct!");
13
+ // ~> Handle correct password
14
+ } else {
15
+ println!("Incorrect password.");
16
+ // ~> Handle incorrect password
17
+ }
18
+ }
19
+
20
+
21
+ fn main() {
22
+ let user = User { password_hash: libpasta::hash_password("hunter2") };
23
+ auth_user(&user);
24
+ }
@@ -0,0 +1,12 @@
1
+ [package]
2
+ name = "pasta"
3
+ version = "0.0.5"
4
+ authors = ["Sam Scott <sam.scott89@gmail.com>"]
5
+
6
+ [dependencies]
7
+ libc = "0.2"
8
+ libpasta = { version = "0.0.5", path = ".." }
9
+ rpassword = "2.0"
10
+
11
+ [lib]
12
+ crate-type = ["cdylib", "staticlib"]
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ set -ex
4
+
5
+ cargo build --manifest-path ../Cargo.toml
6
+ gcc -DDEBUG -o test test.c -ansi -Wall -I../include -L../target/debug -lpasta
@@ -0,0 +1,12 @@
1
+ #include <assert.h>
2
+ #include <stdio.h>
3
+ #include "pasta.h"
4
+
5
+ int main(void) {
6
+ char *hash;
7
+ hash = hash_password("hello123");
8
+ assert (verify_password(hash, "hello123"));
9
+ printf("\x1b[1;32mC test passed\x1b[m\n");
10
+ free_string(hash);
11
+ return 0;
12
+ }