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,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"