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.
@@ -1,3 +1,8 @@
1
+ Version 1.2.1
2
+ -------------
3
+
4
+ - Fixed the decryption bug on long shared folder names.
5
+
1
6
  Version 1.2.0
2
7
  -------------
3
8
 
@@ -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.1.0"
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
 
@@ -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 = decode_aes256_auto read_item(io), encryption_key
32
- group = decode_aes256_auto read_item(io), encryption_key
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 = decode_aes256_auto read_item(io), encryption_key
42
+ notes = decode_aes256_plain_auto read_item(io), encryption_key
35
43
  2.times { skip_item io }
36
- username = decode_aes256_auto read_item(io), encryption_key
37
- password = decode_aes256_auto read_item(io), encryption_key
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
- # Only "Server" secure note stores account information
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 decode_aes256_auto(key, encryption_key)
105
+ decode_hex decode_aes256_plain_auto(key, encryption_key)
99
106
  end
100
107
 
101
- name = decode_aes256_auto encrypted_name, key
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 encoding/cipher from the length of the data.
193
- # Possible combinations are:
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 length16 == 0
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
- elsif length64 == 6 || length64 == 26 || length64 == 50
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
- raise RuntimeError, "'#{data.inspect}' doesn't seem to be AES-256 encrypted"
221
+ decode_aes256_ecb_base64 data, encryption_key
213
222
  end
214
223
  end
215
224
 
@@ -2,5 +2,5 @@
2
2
  # Licensed under the terms of the MIT license. See LICENCE for details.
3
3
 
4
4
  module LastPass
5
- VERSION = "1.2.0"
5
+ VERSION = "1.2.1"
6
6
  end
@@ -316,9 +316,9 @@ describe LastPass::Parser do
316
316
  end
317
317
  end
318
318
 
319
- describe ".decode_aes256_auto" do
319
+ describe ".decode_aes256_plain_auto" do
320
320
  def check encoded, decoded
321
- expect(LastPass::Parser.decode_aes256_auto encoded, encryption_key)
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 ECB/base64 string" do
335
- check "BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=",
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
- it "decodes CBC/plain string" do
340
- check "IcokDWmjOkKtLpZehWKL6666Uj6fNXPpX6lLWlou+1Lrwb+D3ymP6BAwd6C0TB3hSA==".decode64,
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.0
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-04-13 00:00:00.000000000 Z
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.1.0
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.1.0
61
+ version: 10.3.0
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: rspec
64
64
  requirement: !ruby/object:Gem::Requirement