strongboxio 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.
- data/lib/strongboxio.rb +207 -0
- data/test/2fe22f4d-bd41-476a-8159-c6e0b6487f7d.sbox +24 -0
- data/test/test_helper.rb +3 -0
- data/test/test_strongboxio.rb +28 -0
- metadata +53 -0
data/lib/strongboxio.rb
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
require 'openssl' # for decryption
|
|
2
|
+
require 'zlib' # for decompression
|
|
3
|
+
require 'base64' # for decoding
|
|
4
|
+
require 'rubygems' if defined?RUBY_VERSION && RUBY_VERSION =~ /^1.8/ # for requiring gem dependency in Ruby 1.8
|
|
5
|
+
require 'nokogiri' # for xml parsing
|
|
6
|
+
|
|
7
|
+
class Strongboxio
|
|
8
|
+
|
|
9
|
+
VERSION = '0.1.0'
|
|
10
|
+
|
|
11
|
+
STRONGBOX_VERSION = 3
|
|
12
|
+
VERSION_LENGTH = 1
|
|
13
|
+
SALT_LENGTH = 64
|
|
14
|
+
IV_LENGTH = 16
|
|
15
|
+
KEY_LENGTH = 32
|
|
16
|
+
RANDOM_VALUE_LENGTH = 64
|
|
17
|
+
CIPHER = 'AES-256-CBC'
|
|
18
|
+
PAYLOAD_SCHEMA_VERSION = '2.4'
|
|
19
|
+
UNIX_EPOCH_IN_100NS_INTERVALS = 621355968000000000 # .NET time format: number of 100-nanosecond intervals since .NET epoch: January 1, 0001 at 00:00:00.000 (midnight)
|
|
20
|
+
|
|
21
|
+
def self.resembles_base64?(string)
|
|
22
|
+
string.length % 4 == 0 && string =~ /^[A-Za-z0-9+\/=]+\Z/
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.decrypt(sbox_filename, password)
|
|
26
|
+
# open the xml file
|
|
27
|
+
f = File.open(sbox_filename)
|
|
28
|
+
data = Nokogiri::XML(f)
|
|
29
|
+
f.close
|
|
30
|
+
|
|
31
|
+
# extract the Data node
|
|
32
|
+
data = data.xpath('//Data').text
|
|
33
|
+
base64_error_msg = 'expected Base64 encoded byte string from the StrongBox.Payload.Data element of the xml of a Strongbox file'
|
|
34
|
+
raise "#{base64_error_msg}, but got nothing" if data.length == 0
|
|
35
|
+
raise "#{base64_error_msg}, but it does not resemble Base64" unless self.resembles_base64?(data)
|
|
36
|
+
|
|
37
|
+
data = Base64.decode64(data)
|
|
38
|
+
|
|
39
|
+
#version = data.getbyte(0) # ruby 1.9
|
|
40
|
+
version = data.bytes.to_a[0] # ruby 1.8 friendly
|
|
41
|
+
raise "expected version number #{STRONGBOX_VERSION}, but got #{version}" unless version == STRONGBOX_VERSION
|
|
42
|
+
|
|
43
|
+
salt = data.slice(1, SALT_LENGTH)
|
|
44
|
+
raise "expected salt length #{SALT_LENGTH}, but got #{salt.length}" unless salt.length == SALT_LENGTH
|
|
45
|
+
|
|
46
|
+
iv = data.bytes.to_a.slice((1+64), IV_LENGTH).pack('C*')
|
|
47
|
+
raise "expected iv length #{IV_LENGTH}, but got #{iv.length}" unless iv.length == IV_LENGTH
|
|
48
|
+
|
|
49
|
+
key = Digest::SHA256.digest(salt + password)
|
|
50
|
+
raise "expected key length #{KEY_LENGTH}, but got #{key.length}" unless key.length == KEY_LENGTH
|
|
51
|
+
|
|
52
|
+
# prepare for decryption
|
|
53
|
+
d = OpenSSL::Cipher.new(CIPHER)
|
|
54
|
+
d.decrypt
|
|
55
|
+
d.key = key
|
|
56
|
+
d.iv = iv
|
|
57
|
+
|
|
58
|
+
# decrypt the portion beyond the header
|
|
59
|
+
begin
|
|
60
|
+
data = '' << d.update(data.slice((VERSION_LENGTH+SALT_LENGTH+IV_LENGTH)..-1)) << d.final
|
|
61
|
+
rescue => e
|
|
62
|
+
raise "Error decrypting. You probably entered the password incorrectly. Specific error: #{e}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# decompress the portion beyond the random value
|
|
66
|
+
#z = Zlib::Inflate.new
|
|
67
|
+
#z = Zlib::Inflate.new(-Zlib::BEST_COMPRESSION) # works for Strongbox
|
|
68
|
+
z = Zlib::Inflate.new(-Zlib::MAX_WBITS) # works for Strongbox!
|
|
69
|
+
#z = Zlib::Inflate.new(Zlib::MAX_WBITS) # works for roundtrip
|
|
70
|
+
data = z.inflate(data.slice(RANDOM_VALUE_LENGTH..-1))
|
|
71
|
+
z.finish
|
|
72
|
+
z.close
|
|
73
|
+
|
|
74
|
+
data
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.render(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false)
|
|
78
|
+
data = Nokogiri::XML(decrypted_sbox)
|
|
79
|
+
|
|
80
|
+
payload_schema_version = data.xpath('//Payload').xpath('SchemaVersion').text
|
|
81
|
+
unless payload_schema_version == PAYLOAD_SCHEMA_VERSION
|
|
82
|
+
raise "expected schema version #{PAYLOAD_SCHEMA_VERSION}, but got #{payload_schema_version}" unless continue_despite_unexpected_payload_schema_version
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
mt = data.xpath('//Payload').xpath('PayloadInfo').xpath('MT').text
|
|
86
|
+
puts mt
|
|
87
|
+
|
|
88
|
+
data.xpath('//PayloadData').each { |payload_data|
|
|
89
|
+
payload_data.xpath('//SBE').each { |entity|
|
|
90
|
+
puts
|
|
91
|
+
name = entity.xpath('N').text
|
|
92
|
+
puts "#{name}" if name.length > 0
|
|
93
|
+
description = entity.xpath('D').text
|
|
94
|
+
puts "#{description}" if description.length > 0
|
|
95
|
+
tags = entity.xpath('T').text
|
|
96
|
+
puts "#{tags}" if tags.length > 0
|
|
97
|
+
ce = entity.xpath('CE')
|
|
98
|
+
ce.xpath('TFE').each { |tfe|
|
|
99
|
+
name = tfe.xpath('N').text
|
|
100
|
+
puts "#{name}:" if name.length > 0
|
|
101
|
+
content = tfe.xpath('C').text
|
|
102
|
+
puts "#{content}" if content.length > 0
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def assemble(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false)
|
|
109
|
+
data = Nokogiri::XML(decrypted_sbox)
|
|
110
|
+
|
|
111
|
+
payload_schema_version = data.xpath('//Payload').xpath('SchemaVersion').text
|
|
112
|
+
unless payload_schema_version == PAYLOAD_SCHEMA_VERSION
|
|
113
|
+
raise "expected schema version #{PAYLOAD_SCHEMA_VERSION}, but got #{payload_schema_version}" unless continue_despite_unexpected_payload_schema_version
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
sbox = {}
|
|
117
|
+
|
|
118
|
+
mt = data.xpath('//Payload').xpath('PayloadInfo').xpath('MT').text
|
|
119
|
+
sbox['MT'] = mt
|
|
120
|
+
|
|
121
|
+
data.xpath('//PayloadData').each { |payload_data|
|
|
122
|
+
|
|
123
|
+
sbox['PayloadData'] = []
|
|
124
|
+
|
|
125
|
+
payload_data.xpath('//SBE').each_with_index { |strongbox_entity, sbe_index|
|
|
126
|
+
|
|
127
|
+
sbox['PayloadData'][sbe_index] = {}
|
|
128
|
+
|
|
129
|
+
sbe_mt = strongbox_entity.attr('MT') # ModifiedTimestamp.Ticks
|
|
130
|
+
sbox['PayloadData'][sbe_index]['MT'] = sbe_mt if sbe_mt.length > 0
|
|
131
|
+
|
|
132
|
+
sbe_ct = strongbox_entity.attr('CT') # CreatedTimestamp.Ticks
|
|
133
|
+
sbox['PayloadData'][sbe_index]['CT'] = sbe_ct if sbe_ct.length > 0
|
|
134
|
+
|
|
135
|
+
sbe_ac = strongbox_entity.attr('AC') # accessCount
|
|
136
|
+
sbox['PayloadData'][sbe_index]['AC'] = sbe_ac if sbe_ac.length > 0
|
|
137
|
+
|
|
138
|
+
sbe_name = strongbox_entity.xpath('N').text
|
|
139
|
+
sbox['PayloadData'][sbe_index]['N'] = sbe_name if sbe_name.length > 0
|
|
140
|
+
|
|
141
|
+
sbe_description = strongbox_entity.xpath('D').text
|
|
142
|
+
sbox['PayloadData'][sbe_index]['D'] = sbe_description if sbe_description.length > 0
|
|
143
|
+
|
|
144
|
+
sbe_tags = strongbox_entity.xpath('T').text
|
|
145
|
+
sbox['PayloadData'][sbe_index]['T'] = sbe_tags if sbe_tags.length > 0
|
|
146
|
+
|
|
147
|
+
child_entity = strongbox_entity.xpath('CE')
|
|
148
|
+
if child_entity.length > 0
|
|
149
|
+
sbox['PayloadData'][sbe_index]['CE'] = []
|
|
150
|
+
|
|
151
|
+
child_entity.xpath('TFE').each_with_index { |text_field_entity, ce_index|
|
|
152
|
+
|
|
153
|
+
sbox['PayloadData'][sbe_index]['CE'][ce_index] = {}
|
|
154
|
+
|
|
155
|
+
tfe_name = text_field_entity.xpath('N').text
|
|
156
|
+
sbox['PayloadData'][sbe_index]['CE'][ce_index]['N'] = tfe_name if tfe_name.length > 0
|
|
157
|
+
|
|
158
|
+
tfe_content = text_field_entity.xpath('C').text
|
|
159
|
+
sbox['PayloadData'][sbe_index]['CE'][ce_index]['C'] = tfe_content if tfe_content.length > 0
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
sbox
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def render(verbose=false)
|
|
169
|
+
puts sbox['MT']
|
|
170
|
+
|
|
171
|
+
sbox['PayloadData'].each { |payload_data|
|
|
172
|
+
puts
|
|
173
|
+
puts payload_data['N'] unless payload_data['N'].nil?
|
|
174
|
+
puts payload_data['D'] unless payload_data['D'].nil?
|
|
175
|
+
puts payload_data['T'] unless payload_data['T'].nil?
|
|
176
|
+
payload_data['CE'].each { |strongbox_entity|
|
|
177
|
+
puts strongbox_entity['N'] + ': ' unless strongbox_entity['N'].nil?
|
|
178
|
+
puts strongbox_entity['C'] unless strongbox_entity['C'].nil?
|
|
179
|
+
}
|
|
180
|
+
puts "Access Count: #{payload_data['AC']}" if !payload_data['AC'].nil? && verbose
|
|
181
|
+
puts "#{convert_time_from_dot_net_epoch(payload_data['MT'].to_i)} (modify time)" if !payload_data['MT'].nil? && verbose
|
|
182
|
+
puts "#{convert_time_from_dot_net_epoch(payload_data['CT'].to_i)} (create time)" if !payload_data['CT'].nil? && verbose
|
|
183
|
+
}
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
#attr_accessor :decrypted_sbox
|
|
187
|
+
attr_accessor :sbox
|
|
188
|
+
|
|
189
|
+
# create an instance of Strongbox
|
|
190
|
+
def initialize(decrypted_sbox, continue_despite_unexpected_payload_schema_version=false)
|
|
191
|
+
super()
|
|
192
|
+
#self.decrypted_sbox = decrypted_sbox
|
|
193
|
+
self.sbox = assemble(decrypted_sbox, continue_despite_unexpected_payload_schema_version)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
def convert_time_from_dot_net_epoch(t)
|
|
199
|
+
Time.at((t-UNIX_EPOCH_IN_100NS_INTERVALS)*1e-7).utc.getlocal
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
#class String
|
|
204
|
+
# def resembles_base64?
|
|
205
|
+
# self.length % 4 == 0 && self =~ /^[A-Za-z0-9+\/=]+\Z/
|
|
206
|
+
# end
|
|
207
|
+
#end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<StrongBox>
|
|
3
|
+
<SchemaVersion>2.1</SchemaVersion>
|
|
4
|
+
<Metadata>
|
|
5
|
+
<SchemaVersion>2.2</SchemaVersion>
|
|
6
|
+
<SBOXID>2fe22f4d-bd41-476a-8159-c6e0b6487f7d</SBOXID>
|
|
7
|
+
<SID>1aefeb7f-87fb-4c12-9587-78f2354c3a70</SID>
|
|
8
|
+
<CreateDate>129985312023925270</CreateDate>
|
|
9
|
+
<ModifiedDate>129985323759179228</ModifiedDate>
|
|
10
|
+
<Name>strongbox gem test</Name>
|
|
11
|
+
<Description>Strongbox Ruby gem test box</Description>
|
|
12
|
+
<PassphaseHint />
|
|
13
|
+
<LocalModifiedDate>129985312023925280</LocalModifiedDate>
|
|
14
|
+
<PayloadIdentity>sQgzfRSQEkCJo25tVi47Q</PayloadIdentity>
|
|
15
|
+
<PayloadSize>1217</PayloadSize>
|
|
16
|
+
<PayloadType />
|
|
17
|
+
<PayloadItemCount>4</PayloadItemCount>
|
|
18
|
+
<PayloadBaseRevisionTag>129985312024788056-129985312024788056</PayloadBaseRevisionTag>
|
|
19
|
+
</Metadata>
|
|
20
|
+
<Payload>
|
|
21
|
+
<SchemaVersion>2.1</SchemaVersion>
|
|
22
|
+
<Data>AxHLk57HTQaFzAHatF+lFg++t44Dfwr78cKGHzQB1+eWbKL9HVTZK9T/omI7P9az8gvJA//5CkYGz6HcQS7Sg/U5PTNqU4u2EZhkdaRUK6KooHux/u9HBF27RXy/8shiJbS6FN7EPew/8zzuZRe00WzOcoKELmHvbeTgZG0Te2Mtox+PfZMYEvRPjbA2eI70KwzlzSuoHbmyECKo36x9RTAHTeQTEXMfkcMU6D0ONsbMmNoJkC3TqIX5bcYLQ1FxQpwvB/AbtfyCLPk9Zxhmm0ihEsBfcPqxU9kaVkCBOfOyxFyvueEdFgEs1PxYJ571huJpyprCcQKcarr3yvMIzkn3rJKO6s9F0gR8PqdrBBO3PxKeZO6sJnpEq0WIuSYaY2wFGXr0UvK/Hid3hUHwVEjfbiVVJmXFmRHmEnJD7Q2EctX5Ju20ESYSXy3f3r/W3RTaR8ZwLVPiyroV2EjOZrhI0pMhXLZaOhszVA4alC7djphKRZkh1zg39pnMaPNYACW0rlAnFz5zk74Uez64xiWI352i89jfjj5R16blBlxq8FjJJVSlUxJJNJwnlbG744AXxd1ygI56koztmbwY1VbAOmr4FiX9JtVLq6a6gVKv3sy3eKlxKXd41jhOTNIKnu0Nh36TxXs64Q2BdozKnQvCN9BYelawWPQOp3viQ95LlruiQQEnzzmcGuZw33ny1QfxVFuz/Gd+i50eg++urf/woprI74OtXANWWhN6chSP29Gz8y76/zYZoYAerZxAVPuh+elW9Xw3fjCwHk33/tkOvVcKQb/LCcFZdaawh6gdYfRJTRetQYKIWdKn7QuYhZLKYXMcJ1BBrDnJx0QKCN8kwNggzRlfYtgzz07t1BQXL+5F9m18KQfXbGR4HpI3INwWMFA61mFKRMih0cORjbVwfISJIZfRp/oe1Ut8r4+cZbTwdmPEnUrMiOSQLk0gUk7DknnCfEPKLjOFz+DAwhqSfosNKUkV1AB+GDzI2JfR5P3SMLh77/CLN1Adx/tXH46A2K6D5JXPVGUR9mhMD9hCH6v34dRNkfBSD0EN2VHMAkVAWrDm4UiKf3uO6k51Q7IZ0vcp+QSZdcV98rhAVgpx79S3MPd8+riamxuZFHe/5Ao1p4JW1FajPxbZnh4LhQNdN8vTSuywOaefN7Mph4X3WEJ5cOYcJm5MdYQDx9t1DSdY1l+tuDHW+8LWpqicVN0JWNADPFCyQwoAQMzX1ax3zq8zXofI+MaJOxaxiEu/pJDPce07fmf/W6Xxcw8Uugm4bZE7pxcTRrrhXZ4WYBmHyxRfNtGZyw8K385S8wRW93FPUnwHRDUyDoRN+w9FwAxWPmywM2Z8RyfyN6frQ0j4roB9YD2Yt1YuY6/yoUDiDxsLdaBYEfre+A26VlkC3zUy/M64yPe6J/CO1hBDVkwxJ8hmkiw2QtHROIz80hDvprecVWjzwLNT+ddT+oXf5nEFREZP8IMxzDNdrRcydQjpJHViWvn4fLxhF72KcTLKM0yfokpbsGnC3X63dcHFHG0KTiTcfnBNqqdi9WyhD12Jm62bAfgJVV+GFJHXSHdTGCa1REmqfuKeSIVBCxaCPSNG1M/WbEdAfJNjGj980ZQ=</Data>
|
|
23
|
+
</Payload>
|
|
24
|
+
</StrongBox>
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'test_helper'
|
|
3
|
+
|
|
4
|
+
class StrongboxioTest < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
FILENAME = 'test/2fe22f4d-bd41-476a-8159-c6e0b6487f7d.sbox'
|
|
7
|
+
PASSWORD = 'pWY4ic9q'
|
|
8
|
+
|
|
9
|
+
def test_decrypt_from_file
|
|
10
|
+
expect='<Payload><SchemaVersion>2.4</SchemaVersion><PayloadInfo><SchemaVersion>1.0</SchemaVersion><IP>PyOQP3GmNEA3T5BjBOiPg,DU4Qm4btjyejD1TYGoUjQ,nC9jzQ4Tv3RsrfxHzghe4A,YlVFCZO1FqBT91H0M3XmQA,WIVON6o61vebxLKJhXKQ,sQgzfRSQEkCJo25tVi47Q</IP><MT>2012-11-27T23:29:23.18873Z</MT><SD>xJ2VL0VourNV3a7cOJkinAMkVVEJJahV17MlbE5x8w</SD></PayloadInfo><PayloadData><T /><CE><SBE ID="7ijIF8xabBZjKsEKpUFnag" II="4" MT="634896555753103810" CT="634896555753102130" AC="0"><N>VanCity bank info</N><D>credit card, debit card, online banking</D><T>Credit, Debit, Card, Online, Banking</T><CE><TFE ID="K87JOu1lge4X7SSKE9elDQ" II="4" MT="634896555753103820"><N>credit card number</N><C>1234 5678 9012 3456</C></TFE><TFE ID="PTsGYmJb7f1B8nIquZfAMQ" II="4" MT="634896555753104130"><N>credit card expiration</N><C>11/2012</C></TFE><TFE ID="sfRgujycbbKIad58FkC1vg" II="4" MT="634896555753104380"><N>credit card verification value</N><C>123</C></TFE><TFE ID="bK7Vba0t2oupLiRGjEkt5Q" II="4" MT="634896555753104690"><N>debit card PIN</N><C>1234</C></TFE><TFE ID="2j9hKQJqCvbrVpmfRqJVA" II="4" MT="634896555753104970"><N>online banking password</N><C>qwerty</C></TFE></CE></SBE><SBE ID="L35bmTNw34lQnA70hmEVmg" II="3" MT="634896550747551430" CT="634896550747549900" AC="0"><N>fake Gmail account</N><D>used for Stackoverflow</D><T>Fake Gmail Stackoverflow</T><CE><TFE ID="Zmjyh5cMoj5s1AuH18EJA" II="3" MT="634896550747551440"><N>username</N><C>ima_fake@gmail.com</C></TFE><TFE ID="bOudR7nlwP40bo6V23jw" II="3" MT="634896550747551750"><N>password</N><C>password1</C></TFE><TFE ID="klbjFvsyyDEs956gkduKg" II="3" MT="634896550747552080"><N>gender</N><C>other</C></TFE><TFE ID="ckdoh9oM478UliFoeg" II="3" MT="634896550747552370"><N>backup</N><C>bart_simpson@gmail.com</C></TFE></CE></SBE><SBE ID="SwH6NoXPhg7qXLOUlDQyQ" II="2" MT="634896545666557670" CT="634896545666556630" AC="0"><N>just a name</N><D></D><T /><CE><TFE ID="u9LEZ2H2jQlzqc7a5vD2iA" II="2" MT="634896545666557680"><N /><C /></TFE></CE></SBE><SBE ID="ZoPVBFNFdOlRLT0FLO9BVQ" II="5" MT="634896557631887530" CT="634896545082402010" AC="0"><N>test item name</N><D>test item description</D><T>Test, Item, Tag1, Tag2, Tag3</T><CE><TFE ID="NyRRL7tmBMr0VrDoyzfwg" II="1" MT="634896545082426060"><N>test field name</N><C>test secure text</C></TFE></CE></SBE></CE></PayloadData></Payload>'
|
|
11
|
+
|
|
12
|
+
assert_equal expect,
|
|
13
|
+
Strongboxio.decrypt(FILENAME, PASSWORD)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_strongboxio_instantiation
|
|
17
|
+
# #<Strongboxio:0x1011b2e28 @sbox={"PayloadData"=>[{"CE"=>[{"C"=>"1234 5678 9012 3456", "N"=>"credit card number"}, {"C"=>"11/2012", "N"=>"credit card expiration"}, {"C"=>"123", "N"=>"credit card verification value"}, {"C"=>"1234", "N"=>"debit card PIN"}, {"C"=>"qwerty", "N"=>"online banking password"}], "AC"=>"0", "N"=>"VanCity bank info", "D"=>"credit card, debit card, online banking", "CT"=>"634896555753102130", "MT"=>"634896555753103810", "T"=>"Credit, Debit, Card, Online, Banking"}, {"CE"=>[{"C"=>"ima_fake@gmail.com", "N"=>"username"}, {"C"=>"password1", "N"=>"password"}, {"C"=>"other", "N"=>"gender"}, {"C"=>"bart_simpson@gmail.com", "N"=>"backup"}], "AC"=>"0", "N"=>"fake Gmail account", "D"=>"used for Stackoverflow", "CT"=>"634896550747549900", "MT"=>"634896550747551430", "T"=>"Fake Gmail Stackoverflow"}, {"CE"=>[{}], "AC"=>"0", "N"=>"just a name", "CT"=>"634896545666556630", "MT"=>"634896545666557670"}, {"CE"=>[{"C"=>"test secure text", "N"=>"test field name"}], "AC"=>"0", "N"=>"test item name", "D"=>"test item description", "CT"=>"634896545082402010", "MT"=>"634896557631887530", "T"=>"Test, Item, Tag1, Tag2, Tag3"}], "MT"=>"2012-11-27T23:29:23.18873Z"}>
|
|
18
|
+
|
|
19
|
+
d = Strongboxio.decrypt(FILENAME, PASSWORD)
|
|
20
|
+
sbox = Strongboxio.new(d)
|
|
21
|
+
assert_equal 'Strongboxio',
|
|
22
|
+
sbox.class.to_s
|
|
23
|
+
assert_equal '2012-11-27T23:29:23.18873Z',
|
|
24
|
+
sbox.sbox['MT']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
metadata
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: strongboxio
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Alex Batko
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-11-29 00:00:00.000000000Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: Decrypt and read www.Strongbox.io files.
|
|
15
|
+
email:
|
|
16
|
+
- alexbatko@gmail.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- lib/strongboxio.rb
|
|
22
|
+
- test/2fe22f4d-bd41-476a-8159-c6e0b6487f7d.sbox
|
|
23
|
+
- test/test_helper.rb
|
|
24
|
+
- test/test_strongboxio.rb
|
|
25
|
+
homepage: https://github.com/abatko/strongboxio
|
|
26
|
+
licenses:
|
|
27
|
+
- MIT
|
|
28
|
+
post_install_message:
|
|
29
|
+
rdoc_options: []
|
|
30
|
+
require_paths:
|
|
31
|
+
- lib
|
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - ! '>='
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
44
|
+
requirements: []
|
|
45
|
+
rubyforge_project:
|
|
46
|
+
rubygems_version: 1.8.10
|
|
47
|
+
signing_key:
|
|
48
|
+
specification_version: 3
|
|
49
|
+
summary: Decrypt and read www.Strongbox.io files
|
|
50
|
+
test_files:
|
|
51
|
+
- test/2fe22f4d-bd41-476a-8159-c6e0b6487f7d.sbox
|
|
52
|
+
- test/test_helper.rb
|
|
53
|
+
- test/test_strongboxio.rb
|