lib/opentoken.rb in opentoken-0.2.0 vs lib/opentoken.rb in opentoken-0.2.1
- old
+ new
@@ -2,10 +2,12 @@
require 'openssl'
require 'digest/sha1'
require 'zlib'
require 'stringio'
require 'cgi'
+require File.join(File.dirname(__FILE__), 'opentoken', 'key_value_serializer')
+require File.join(File.dirname(__FILE__), 'opentoken', 'password_key_generator')
class OpenToken
class TokenExpiredError < StandardError; end
DEBUG = false
@@ -88,10 +90,11 @@
unparsed_payload = begin
Zlib::Inflate.inflate(compressed_payload)
rescue Zlib::BufError
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(compressed_payload[2, compressed_payload.size])
end
+ puts 'EXPANDED PAYLOAD', unparsed_payload if DEBUG
#validate payload hmac
mac = "0x01".hex.chr
mac += cipher_suite.chr
mac += iv
@@ -100,11 +103,14 @@
hash = OpenSSL::HMAC.digest(PasswordKeyGenerator::SHA1_DIGEST, key, mac)
if (hash <=> payload_hmac) != 0
raise "HMAC for payload was #{hash} and expected to be #{payload_hmac}" unless payload_hmac == hash
end
- @payload = KeyValueSerializer.deserialize CGI::unescapeHTML(unparsed_payload)
+ unescaped_payload = CGI::unescapeHTML(unparsed_payload)
+ puts 'UNESCAPED PAYLOAD', unescaped_payload if DEBUG
+ @payload = KeyValueSerializer.deserialize unescaped_payload
+ puts @payload.inspect if DEBUG
raise TokenExpiredError.new("#{Time.now.utc} is not within token duration: #{self.start_at} - #{self.end_at}") if self.expired?
end
def [](key)
@payload[key.to_s]
@@ -147,180 +153,7 @@
index = 0
string.each_byte do |b|
puts "#{index}: #{b} => #{b.chr}"
index += 1
end
- end
-end
-
-class PasswordKeyGenerator
- SHA1_DIGEST = OpenSSL::Digest::Digest.new('sha1')
-
- def self.generate(password, cipher_suite)
- salt = 0.chr * 8
- self.generate_impl(password, cipher_suite, salt, 1000)
- end
-
- def self.generate_block(password, salt, count, index)
- mac = salt
- mac += [index].pack("N")
-
- result = OpenSSL::HMAC.digest(SHA1_DIGEST, password, mac)
- cur = result
-
- i_count = 1
- while i_count < count
- i_count +=1
-
- cur = OpenSSL::HMAC.digest(SHA1_DIGEST, password, cur)
-
- 20.times do |i|
- result[i] = result[i] ^ cur[i]
- end
- end
-
- return result
- end
-
- def self.generate_impl(password, cipher, salt, iterations)
- return unless cipher[:algorithm]
-
- key_size = cipher[:key_length] / 8
- numblocks = key_size / 20
- numblocks += 1 if (key_size % 20) > 0
-
- # Generate the appropriate number of blocks and write their output to
- # the key bytes; note that it's important to start from 1 (vs. 0) as the
- # initial block number affects the hash. It's not clear that this fact
- # is stated explicitly anywhere, but without this approach, the generated
- # keys will not match up with test cases defined in RFC 3962.
- key_buffer_index = 0
- key = ""
-
- numblocks.times do |i|
- i+=1 # Previously zero based, needs to be 1 based
- block = self.generate_block(password, salt, iterations, i)
- len = [20, (key_size - key_buffer_index)].min
- key += block[0, len]
- key_buffer_index += len
- end
-
- return key
- end
-end
-
-class KeyValueSerializer
- LINE_START = 0
- EMPTY_SPACE = 1
- VALUE_START = 2
- LINE_END = 3
- IN_KEY = 4
- IN_VALUE = 5
- IN_QUOTED_VALUE = 6
-
- def self.unescape_value(value)
- value.gsub("\\\"", "\"").gsub("\'", "'")
- end
-
- def self.deserialize(string)
- result = {}
- state = LINE_START
- open_quote_char = 0.chr
- currkey = ""
- token = ""
- nextval = ""
-
- string.split(//).each do |c|
-
- nextval = c
-
- case c
- when "\t"
- if state == IN_KEY
- # key ends
- currkey = token
- token = ""
- state = EMPTY_SPACE
- elsif state == IN_VALUE
- # non-quoted value ends
- result[currkey] = self.deserialize(token)
- token = ""
- state = LINE_END
- elsif state == IN_QUOTED_VALUE
- token += c
- end
- when " "
- if state == IN_KEY
- # key ends
- currkey = token
- token = ""
- state = EMPTY_SPACE
- elsif state == IN_VALUE
- # non-quoted value ends
- result[currkey] = self.deserialize(token)
- token = ""
- state = LINE_END
- elsif state == IN_QUOTED_VALUE
- token += c
- end
- when "\n"
- # newline
- if (state == IN_VALUE) || (state == VALUE_START)
- result[currkey] = self.unescape_value(token)
- token = ""
- state = LINE_START
- elsif state == LINE_END
- token = ""
- state = LINE_START
- elsif state == IN_QUOTED_VALUE
- token += c
- end
- when "="
- if state == IN_KEY
- currkey = token
- token = ""
- state = VALUE_START
- elsif (state == IN_QUOTED_VALUE) || (state == IN_VALUE)
- token += c
- end
- when "\""
- if state == IN_QUOTED_VALUE
- if (c == open_quote_char) && (token[token.size-1] != "\\")
- result[currkey] = self.unescape_value(token)
- token = ""
- state = LINE_END
- else
- token += c
- end
- elsif state == VALUE_START
- state = IN_QUOTED_VALUE
- open_quote_char = c
- end
- when "'"
- if state == IN_QUOTED_VALUE
- if (c == open_quote_char) && (token[token.size-1] != "\\")
- result[currkey] = self.unescape_value(token)
- token = ""
- state = LINE_END
- else
- token += c
- end
- else state == VALUE_START
- state = IN_QUOTED_VALUE
- open_quote_char = c
- end
- else
- if state == LINE_START
- state = IN_KEY
- elsif state == VALUE_START
- state = IN_VALUE
- end
- token += c
- end
-
- if (state == IN_QUOTED_VALUE) || (state == IN_VALUE)
- result[currkey] = unescape_value(token)
- end
- end
- result
end
end