pbkdf2_password_hasher 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e5ef13ed0a6bd80499e058a98c70fe3797f5b5e7
4
+ data.tar.gz: 0abc6f671b5cf855ce359db027c32aea1d55a10c
5
+ SHA512:
6
+ metadata.gz: 2b7dcfa535e5e19c1141d3e4668dba5ffd50b919e5f7a699049223a34f51639a144a1cbc067d4e7743f4dd88c35914887fd6d053b8a79a06529b4d0966469839
7
+ data.tar.gz: 4e2bc782267f3f554abcafe049c6841666e8fbeae805ff03f1b0f1a88667186070bab55fb5463531a4782e3515f0b1e36487ebd5bf29e6030ddbf80701da7a3c
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.swp
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pbkdf2_password_hasher.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Aurélien Hervé
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ pbkdf2-password-hasher
2
+ ======================
3
+
4
+ Compute a pbkdf2 hash of a string, and/or check a password against a pbkdf2 hashed string.
5
+
6
+ This was originally built to import password hashes from django application to rails/devise application
7
+
8
+ ## Installation
9
+
10
+ In your Gemfile :
11
+ ```ruby
12
+ gem pbkdf2_password_hasher, git: 'aherve/pbkdf2-password-hasher'
13
+ ```
14
+
15
+ or install it with:
16
+ ```ruby
17
+ gem install pbkdf2_password_hasher
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ - Hash a password with salt:
23
+ ```ruby
24
+ salt = 'NaCl' # random salt key
25
+ pass = 's3cr3t' # your password
26
+ it = 1000 # number of iterations
27
+
28
+ hash = Pbkdf2PasswordHasher.hash_password(pass,salt,it)
29
+ ```
30
+ - Check password validity against string
31
+
32
+ ```ruby
33
+ # hashed string from django app
34
+ hsh ='pbkdf2_sha256$12000$PEnXGf9dviXF$2soDhu1WB8NSbFDm0w6NEe6OvslVXtiyf4VMiiy9rH0='
35
+
36
+ # with right password:
37
+ Pbkdf2PasswordHasher.check_password('bite',hsh) #=> true
38
+
39
+ #with wrong password:
40
+ Pbkdf2PasswordHasher.check_password('bitten',hsh) #=> false
41
+ ```
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,68 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ class DjangoHash
5
+ attr_reader :hsh
6
+
7
+ def initialize(params)
8
+ @password = params[:password]
9
+ @dklen = params[:dklen] || 32
10
+ @c = params[:c].to_i || 12000
11
+ @hsh = params[:hash]
12
+ @salt = params[:salt]
13
+
14
+ @hash_f = OpenSSL::Digest.new("sha256")
15
+ end
16
+
17
+ # Instanciate class using hash string
18
+ def self.parse(str)
19
+ algo,c,salt,hsh = str.split('$')
20
+ raise "sorry, don't know what to do with #{algo}" unless algo == 'pbkdf2_sha256'
21
+ DjangoHash.new(
22
+ :dklen => Base64.decode64(hsh).size,
23
+ :c => c,
24
+ :salt => salt,
25
+ :hash => hsh,
26
+ )
27
+ end
28
+
29
+ # Compute hash
30
+ def get_hash
31
+ (1..number_of_blocks).map(&block).reduce("",&:<<)
32
+ end
33
+
34
+ # Check password against computed hash
35
+ def check_password(password)
36
+ @password = password
37
+ @hsh == get_hash
38
+ end
39
+
40
+ private
41
+
42
+ def number_of_blocks
43
+ (@dklen.to_f/@hash_f.size).ceil
44
+ end
45
+
46
+ # "string xor"
47
+ def xor(s1,s2)
48
+ s1.bytes.zip((s2).bytes).map{|a,b| a ^ b}.pack("C*")
49
+ end
50
+
51
+ # Pseudo Random Function, as described in wikipedia
52
+ def prf(data)
53
+ @hash_func ||= OpenSSL::Digest.new("sha256")
54
+ OpenSSL::HMAC.digest(@hash_func,@password, data)
55
+ end
56
+
57
+ def block
58
+ -> i {
59
+ u = prf(@salt+[i].pack("N"))
60
+ f = u
61
+ 2.upto(@c) do |i|
62
+ u = prf(u)
63
+ f = xor(f,u)
64
+ end
65
+ Base64.encode64(f[0..@dklen-1]).chomp
66
+ }
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module Pbkdf2PasswordHasher
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ require "pbkdf2_password_hasher/version"
2
+ require 'pbkdf2_password_hasher/django_hash'
3
+
4
+ module Pbkdf2PasswordHasher
5
+
6
+ class << self
7
+
8
+ # 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(
11
+ :password => pass,
12
+ :salt => salt,
13
+ :c => nb_of_iterations,
14
+ :dklen => key_length,
15
+ ).get_hash
16
+ end
17
+
18
+ # Check password against hash string
19
+ def check_password(pass,hash)
20
+ DjangoHash::parse(hash).check_password(pass)
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pbkdf2_password_hasher/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pbkdf2_password_hasher"
8
+ spec.version = Pbkdf2PasswordHasher::VERSION
9
+ spec.authors = ["Aurélien Hervé"]
10
+ spec.email = ["mail@aurelien-herve.com"]
11
+ spec.summary = %q{pbkdf2 hash check}
12
+ spec.description = %q{Check a password against a pbkdf2 hashed string. Useful to import password hashes from django application to rails/devise application}
13
+ spec.homepage = "https://github.com/aherve/pbkdf2-password-hasher"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+
25
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ describe Pbkdf2PasswordHasher do
3
+
4
+ before(:all) do
5
+ @django_hash = 'pbkdf2_sha256$12000$PEnXGf9dviXF$2soDhu1WB8NSbFDm0w6NEe6OvslVXtiyf4VMiiy9rH0='
6
+ end
7
+
8
+ describe 'check_password' do
9
+
10
+ describe "when provided the right password" do
11
+ it "should validate" do
12
+ Pbkdf2PasswordHasher::check_password('bite',@django_hash).should be_true
13
+ end
14
+ end
15
+
16
+ describe "when NOT provided the right password" do
17
+ it "should NOT validate" do
18
+ Pbkdf2PasswordHasher::check_password('false_pass',@django_hash).should be_false
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ describe "hash_password" do
25
+
26
+ it "should work" do
27
+ a = @django_hash.split("$")
28
+ Pbkdf2PasswordHasher.hash_password('bite',a[2],a[1]).should == a[3]
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec'
2
+ require 'pbkdf2_password_hasher'
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pbkdf2_password_hasher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Aurélien Hervé
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Check a password against a pbkdf2 hashed string. Useful to import password
56
+ hashes from django application to rails/devise application
57
+ email:
58
+ - mail@aurelien-herve.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - lib/pbkdf2_password_hasher.rb
70
+ - lib/pbkdf2_password_hasher/django_hash.rb
71
+ - lib/pbkdf2_password_hasher/version.rb
72
+ - pbkdf2_password_hasher.gemspec
73
+ - spec/pbkdf2_password_hasher_spec.rb
74
+ - spec/spec_helper.rb
75
+ homepage: https://github.com/aherve/pbkdf2-password-hasher
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.2.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: pbkdf2 hash check
99
+ test_files:
100
+ - spec/pbkdf2_password_hasher_spec.rb
101
+ - spec/spec_helper.rb