lastpass 1.2.0 → 1.2.1
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/CHANGELOG.md +5 -0
- data/lastpass.gemspec +1 -1
- data/lib/lastpass/parser.rb +32 -23
- data/lib/lastpass/version.rb +1 -1
- data/spec/parser_spec.rb +17 -6
- metadata +4 -4
data/CHANGELOG.md
CHANGED
data/lastpass.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_dependency "httparty", "~> 0.13.0"
|
20
20
|
s.add_dependency "pbkdf2-ruby", "~> 0.2.0"
|
21
21
|
|
22
|
-
s.add_development_dependency "rake", "~> 10.
|
22
|
+
s.add_development_dependency "rake", "~> 10.3.0"
|
23
23
|
s.add_development_dependency "rspec", "~> 2.14.0"
|
24
24
|
s.add_development_dependency "coveralls", "~> 0.7.0"
|
25
25
|
|
data/lib/lastpass/parser.rb
CHANGED
@@ -6,6 +6,14 @@ module LastPass
|
|
6
6
|
# OpenSSL constant
|
7
7
|
RSA_PKCS1_OAEP_PADDING = 4
|
8
8
|
|
9
|
+
# Secure note types that contain account-like information
|
10
|
+
ALLOWED_SECURE_NOTE_TYPES = {
|
11
|
+
"Server" => true,
|
12
|
+
"Email Account" => true,
|
13
|
+
"Database" => true,
|
14
|
+
"Instant Messenger" => true,
|
15
|
+
}
|
16
|
+
|
9
17
|
# Splits the blob into chucks grouped by kind.
|
10
18
|
def self.extract_chunks blob
|
11
19
|
chunks = []
|
@@ -28,13 +36,13 @@ module LastPass
|
|
28
36
|
def self.parse_ACCT chunk, encryption_key
|
29
37
|
StringIO.open chunk.payload do |io|
|
30
38
|
id = read_item io
|
31
|
-
name =
|
32
|
-
group =
|
39
|
+
name = decode_aes256_plain_auto read_item(io), encryption_key
|
40
|
+
group = decode_aes256_plain_auto read_item(io), encryption_key
|
33
41
|
url = decode_hex read_item io
|
34
|
-
notes =
|
42
|
+
notes = decode_aes256_plain_auto read_item(io), encryption_key
|
35
43
|
2.times { skip_item io }
|
36
|
-
username =
|
37
|
-
password =
|
44
|
+
username = decode_aes256_plain_auto read_item(io), encryption_key
|
45
|
+
password = decode_aes256_plain_auto read_item(io), encryption_key
|
38
46
|
2.times { skip_item io }
|
39
47
|
secure_note = read_item io
|
40
48
|
|
@@ -43,8 +51,7 @@ module LastPass
|
|
43
51
|
17.times { skip_item io }
|
44
52
|
secure_note_type = read_item io
|
45
53
|
|
46
|
-
|
47
|
-
if secure_note_type != "Server"
|
54
|
+
if !ALLOWED_SECURE_NOTE_TYPES.key? secure_note_type
|
48
55
|
return nil
|
49
56
|
end
|
50
57
|
|
@@ -95,10 +102,10 @@ module LastPass
|
|
95
102
|
key = if key.empty?
|
96
103
|
decode_hex rsa_key.private_decrypt(encrypted_key, RSA_PKCS1_OAEP_PADDING)
|
97
104
|
else
|
98
|
-
decode_hex
|
105
|
+
decode_hex decode_aes256_plain_auto(key, encryption_key)
|
99
106
|
end
|
100
107
|
|
101
|
-
name =
|
108
|
+
name = decode_aes256_base64_auto encrypted_name, key
|
102
109
|
|
103
110
|
# TODO: Return an object, not a hash
|
104
111
|
{id: id, name: name, encryption_key: key}
|
@@ -189,27 +196,29 @@ module LastPass
|
|
189
196
|
Base64.decode64 data
|
190
197
|
end
|
191
198
|
|
192
|
-
# Guesses AES
|
193
|
-
|
194
|
-
# - ciphers: AES-256 EBC, AES-256 CBC
|
195
|
-
# - encodings: plain, base64
|
196
|
-
def self.decode_aes256_auto data, encryption_key
|
199
|
+
# Guesses AES cipher (EBC or CBD) from the length of the plain data.
|
200
|
+
def self.decode_aes256_plain_auto data, encryption_key
|
197
201
|
length = data.length
|
198
|
-
length16 = length % 16
|
199
|
-
length64 = length % 64
|
200
202
|
|
201
203
|
if length == 0
|
202
204
|
""
|
203
|
-
elsif
|
204
|
-
decode_aes256_ecb_plain data, encryption_key
|
205
|
-
elsif length64 == 0 || length64 == 24 || length64 == 44
|
206
|
-
decode_aes256_ecb_base64 data, encryption_key
|
207
|
-
elsif length16 == 1
|
205
|
+
elsif data[0] == "!" && length % 16 == 1 && length > 32
|
208
206
|
decode_aes256_cbc_plain data, encryption_key
|
209
|
-
|
207
|
+
else
|
208
|
+
decode_aes256_ecb_plain data, encryption_key
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Guesses AES cipher (EBC or CBD) from the length of the base64 encoded data.
|
213
|
+
def self.decode_aes256_base64_auto data, encryption_key
|
214
|
+
length = data.length
|
215
|
+
|
216
|
+
if length == 0
|
217
|
+
""
|
218
|
+
elsif data[0] == "!"
|
210
219
|
decode_aes256_cbc_base64 data, encryption_key
|
211
220
|
else
|
212
|
-
|
221
|
+
decode_aes256_ecb_base64 data, encryption_key
|
213
222
|
end
|
214
223
|
end
|
215
224
|
|
data/lib/lastpass/version.rb
CHANGED
data/spec/parser_spec.rb
CHANGED
@@ -316,9 +316,9 @@ describe LastPass::Parser do
|
|
316
316
|
end
|
317
317
|
end
|
318
318
|
|
319
|
-
describe ".
|
319
|
+
describe ".decode_aes256_plain_auto" do
|
320
320
|
def check encoded, decoded
|
321
|
-
expect(LastPass::Parser.
|
321
|
+
expect(LastPass::Parser.decode_aes256_plain_auto encoded, encryption_key)
|
322
322
|
.to eq decoded
|
323
323
|
end
|
324
324
|
|
@@ -331,13 +331,24 @@ describe LastPass::Parser do
|
|
331
331
|
"All your base are belong to us"
|
332
332
|
end
|
333
333
|
|
334
|
-
it "decodes
|
335
|
-
check "
|
334
|
+
it "decodes CBC/plain string" do
|
335
|
+
check "IcokDWmjOkKtLpZehWKL6666Uj6fNXPpX6lLWlou+1Lrwb+D3ymP6BAwd6C0TB3hSA==".decode64,
|
336
336
|
"All your base are belong to us"
|
337
337
|
end
|
338
|
+
end
|
338
339
|
|
339
|
-
|
340
|
-
|
340
|
+
describe ".decode_aes256_base64_auto" do
|
341
|
+
def check encoded, decoded
|
342
|
+
expect(LastPass::Parser.decode_aes256_base64_auto encoded, encryption_key)
|
343
|
+
.to eq decoded
|
344
|
+
end
|
345
|
+
|
346
|
+
it "decodes a blank string" do
|
347
|
+
check "", ""
|
348
|
+
end
|
349
|
+
|
350
|
+
it "decodes ECB/base64 string" do
|
351
|
+
check "BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=",
|
341
352
|
"All your base are belong to us"
|
342
353
|
end
|
343
354
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lastpass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-06-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 10.
|
53
|
+
version: 10.3.0
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 10.
|
61
|
+
version: 10.3.0
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rspec
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|