class Strongboxio
Constants
- CIPHER
- IV_LENGTH
- KEY_LENGTH
- PAYLOAD_SCHEMA_VERSION
- RANDOM_VALUE_LENGTH
- SALT_LENGTH
- STRONGBOX_VERSION
- UNIX_EPOCH_IN_100NS_INTERVALS
- VERSION
- VERSION_LENGTH
Attributes
sbox[RW]
Public Class Methods
decrypt(sbox_filename, password)
click to toggle source
# File lib/strongboxio.rb, line 23 def self.decrypt(sbox_filename, password) # open the xml file f = File.open(sbox_filename) data = Nokogiri::XML(f) f.close # extract the Data node data = data.xpath('//Data').text base64_error_msg = 'expected Base64 encoded byte string from the StrongBox.Payload.Data element of the xml of a Strongbox file' raise "#{base64_error_msg}, but got nothing" if data.length == 0 raise "#{base64_error_msg}, but it does not resemble Base64" unless self.resembles_base64?(data) data = Base64.decode64(data) #version = data.getbyte(0) # ruby 1.9 version = data.bytes.to_a[0] # ruby 1.8 friendly raise "expected version number #{STRONGBOX_VERSION}, but got #{version}" unless version == STRONGBOX_VERSION salt = data.slice(1, SALT_LENGTH) raise "expected salt length #{SALT_LENGTH}, but got #{salt.length}" unless salt.length == SALT_LENGTH iv = data.bytes.to_a.slice((1+64), IV_LENGTH).pack('C*') raise "expected iv length #{IV_LENGTH}, but got #{iv.length}" unless iv.length == IV_LENGTH key = Digest::SHA256.digest(salt + password) raise "expected key length #{KEY_LENGTH}, but got #{key.length}" unless key.length == KEY_LENGTH # prepare for decryption d = OpenSSL::Cipher.new(CIPHER) d.decrypt d.key = key d.iv = iv # decrypt the portion beyond the header begin data = '' << d.update(data.slice((VERSION_LENGTH+SALT_LENGTH+IV_LENGTH)..-1)) << d.final rescue => e raise "Error decrypting. You probably entered the password incorrectly. Specific error: #{e}" end # decompress the portion beyond the random value #z = Zlib::Inflate.new #z = Zlib::Inflate.new(-Zlib::BEST_COMPRESSION) # works for Strongbox z = Zlib::Inflate.new(-Zlib::MAX_WBITS) # works for Strongbox! #z = Zlib::Inflate.new(Zlib::MAX_WBITS) # works for roundtrip data = z.inflate(data.slice(RANDOM_VALUE_LENGTH..-1)) z.finish z.close data end
new(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false)
click to toggle source
Calls superclass method
# File lib/strongboxio.rb, line 106 def initialize(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false) super() data = Nokogiri::XML(decrypted_sbox) payload_schema_version = data.xpath('//Payload').xpath('SchemaVersion').text unless payload_schema_version == PAYLOAD_SCHEMA_VERSION raise "expected schema version #{PAYLOAD_SCHEMA_VERSION}, but got #{payload_schema_version}" unless continue_despite_unexpected_payload_schema_version end @sbox = {} mt = data.xpath('//Payload').xpath('PayloadInfo').xpath('MT').text @sbox['MT'] = mt data.xpath('//PayloadData').each { |payload_data| @sbox['PayloadData'] = [] payload_data.xpath('//SBE').each_with_index { |strongbox_entity, sbe_index| @sbox['PayloadData'][sbe_index] = {} sbe_mt = strongbox_entity.attr('MT') # ModifiedTimestamp.Ticks @sbox['PayloadData'][sbe_index]['MT'] = sbe_mt if sbe_mt.length > 0 sbe_ct = strongbox_entity.attr('CT') # CreatedTimestamp.Ticks @sbox['PayloadData'][sbe_index]['CT'] = sbe_ct if sbe_ct.length > 0 sbe_ac = strongbox_entity.attr('AC') # accessCount @sbox['PayloadData'][sbe_index]['AC'] = sbe_ac if defined?sbe_ac && sbe_ac.length > 0 sbe_name = strongbox_entity.xpath('N').text @sbox['PayloadData'][sbe_index]['N'] = sbe_name if sbe_name.length > 0 sbe_description = strongbox_entity.xpath('D').text @sbox['PayloadData'][sbe_index]['D'] = sbe_description if sbe_description.length > 0 sbe_tags = strongbox_entity.xpath('T').text @sbox['PayloadData'][sbe_index]['T'] = sbe_tags if sbe_tags.length > 0 child_entity = strongbox_entity.xpath('CE') if child_entity.length > 0 @sbox['PayloadData'][sbe_index]['CE'] = [] child_entity.xpath('TFE').each_with_index { |text_field_entity, ce_index| @sbox['PayloadData'][sbe_index]['CE'][ce_index] = {} tfe_name = text_field_entity.xpath('N').text @sbox['PayloadData'][sbe_index]['CE'][ce_index]['N'] = tfe_name if tfe_name.length > 0 tfe_content = text_field_entity.xpath('C').text @sbox['PayloadData'][sbe_index]['CE'][ce_index]['C'] = tfe_content if tfe_content.length > 0 } end } } end
render(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false)
click to toggle source
# File lib/strongboxio.rb, line 75 def self.render(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false) data = Nokogiri::XML(decrypted_sbox) payload_schema_version = data.xpath('//Payload').xpath('SchemaVersion').text unless payload_schema_version == PAYLOAD_SCHEMA_VERSION raise "expected schema version #{PAYLOAD_SCHEMA_VERSION}, but got #{payload_schema_version}" unless continue_despite_unexpected_payload_schema_version end puts data.xpath('//Payload').xpath('PayloadInfo').xpath('MT').text data.xpath('//PayloadData').each { |payload_data| payload_data.xpath('//SBE').each { |entity| puts name = entity.xpath('N').text puts "#{name}" if name.length > 0 description = entity.xpath('D').text puts "#{description}" if description.length > 0 tags = entity.xpath('T').text puts "#{tags}" if tags.length > 0 ce = entity.xpath('CE') ce.xpath('TFE').each { |tfe| name = tfe.xpath('N').text puts "#{name}:" if name.length > 0 content = tfe.xpath('C').text puts "#{content}" if content.length > 0 } } } 0 end
Private Class Methods
resembles_base64?(string)
click to toggle source
# File lib/strongboxio.rb, line 187 def self.resembles_base64?(string) string.length % 4 == 0 && string =~ /^[A-Za-z0-9+\/=]+\Z/ end
Public Instance Methods
render(verbose=false)
click to toggle source
# File lib/strongboxio.rb, line 166 def render(verbose=false) puts sbox['MT'] sbox['PayloadData'].each { |payload_data| puts puts payload_data['N'] unless payload_data['N'].nil? puts payload_data['D'] unless payload_data['D'].nil? puts payload_data['T'] unless payload_data['T'].nil? payload_data['CE'].each { |strongbox_entity| puts strongbox_entity['N'] + ': ' unless strongbox_entity['N'].nil? puts strongbox_entity['C'] unless strongbox_entity['C'].nil? } puts "Access Count: #{payload_data['AC']}" if !payload_data['AC'].nil? && verbose puts "#{convert_time_from_dot_net_epoch(payload_data['MT'].to_i)} (modify time)" if !payload_data['MT'].nil? && verbose puts "#{convert_time_from_dot_net_epoch(payload_data['CT'].to_i)} (create time)" if !payload_data['CT'].nil? && verbose } 0 end
Private Instance Methods
convert_time_from_dot_net_epoch(t)
click to toggle source
# File lib/strongboxio.rb, line 191 def convert_time_from_dot_net_epoch(t) Time.at((t-UNIX_EPOCH_IN_100NS_INTERVALS)*1e-7).utc.getlocal end