libpasta 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +37 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/Rakefile +9 -0
- data/ext/pasta-bindings/.gitmodules +3 -0
- data/ext/pasta-bindings/Makefile +84 -0
- data/ext/pasta-bindings/README.md +54 -0
- data/ext/pasta-bindings/libpasta/.gitignore +2 -0
- data/ext/pasta-bindings/libpasta/.travis.yml +60 -0
- data/ext/pasta-bindings/libpasta/Cargo.toml +42 -0
- data/ext/pasta-bindings/libpasta/LICENSE.md +21 -0
- data/ext/pasta-bindings/libpasta/Makefile +27 -0
- data/ext/pasta-bindings/libpasta/README.md +78 -0
- data/ext/pasta-bindings/libpasta/benches/bench.rs +125 -0
- data/ext/pasta-bindings/libpasta/examples/alternate_key_source.rs +33 -0
- data/ext/pasta-bindings/libpasta/examples/config.rs +10 -0
- data/ext/pasta-bindings/libpasta/examples/config_hmac.rs +25 -0
- data/ext/pasta-bindings/libpasta/examples/hash_password.rs +10 -0
- data/ext/pasta-bindings/libpasta/examples/migrate_password.rs +47 -0
- data/ext/pasta-bindings/libpasta/examples/verify_password.rs +24 -0
- data/ext/pasta-bindings/libpasta/libpasta-capi/Cargo.toml +12 -0
- data/ext/pasta-bindings/libpasta/libpasta-capi/ctest/compile +6 -0
- data/ext/pasta-bindings/libpasta/libpasta-capi/ctest/test +0 -0
- data/ext/pasta-bindings/libpasta/libpasta-capi/ctest/test.c +12 -0
- data/ext/pasta-bindings/libpasta/libpasta-capi/include/pasta.h +6 -0
- data/ext/pasta-bindings/libpasta/libpasta-capi/src/lib.rs +80 -0
- data/ext/pasta-bindings/libpasta/src/bench.rs +39 -0
- data/ext/pasta-bindings/libpasta/src/config.rs +358 -0
- data/ext/pasta-bindings/libpasta/src/hashing/de.rs +284 -0
- data/ext/pasta-bindings/libpasta/src/hashing/mod.rs +161 -0
- data/ext/pasta-bindings/libpasta/src/hashing/ser.rs +67 -0
- data/ext/pasta-bindings/libpasta/src/key/mod.rs +66 -0
- data/ext/pasta-bindings/libpasta/src/lib.rs +468 -0
- data/ext/pasta-bindings/libpasta/src/primitives/argon2.rs +180 -0
- data/ext/pasta-bindings/libpasta/src/primitives/bcrypt.rs +165 -0
- data/ext/pasta-bindings/libpasta/src/primitives/hmac.rs +134 -0
- data/ext/pasta-bindings/libpasta/src/primitives/mod.rs +312 -0
- data/ext/pasta-bindings/libpasta/src/primitives/pbkdf2.rs +272 -0
- data/ext/pasta-bindings/libpasta/src/primitives/scrypt.rs +144 -0
- data/ext/pasta-bindings/libpasta/src/sod.rs +46 -0
- data/ext/pasta-bindings/libpasta/tests/.libpasta.yaml +8 -0
- data/ext/pasta-bindings/libpasta/tests/common/mod.rs +37 -0
- data/ext/pasta-bindings/libpasta/tests/test_argon2.rs +8 -0
- data/ext/pasta-bindings/libpasta/tests/test_bcrypt.rs +8 -0
- data/ext/pasta-bindings/libpasta/tests/test_from_file.rs +13 -0
- data/ext/pasta-bindings/libpasta/tests/test_hmac.rs +26 -0
- data/ext/pasta-bindings/libpasta/tests/test_pbkdf2.rs +8 -0
- data/ext/pasta-bindings/libpasta/tests/test_ringpbkdf2.rs +8 -0
- data/ext/pasta-bindings/libpasta/tests/test_scrypt.rs +8 -0
- data/ext/pasta-bindings/pasta.i +31 -0
- data/ext/pasta-bindings/tests/Makefile +38 -0
- data/ext/pasta-bindings/tests/pasta_test.go +12 -0
- data/ext/pasta-bindings/tests/test.php +7 -0
- data/ext/pasta-bindings/tests/test.py +7 -0
- data/ext/pasta-bindings/tests/test.rb +5 -0
- data/lib/libpasta.rb +2 -0
- data/lib/libpasta/version.rb +3 -0
- data/libpasta.gemspec +52 -0
- data/spec/libpasta_spec.rb +11 -0
- data/spec/spec_helper.rb +11 -0
- 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,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,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,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
|