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