salty_dog 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: b6e3d2c400d8da82752ae6862e1de092d9596e1b
4
+ data.tar.gz: c22eabb1c6afff27a88fe6927114e2fd0a782dd3
5
+ SHA512:
6
+ metadata.gz: 1a523b3345361daf452930cb9cc23de6fb3ee2fff54d015835a47bdb4fbe5f5ce7abfe271e34712f2c58715f2bd0b8fb2710a5c08fe76ad70e9f789e3aa7d343
7
+ data.tar.gz: 74675135cd008d478a1376232b614ac804946be2246c984c107d056466b9f76dad8ca853ffdec2316d098a514aa2ef240852ecd9be38936a29561ba40056b3ae
@@ -0,0 +1,143 @@
1
+ require 'openssl'
2
+
3
+ module SaltyDog
4
+
5
+ ##
6
+ # PBKDF2 encapsulates the identically-named password-based key derivation
7
+ # function outlined in PKCS[http://www.rsa.com/rsalabs/node.asp?id=2127] #5: Password-Based Cryptography Standard. PBKDF1, as set
8
+ # forth in the same document, has been recommended for removal from use, and
9
+ # thus is not implemented in SaltyDog. If you just need to generate keys,
10
+ # skip down to ::digest:
11
+
12
+ class PBKDF2
13
+
14
+ ##
15
+ # According to the recommendation, the hash functions that are supported
16
+ # for HMAC (pseudorandom number generation) are SHA1, SHA224, SHA256,
17
+ # SHA384, AND SHA512. These are provided here.
18
+
19
+ ALLOWED_DIGESTS = [:sha1, :sha224, :sha256, :sha384, :sha512]
20
+
21
+ ##
22
+ # The primary point of entry for SaltyDog::PBKDF2. The available options
23
+ # are:
24
+ #
25
+ # - :digest - One of +:sha1+, +:sha224+, +:sha256+, +:sha384+, or
26
+ # +:sha512+. Defaults to +:sha512+.
27
+ # - :password - A password for use in deriving the key. Required, and must be a string.
28
+ # - :salt - A salt that is concatenated to the password in key derivation.
29
+ # Required, and must ba a string.
30
+ # - :length - The desired length, in bytes, of the derived key. Required.
31
+ # - :iterations - The number of iterations to be used in key derivation.
32
+ # Defaults to 10000.
33
+ #
34
+ # Returns a hex-string representing the derived key.
35
+
36
+ def self.digest(options = {})
37
+ digest = options[:digest] || :sha512
38
+ self.build_digest(digest)
39
+
40
+ check_key_length_requirements(options[:length])
41
+ @length = options[:length]
42
+ @iterations = options[:iterations] || 10000
43
+
44
+ @l = (@length / @digest.length).ceil
45
+ @r = @length - (@l - 1) * @digest.length
46
+
47
+ self.calculate_key(@digest, options[:password], options[:salt], @l, @r, @iterations).unpack('H*')[0]
48
+ end
49
+
50
+ ##
51
+ # Build the derived key. Called directly by SaltyDog::PBKDF2.digest.
52
+
53
+ def self.build_digest(digest)
54
+ if !ALLOWED_DIGESTS.include?(digest)
55
+ raise PBKDF2Error, 'Invalid digest'
56
+ end
57
+
58
+ klass = "OpenSSL::Digest::#{digest.to_s.upcase}"
59
+ @digest = Object::const_get(klass).new
60
+ end
61
+
62
+ ##
63
+ # Check desired key length requirements. These are:
64
+ #
65
+ # - Must be present
66
+ # - Must be strictly positive
67
+ # - Must be no larger than (2^32 - 1) * digest length of the chosen hash
68
+ # function
69
+ #
70
+ # Raises a PBKDF2Error if any of these requirements are not met.
71
+
72
+ def self.check_key_length_requirements(length)
73
+ raise PBKDF2Error, 'A key length must be provided' if !length
74
+ raise PBKDF2Error, 'Desired key is too long' if ((2**32 - 1) * @digest.length) < length
75
+ raise PBKDF2Error, 'Desired key length must be positive' if length < 0
76
+ end
77
+
78
+ ##
79
+ # XOR two strings +x+ and +y+.
80
+ #
81
+ # Raises a PBKDF2Error if +a+ and +b+ are not the same length.
82
+ #
83
+ # Returns a string of bytes representing the XORed value.
84
+
85
+ def self.xor(x, y)
86
+ raise PBKDF2Error, 'XOR arguments are not the same length' if x.length - y.length != 0
87
+ output = "".encode('ASCII-8BIT')
88
+
89
+ x.bytes.zip(y.bytes) { |x,y| output << (x^y) }
90
+ output
91
+ end
92
+
93
+ ##
94
+ # Uses a pseudorandom function based on the digest function provided to
95
+ # SaltyDog::PBKDF2.digest to generate input for each iteration round.
96
+
97
+ def self.prf(digest, password, seed)
98
+ raise PBKDF2Error if !password || !seed
99
+ OpenSSL::HMAC.digest(digest, password, seed)
100
+ end
101
+
102
+ ##
103
+ # Within each iteration, SaltyDog::PBKDF2.xor_sum XORs each block of output
104
+ # from SaltyDog::PBKDF2.prf. The result of this chain of XORs is provided
105
+ # to ::calculate_key to be used as a block of the final derived key.
106
+
107
+ def self.xor_sum(digest, password, salt, iterations, block_number)
108
+ packed_index = [block_number].pack("N")
109
+ seed = salt + packed_index
110
+ final = self.prf(digest, password, seed)
111
+ u = final
112
+
113
+ for i in 2..iterations do
114
+ u = self.prf(digest, password, u)
115
+ final = self.xor(final, u)
116
+ end
117
+
118
+ final
119
+ end
120
+
121
+ ##
122
+ # The workhorse of SaltyDog::PBKDF2. ::calculate_key initiates the
123
+ # specified number of iterations of hashing in calculating each block of
124
+ # the derived key. All blocks are then concatenated together in computing
125
+ # the final derived key.
126
+
127
+ def self.calculate_key(digest, password, salt, l, r, iterations)
128
+ t = ""
129
+
130
+ for i in 1..l+1 do
131
+ t << self.xor_sum(digest, password, salt, iterations, i)
132
+ end
133
+
134
+ total_length = digest.length * (l-1) + r
135
+ sliced = t.slice(0..total_length - 1)
136
+ sliced
137
+ end
138
+ end
139
+
140
+ class PBKDF2Error < StandardError
141
+ end
142
+ end
143
+
data/lib/salty_dog.rb ADDED
@@ -0,0 +1 @@
1
+ require 'salty_dog/salty_dog'
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: salty_dog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brennon Bortz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: simplecov
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: turn
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.6
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.6
41
+ description: A complete, RFC compliant implementation of PBKDF2. As opposed to other
42
+ PBKDF2 gems, all parameters to the key-derivation function are completely and easily
43
+ customizable.
44
+ email: brennon@brennonbortz.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - lib/salty_dog.rb
50
+ - lib/salty_dog/salty_dog.rb
51
+ homepage: http://github.com/brennon/salty_dog
52
+ licenses:
53
+ - BSD-3
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --main
58
+ - README.md
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 2.0.3
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: PBKDF2, Ruby-style
77
+ test_files: []