pbkdf2_password_hasher 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/lib/pbkdf2_password_hasher.rb +7 -11
- data/lib/pbkdf2_password_hasher/django_hash.rb +17 -17
- data/lib/pbkdf2_password_hasher/version.rb +1 -1
- data/spec/pbkdf2_password_hasher_spec.rb +13 -19
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4da9a1f50fcf2892177ec04bea61b094cb642e5
|
4
|
+
data.tar.gz: 620f187ecaba9d0ed453a867ec720d9c1a8318be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e5799e40f3c2fa359ed4198d05ae65a77afd59a2ad6a12df6d3f163323f6e99192a8dbea267f76ee242acfd1108a78b89ce4def321379afd83496e4fe8943c1
|
7
|
+
data.tar.gz: 899aaeef1e3a04d60d4662b6f652608ebcc6002fa78f9bdb12ee91f0daa9ae41cd33a5c9c9e45fe6fc19bfb46d64b8391f7b55e116525e4a89339f152d86034f
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ This was originally built to import password hashes from django application to r
|
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
10
|
-
In your Gemfile :
|
10
|
+
In your Gemfile :
|
11
11
|
```ruby
|
12
12
|
gem pbkdf2_password_hasher, git: 'aherve/pbkdf2-password-hasher'
|
13
13
|
```
|
@@ -25,13 +25,13 @@ salt = 'NaCl' # random salt key
|
|
25
25
|
pass = 's3cr3t' # your password
|
26
26
|
it = 1000 # number of iterations
|
27
27
|
|
28
|
-
hash = Pbkdf2PasswordHasher.hash_password(pass,salt,it)
|
28
|
+
hash = Pbkdf2PasswordHasher.hash_password(pass,salt,it) #=> "pbkdf2_sha256$1000$NaCl$uDAu+fkRHoZk03PKp0bzrXDWc4j4mhkzGBm7ljbvp58="
|
29
29
|
```
|
30
30
|
- Check password validity against string
|
31
31
|
|
32
32
|
```ruby
|
33
33
|
# hashed string from django app
|
34
|
-
hsh ='pbkdf2_sha256$12000$PEnXGf9dviXF$2soDhu1WB8NSbFDm0w6NEe6OvslVXtiyf4VMiiy9rH0='
|
34
|
+
hsh ='pbkdf2_sha256$12000$PEnXGf9dviXF$2soDhu1WB8NSbFDm0w6NEe6OvslVXtiyf4VMiiy9rH0='
|
35
35
|
|
36
36
|
# with right password:
|
37
37
|
Pbkdf2PasswordHasher.check_password('bite',hsh) #=> true
|
@@ -1,26 +1,22 @@
|
|
1
|
-
require
|
1
|
+
require 'pbkdf2_password_hasher/version'
|
2
2
|
require 'pbkdf2_password_hasher/django_hash'
|
3
3
|
|
4
4
|
module Pbkdf2PasswordHasher
|
5
|
-
|
6
5
|
class << self
|
7
|
-
|
8
6
|
# compute a hash from password, salt, number of iterations, and key length
|
9
|
-
def hash_password(pass,salt,nb_of_iterations,key_length=32)
|
10
|
-
DjangoHash.new(
|
7
|
+
def hash_password(pass, salt, nb_of_iterations, key_length = 32)
|
8
|
+
hsh = DjangoHash.new(
|
11
9
|
:password => pass,
|
12
10
|
:salt => salt,
|
13
11
|
:c => nb_of_iterations,
|
14
|
-
:dklen => key_length
|
12
|
+
:dklen => key_length
|
15
13
|
).get_hash
|
14
|
+
"pbkdf2_sha256$#{nb_of_iterations}$#{salt}$#{hsh}"
|
16
15
|
end
|
17
16
|
|
18
17
|
# Check password against hash string
|
19
|
-
def check_password(pass,hash)
|
20
|
-
DjangoHash
|
18
|
+
def check_password(pass, hash)
|
19
|
+
DjangoHash.parse(hash).check_password(pass)
|
21
20
|
end
|
22
|
-
|
23
21
|
end
|
24
|
-
|
25
22
|
end
|
26
|
-
|
@@ -7,28 +7,28 @@ class DjangoHash
|
|
7
7
|
def initialize(params)
|
8
8
|
@password = params[:password]
|
9
9
|
@dklen = params[:dklen] || 32
|
10
|
-
@c = params[:c].to_i ||
|
10
|
+
@c = params[:c].to_i || 12_000
|
11
11
|
@hsh = params[:hash]
|
12
12
|
@salt = params[:salt]
|
13
13
|
|
14
|
-
@hash_f = OpenSSL::Digest.new(
|
14
|
+
@hash_f = OpenSSL::Digest.new('sha256')
|
15
15
|
end
|
16
16
|
|
17
17
|
# Instanciate class using hash string
|
18
18
|
def self.parse(str)
|
19
|
-
algo,c,salt,hsh = str.split('$')
|
20
|
-
|
19
|
+
algo, c, salt, hsh = str.split('$')
|
20
|
+
fail "sorry, don't know what to do with #{algo}" unless algo == 'pbkdf2_sha256'
|
21
21
|
DjangoHash.new(
|
22
22
|
:dklen => Base64.decode64(hsh).size,
|
23
23
|
:c => c,
|
24
24
|
:salt => salt,
|
25
|
-
:hash => hsh
|
25
|
+
:hash => hsh
|
26
26
|
)
|
27
27
|
end
|
28
28
|
|
29
29
|
# Compute hash
|
30
30
|
def get_hash
|
31
|
-
(1..number_of_blocks).map(&block).reduce(
|
31
|
+
(1..number_of_blocks).map(&block).reduce('', &:<<)
|
32
32
|
end
|
33
33
|
|
34
34
|
# Check password against computed hash
|
@@ -40,29 +40,29 @@ class DjangoHash
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def number_of_blocks
|
43
|
-
(@dklen.to_f
|
43
|
+
(@dklen.to_f / @hash_f.size).ceil
|
44
44
|
end
|
45
45
|
|
46
46
|
# "string xor"
|
47
|
-
def xor(s1,s2)
|
48
|
-
s1.bytes.zip((s2).bytes).map{|a,b| a ^ b}.pack(
|
47
|
+
def xor(s1, s2)
|
48
|
+
s1.bytes.zip((s2).bytes).map { |a, b| a ^ b }.pack('C*')
|
49
49
|
end
|
50
50
|
|
51
51
|
# Pseudo Random Function, as described in wikipedia
|
52
52
|
def prf(data)
|
53
|
-
@hash_func ||= OpenSSL::Digest.new(
|
54
|
-
OpenSSL::HMAC.digest(@hash_func
|
53
|
+
@hash_func ||= OpenSSL::Digest.new('sha256')
|
54
|
+
OpenSSL::HMAC.digest(@hash_func, @password, data)
|
55
55
|
end
|
56
56
|
|
57
57
|
def block
|
58
|
-
-> i
|
59
|
-
u = prf(@salt+[i].pack(
|
58
|
+
-> i do
|
59
|
+
u = prf(@salt + [i].pack('N'))
|
60
60
|
f = u
|
61
|
-
2.upto(@c) do |
|
61
|
+
2.upto(@c) do |_i|
|
62
62
|
u = prf(u)
|
63
|
-
f = xor(f,u)
|
63
|
+
f = xor(f, u)
|
64
64
|
end
|
65
|
-
Base64.encode64(f[0..@dklen-1]).chomp
|
66
|
-
|
65
|
+
Base64.encode64(f[0..@dklen - 1]).chomp
|
66
|
+
end
|
67
67
|
end
|
68
68
|
end
|
@@ -1,33 +1,27 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
describe Pbkdf2PasswordHasher do
|
3
|
-
|
4
|
-
before(:all) do
|
2
|
+
describe Pbkdf2PasswordHasher do
|
3
|
+
before(:all) do
|
5
4
|
@django_hash = 'pbkdf2_sha256$12000$PEnXGf9dviXF$2soDhu1WB8NSbFDm0w6NEe6OvslVXtiyf4VMiiy9rH0='
|
6
5
|
end
|
7
6
|
|
8
|
-
describe 'check_password' do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
Pbkdf2PasswordHasher::check_password('bite',@django_hash).should be_true
|
7
|
+
describe 'check_password' do
|
8
|
+
describe 'when provided the right password' do
|
9
|
+
it 'should validate' do
|
10
|
+
expect(Pbkdf2PasswordHasher.check_password('bite', @django_hash)).to be true
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
16
|
-
describe
|
17
|
-
it
|
18
|
-
Pbkdf2PasswordHasher
|
14
|
+
describe 'when NOT provided the right password' do
|
15
|
+
it 'should NOT validate' do
|
16
|
+
expect(Pbkdf2PasswordHasher.check_password('false_pass', @django_hash)).to be false
|
19
17
|
end
|
20
18
|
end
|
21
|
-
|
22
19
|
end
|
23
20
|
|
24
|
-
describe
|
25
|
-
|
26
|
-
|
27
|
-
a
|
28
|
-
Pbkdf2PasswordHasher.hash_password('bite',a[2],a[1]).should == a[3]
|
21
|
+
describe 'hash_password' do
|
22
|
+
it 'should work' do
|
23
|
+
a = @django_hash.split('$')
|
24
|
+
expect(Pbkdf2PasswordHasher.hash_password('bite', a[2], a[1])).to eq(@django_hash)
|
29
25
|
end
|
30
|
-
|
31
26
|
end
|
32
|
-
|
33
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pbkdf2_password_hasher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aurélien Hervé
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
94
|
rubyforge_project:
|
95
|
-
rubygems_version: 2.2
|
95
|
+
rubygems_version: 2.4.2
|
96
96
|
signing_key:
|
97
97
|
specification_version: 4
|
98
98
|
summary: pbkdf2 hash check
|