rypt 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f7c7e6578e7ed82c0cb83ceecc831fde58389e3
4
+ data.tar.gz: a1a919ef3158eddde0dc1a750ce462d9b89ff85f
5
+ SHA512:
6
+ metadata.gz: cb60404071678964452f847347e6dc4959627efb3247f81caf92b233979604889b5276d8644c74b3cc1e8b618b8282cbb523a8a57f01d2494964bb5bc61df966
7
+ data.tar.gz: c5b59bf1a2ac1d70d3233a9ebd24281dc983415302de8ea737c99c7db3e74f7d905531ab329ff8396ee138186ed573e5dc286737310c87c6199779884f63f1f2
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1 @@
1
+ 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rypt.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Trey Evans
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ # Rypt
2
+
3
+ Rypt provides implementations of standard crypt functions that are not available on all environments. Currently it only supports salted SHA512.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ require File.join(File.dirname(__FILE__), "rypt", "version")
2
+ require File.join(File.dirname(__FILE__), "rypt", "sha512")
3
+
4
+ module Rypt
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,79 @@
1
+ require 'digest'
2
+ require 'base64'
3
+
4
+ module Rypt
5
+ # Implements the standard crypt(3) call with SHA-512 and a salt.
6
+ # It consists of 3 main steps:
7
+ # 1. Calculate an initial set of 'special' values from the salt and password
8
+ # 2. Perform repeated stretching rounds using the 'special' values
9
+ # 3. Finalize the hash result by reordering the bytes and base-64 encoding them using a custom mapping scheme
10
+ # At the end we are going to take the result of #3 and spit it out concatenated with the seed as the final result.
11
+ class Sha512
12
+ def init_hash(salt, pass)
13
+ alt_sum = Digest::SHA2.new(512).digest(pass + salt + pass)
14
+ s_length = [salt.length, 16].min
15
+ p_length = [pass.length, 64].min
16
+ int_sum_input = pass + salt + alt_sum[0..(p_length - 1)]
17
+ p_length_array = p_length.to_s(2)
18
+ p_length_array.reverse.each_char do |c|
19
+ if (c == "1")
20
+ int_sum_input << alt_sum
21
+ else
22
+ int_sum_input << pass
23
+ end
24
+ end
25
+ intermediate_0 = Digest::SHA2.new(512).digest(int_sum_input)
26
+ s_factor = 16 + intermediate_0[0].ord
27
+ s_bytes_input = ""
28
+ s_factor.times do
29
+ s_bytes_input << salt
30
+ end
31
+ p_bytes_input = ""
32
+ p_length.times do
33
+ p_bytes_input << pass
34
+ end
35
+ s_bytes = Digest::SHA2.new(512).digest(s_bytes_input)[0..(s_length - 1)]
36
+ p_bytes = Digest::SHA2.new(512).digest(p_bytes_input)[0..(p_length - 1)]
37
+ [s_bytes, p_bytes, intermediate_0]
38
+ end
39
+
40
+ def round(i, s, p, intermediate)
41
+ hash_input = ""
42
+ hash_input << intermediate if ((i % 2) == 0)
43
+ hash_input << p if ((i % 2) == 1)
44
+ hash_input << s if ((i % 3) != 0)
45
+ hash_input << p if ((i % 7) != 0)
46
+ hash_input << p if ((i % 2) == 0)
47
+ hash_input << intermediate if ((i % 2) == 1)
48
+ (Digest::SHA2.new(512).digest(hash_input))
49
+ end
50
+
51
+ # Don't ask me how or why this works. I don't actually understand it.
52
+ # All I know is that it gives the right answer according to the tests cases.
53
+ # The original instructions on how to implement this algorithm are kind of hairy and not well explained, you're welcome to injure yourself trying to understand them here:
54
+ # http://www.akkadia.org/drepper/SHA-crypt.txt
55
+ # Follow item #22 on, and be amazed at the pain.
56
+ def finalize_block(hash_val)
57
+ index_hash = [63, 62, 20, 41, 40, 61, 19, 18, 39, 60, 59, 17, 38, 37, 58, 16, 15, 36, 57, 56, 14, 35, 34, 55, 13, 12, 33, 54, 53, 11, 32, 31, 52, 10, 9, 30, 51, 50, 8, 29, 28, 49, 7, 6, 27, 48, 47, 5, 26, 25, 46, 4, 3, 24, 45, 44, 2, 23, 22, 43, 1, 0, 21, 42].reverse
58
+
59
+ b64="./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
60
+
61
+ reordered_hash = (0..63).to_a.map { |i| hash_val[index_hash[i]] }
62
+ char_array = []
63
+ reordered_hash.join.each_char { |e| char_array << e.unpack("b*") }
64
+ ((char_array.join + "0000").reverse.scan(/.{1,6}/).map { |e| ((e).to_i 2) }.reverse.map { |i| b64[i] }).join
65
+ end
66
+
67
+ def run(salt_val, pass_val)
68
+ salt_trunc = salt_val[0..15]
69
+ pass_trunc = pass_val
70
+ sb, pb, i0 = init_hash(salt_trunc.force_encoding(Encoding::UTF_8), pass_trunc.force_encoding(Encoding::UTF_8))
71
+
72
+ hash_val = (0..4999).to_a.inject(i0) do |acc, i|
73
+ val = round(i, sb, pb, acc)
74
+ end
75
+
76
+ "$6$" + salt_trunc + "$" + finalize_block(hash_val)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module Rypt
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rypt/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rypt"
8
+ spec.version = Rypt::VERSION
9
+ spec.authors = ["Trey Evans"]
10
+ spec.email = ["lewis.r.evans@gmail.com"]
11
+
12
+ spec.summary = %q{Pure ruby implementations of standard crypt.}
13
+ spec.description = %q{Pure ruby implementations of standard crypt.}
14
+ spec.homepage = "https://github.com/TreyE/rypt"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.10"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rspec", "~> 3.3"
23
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rypt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Trey Evans
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-23 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.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.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: '3.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ description: Pure ruby implementations of standard crypt.
56
+ email:
57
+ - lewis.r.evans@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".ruby-version"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - lib/rypt.rb
70
+ - lib/rypt/sha512.rb
71
+ - lib/rypt/version.rb
72
+ - rypt.gemspec
73
+ homepage: https://github.com/TreyE/rypt
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.4.5
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Pure ruby implementations of standard crypt.
97
+ test_files: []