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,144 @@
1
+ /// Native Rust implementation of scrypt.
2
+ pub use self::native::Scrypt;
3
+
4
+ /// Native Rust implementation of scrypt.
5
+ mod native {
6
+ #![allow(cast_possible_truncation)]
7
+
8
+ use primitives::Primitive;
9
+ use sod::Sod;
10
+
11
+ use ring_pwhash::scrypt;
12
+ use serde_mcf::Hashes;
13
+
14
+ use std::fmt;
15
+
16
+ /// Struct holding `scrypt` parameters.
17
+ ///
18
+ /// This implementation is backed by `ring_pwhash`.
19
+ pub struct Scrypt {
20
+ log_n: u8,
21
+ r: u32,
22
+ p: u32,
23
+ /// Parameters used internally by `ring_pwhash`.
24
+ params: scrypt::ScryptParams,
25
+ }
26
+
27
+ lazy_static! {
28
+ static ref DEFAULT: Scrypt = {
29
+ Scrypt::new_impl(14, 8, 1)
30
+ };
31
+ }
32
+
33
+ impl ::primitives::PrimitiveImpl for Scrypt {
34
+ /// Compute the scrypt hash
35
+ fn compute<'a>(&'a self, password: &[u8], salt: &[u8]) -> Vec<u8> {
36
+ let mut hash = [0_u8; 32];
37
+ scrypt::scrypt(password, salt, &self.params, &mut hash);
38
+ hash[..32].to_vec()
39
+ }
40
+
41
+ /// Convert parameters into a vector of (key, value) tuples
42
+ /// for serializing.
43
+ fn params_as_vec(&self) -> Vec<(&'static str, String)> {
44
+ vec![("ln", self.log_n.to_string()), ("r", self.r.to_string()), ("p", self.p.to_string())]
45
+ }
46
+
47
+ fn hash_id(&self) -> Hashes {
48
+ Hashes::Scrypt
49
+ }
50
+ }
51
+
52
+ impl fmt::Debug for Scrypt {
53
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
54
+ write!(f,
55
+ "Scrypt, N: {}, r: {}, p: {}",
56
+ 1 << self.log_n,
57
+ self.r,
58
+ self.p)
59
+ }
60
+ }
61
+
62
+ impl Scrypt {
63
+ /// Gets the default scrypt instance.
64
+ pub fn default() -> Primitive {
65
+ Primitive(Sod::Static(&*DEFAULT))
66
+ }
67
+
68
+ fn new_impl(log_n: u8, r: u32, p: u32) -> Self {
69
+ Self {
70
+ log_n, r, p,
71
+ params: scrypt::ScryptParams::new(log_n, r, p),
72
+ }
73
+ }
74
+
75
+ /// Create a new scrypt instance.
76
+ pub fn new(log_n: u8, r: u32, p: u32) -> Primitive {
77
+ Self::new_impl(log_n, r, p).into()
78
+ }
79
+ }
80
+
81
+ }
82
+
83
+
84
+ #[cfg(test)]
85
+ mod test {
86
+ use data_encoding;
87
+ use ::hashing::*;
88
+ use serde_mcf;
89
+ #[test]
90
+ fn sanity_check() {
91
+ let password = "hunter2";
92
+ let params = super::Scrypt::default();
93
+ let salt = ::get_salt();
94
+ let hash = params.compute(password.as_bytes(), &salt);
95
+ let hash2 = params.compute(password.as_bytes(), &salt);
96
+ assert_eq!(hash, hash2);
97
+ let out = Output {
98
+ alg: Algorithm::Single(params.into()),
99
+ salt: salt,
100
+ hash: hash,
101
+ };
102
+ println!("{:?}", serde_mcf::to_string(&out).unwrap());
103
+ }
104
+
105
+ fn scrypt_test(password: &str, salt: &str, n: u32, r: u32, p: u32, _output_len: u32, expected: &str) {
106
+ let scrypt = super::Scrypt::new(f32::log2(n as f32) as u8, r, p);
107
+ let hash = scrypt.compute(password.as_bytes(), salt.as_bytes());
108
+ let expected = expected.replace(" ", "");
109
+ println!("{}", expected);
110
+ let expected = data_encoding::HEXLOWER.decode(expected.as_bytes()).unwrap();
111
+ assert_eq!(&expected[..32], &hash[..]);
112
+ }
113
+
114
+ #[test]
115
+ fn scrypt_test_vectors() {
116
+ scrypt_test("", "", 16, 1, 1, 64, "\
117
+ 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97\
118
+ f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42\
119
+ fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17\
120
+ e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06");
121
+
122
+ scrypt_test("password", "NaCl", 1024, 8, 16, 64, "\
123
+ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe\
124
+ 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62\
125
+ 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da\
126
+ c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40");
127
+ }
128
+
129
+ #[test] #[cfg(feature = "long_tests")]
130
+ fn scrypt_test_vectors_long() {
131
+ scrypt_test("pleaseletmein", "SodiumChloride", 16384, 8, 1, 64,"\
132
+ 70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb\
133
+ fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2\
134
+ d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9\
135
+ e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87");
136
+ scrypt_test("pleaseletmein", "SodiumChloride", 1048576, 8, 1, 64,"\
137
+ 21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81\
138
+ ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47\
139
+ 8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3\
140
+ 37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4");
141
+ }
142
+ }
143
+
144
+ benches!(Scrypt);
@@ -0,0 +1,46 @@
1
+ /// Sod stands for Static or Dynamic. An enum to encapsulate values which
2
+ /// are either dynamically, heap-allocated values, or statics.
3
+ ///
4
+ /// This allows us to define default primitives which are used throughout
5
+ /// without the overhead of reference counting, while still supporting the
6
+ /// flexibility to create primitives dynamically.
7
+ ///
8
+ /// Thanks to the `Deref` implementation, either variants are treated like
9
+ /// the inner type without needing to worry about which it is.
10
+ ///
11
+ /// Many thanks to [panicbit](https://github.com/panicbit) for helping to
12
+ /// get the `Deref` implementation working to make all the magic happen.
13
+
14
+ use std::ops::Deref;
15
+ use std::sync::Arc;
16
+
17
+ #[derive(Debug, PartialEq, PartialOrd)]
18
+ /// Enum to hold either static references or reference-counted owned objects.
19
+ /// Implements `Deref` to `T` for ease of use.
20
+ /// Since internal data is either a static reference, or an `Arc`, cloning
21
+ /// is a cheap operation.
22
+ pub enum Sod<T: ?Sized + 'static> {
23
+ /// Static reference to T
24
+ Static(&'static T),
25
+ /// Dynamically allocated T, on the heap, atomically reference-counted.
26
+ Dynamic(Arc<Box<T>>),
27
+ }
28
+
29
+ impl<T: ?Sized> Deref for Sod<T> {
30
+ type Target = T;
31
+ fn deref(&self) -> &T {
32
+ match *self {
33
+ Sod::Static(t) => t,
34
+ Sod::Dynamic(ref t) => t,
35
+ }
36
+ }
37
+ }
38
+
39
+ impl<T: ?Sized> Clone for Sod<T> {
40
+ fn clone(&self) -> Self {
41
+ match *self {
42
+ Sod::Static(t) => Sod::Static(t),
43
+ Sod::Dynamic(ref t) => Sod::Dynamic(Arc::clone(t)),
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,8 @@
1
+ default: Custom
2
+ keyed: ~
3
+ primitive:
4
+ id: "scrypt"
5
+ params:
6
+ ln: 11
7
+ r: 8
8
+ p: 1
@@ -0,0 +1,37 @@
1
+ #![allow(dead_code, unused_macros)]
2
+
3
+ extern crate env_logger;
4
+
5
+ use std::path::PathBuf;
6
+
7
+ macro_rules! config_test {
8
+ ($name:ident, $prefix:expr) => (
9
+ #[macro_use]
10
+ extern crate log;
11
+
12
+ #[test]
13
+ fn test_prim() {
14
+ common::init_test();
15
+
16
+ let password = "hunter2";
17
+ let config = libpasta::Config::with_primitive($name::default());
18
+ trace!("config setup as: {}", config.to_string());
19
+ let password_hash = config.hash_password(password);
20
+ assert!(password_hash.starts_with($prefix));
21
+ assert!(libpasta::verify_password(&password_hash, password));
22
+ }
23
+
24
+ )
25
+ }
26
+
27
+ pub fn get_test_path(filename: &str) -> PathBuf {
28
+ let mut path = PathBuf::from(file!());
29
+ path.pop();
30
+ path.pop();
31
+ path.push(filename);
32
+ path
33
+ }
34
+
35
+ pub fn init_test() {
36
+ self::env_logger::init().unwrap();
37
+ }
@@ -0,0 +1,8 @@
1
+ extern crate libpasta;
2
+
3
+ #[macro_use]
4
+ mod common;
5
+
6
+ use libpasta::primitives::Argon2;
7
+
8
+ config_test!(Argon2, "$$argon2");
@@ -0,0 +1,8 @@
1
+ extern crate libpasta;
2
+
3
+ #[macro_use]
4
+ mod common;
5
+
6
+ use libpasta::primitives::Bcrypt;
7
+
8
+ config_test!(Bcrypt, "$$2y");
@@ -0,0 +1,13 @@
1
+ extern crate libpasta;
2
+
3
+ use libpasta::config;
4
+
5
+ mod common;
6
+
7
+ #[test]
8
+ pub fn test_config_file() {
9
+ common::init_test();
10
+ let config = config::Config::from_file(common::get_test_path(".libpasta.yaml")).unwrap();
11
+ println!("{}", config.to_string());
12
+ assert!(config.to_string().contains("ln: \"11\""));
13
+ }
@@ -0,0 +1,26 @@
1
+ extern crate libpasta;
2
+ extern crate ring;
3
+
4
+ use ring::digest;
5
+
6
+ #[test]
7
+ fn test_hmac() {
8
+ // Use scrypt as the default inner hash
9
+ let hash_primitive = libpasta::primitives::Scrypt::default();
10
+ let mut config = libpasta::Config::with_primitive(hash_primitive);
11
+
12
+ // Some proper way of getting a key
13
+ let key = b"yellow submarine";
14
+ let key_id = config.add_key(key);
15
+ // Construct an HMAC instance and use this as the outer configuration
16
+ let keyed_function = libpasta::primitives::Hmac::with_key_id(&digest::SHA256, &key_id);
17
+ config.set_keyed_hash(keyed_function);
18
+
19
+ let hash = config.hash_password("hunter2");
20
+ println!("Computed hash: {:?}", hash);
21
+ // Outputs:
22
+ // Computed hash: "$!$hmac$key_id=LNMhDy...,h=SHA256$$scrypt$ln=14,r=8,p=1$ZJ5EY...$grlNA...."
23
+
24
+ assert!(hash.starts_with("$!$hmac"));
25
+ assert!(hash.contains("scrypt"));
26
+ }
@@ -0,0 +1,8 @@
1
+ extern crate libpasta;
2
+
3
+ #[macro_use]
4
+ mod common;
5
+
6
+ use libpasta::primitives::Pbkdf2;
7
+
8
+ config_test!(Pbkdf2, "$$pbkdf2");
@@ -0,0 +1,8 @@
1
+ extern crate libpasta;
2
+
3
+ #[macro_use]
4
+ mod common;
5
+
6
+ use libpasta::primitives::RingPbkdf2;
7
+
8
+ config_test!(RingPbkdf2, "$$pbkdf2");
@@ -0,0 +1,8 @@
1
+ extern crate libpasta;
2
+
3
+ #[macro_use]
4
+ mod common;
5
+
6
+ use libpasta::primitives::Scrypt;
7
+
8
+ config_test!(Scrypt, "$$scrypt");
@@ -0,0 +1,31 @@
1
+ %module(package="libpasta") pasta
2
+ %{
3
+ #include "../libpasta/libpasta-capi/include/pasta.h"
4
+ %}
5
+
6
+ %typemap(newfree) char * "free_string($1);";
7
+ %newobject hash_password;
8
+ %newobject read_password;
9
+
10
+
11
+
12
+ %pragma(java) jniclassimports=%{
13
+ import org.scijava.nativelib.*;
14
+ %}
15
+
16
+ %pragma(java) jniclasscode=%{
17
+ static {
18
+ try {
19
+ NativeLoader.loadLibrary("pasta_jni");
20
+ } catch (Exception e) {
21
+ try {
22
+ NativeLibraryUtil.loadNativeLibrary(pastaJNI.class, "pasta_jni");
23
+ } catch (Exception e2) {
24
+ System.err.println("Native code library failed to load. \n" + e);
25
+ System.exit(1);
26
+ }
27
+ }
28
+ }
29
+ %}
30
+
31
+ %include "libpasta/libpasta-capi/include/pasta.h"
@@ -0,0 +1,38 @@
1
+ LD_LIBRARY_PATH="../"
2
+ NATIVE_LIBS=-lcrypto -lc -lm -lc -lutil -lutil -ldl -lrt -lpthread -lgcc_s -lc -lm -lrt -lpthread -lutil
3
+
4
+ all: c java javascript go php python ruby
5
+
6
+ c:
7
+ @printf "\nTest C:\n"
8
+ @echo -e "\e[1;33mC tests should be performed using the libpasta repo in the libpasta-capi/ folder.\e[0m"
9
+
10
+ java:
11
+ @printf "\nTest Java:\n"
12
+ @echo -e "\e[1;33mJava tests should be performed using the libpasta-java repo.\e[0m"
13
+
14
+ javascript:
15
+ @printf "\nTest Javascript (node.js)\n"
16
+ cd ../javascript && node-gyp build
17
+
18
+ go:
19
+ @printf "\nTest Go:\n"
20
+ go test
21
+
22
+ php5 php56 php:
23
+ @printf "\nTest PHP:\n"
24
+ @$(PHP_BIN) test.php || \
25
+ echo -e "\e[1;33mPHP requires either installing libpasta (try: make install_php), or enabling dynamically loaded extensions.\e[0m"
26
+
27
+
28
+ python:
29
+ @printf "\nTest Python:\n"
30
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) \
31
+ python2 test.py
32
+
33
+ ruby:
34
+ @printf "\nTest Ruby\n"
35
+ LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) \
36
+ ruby test.rb
37
+
38
+ .PHONY: all c java javascript go php python ruby
@@ -0,0 +1,12 @@
1
+ package pasta_test
2
+
3
+ import "../go"
4
+ import "testing"
5
+
6
+ func TestPasta(t *testing.T) {
7
+ hash := pasta.Hash_password("hello123")
8
+ verify := pasta.Verify_password(hash, "hello123")
9
+ if verify == 0 {
10
+ t.Error("failed to verify correctly")
11
+ }
12
+ }
@@ -0,0 +1,7 @@
1
+ <?php
2
+ include("../php5/pasta.php");
3
+
4
+ $hash = pasta::hash_password("hello123");
5
+ assert(pasta::verify_password($hash, "hello123"));
6
+ echo "\033[1;32mPHP test passed.\033[m";
7
+ ?>
@@ -0,0 +1,7 @@
1
+ import sys
2
+ sys.path.insert(1, '../python')
3
+ import pasta
4
+
5
+ hash = pasta.hash_password("hello123")
6
+ assert pasta.verify_password(hash, "hello123")
7
+ print '\x1b[1;32m' + "Python test passed." + '\x1b[m'
@@ -0,0 +1,5 @@
1
+ require '../ruby/pasta.so'
2
+
3
+ hash = Pasta::hash_password("hunter2")
4
+ raise "Failed to verify password" unless Pasta::verify_password(hash, "hunter2")
5
+ puts "\e[1;32m" + "Ruby test passed." + "\e[m"