lastpass 1.3.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ruby.yml +23 -0
- data/.gitignore +5 -4
- data/.travis.yml +8 -3
- data/CHANGELOG.md +41 -0
- data/README.md +5 -5
- data/Rakefile +1 -0
- data/example/example.rb +5 -3
- data/lastpass.gemspec +7 -8
- data/lib/lastpass.rb +1 -1
- data/lib/lastpass/account.rb +3 -1
- data/lib/lastpass/blob.rb +4 -2
- data/lib/lastpass/fetcher.rb +33 -26
- data/lib/lastpass/http.rb +3 -3
- data/lib/lastpass/note.rb +15 -0
- data/lib/lastpass/parser.rb +58 -43
- data/lib/lastpass/session.rb +4 -2
- data/lib/lastpass/vault.rb +44 -18
- data/lib/lastpass/version.rb +1 -1
- data/spec/account_spec.rb +3 -1
- data/spec/blob_spec.rb +3 -1
- data/spec/fetcher_spec.rb +43 -17
- data/spec/http_spec.rb +17 -9
- data/spec/parser_spec.rb +10 -8
- data/spec/session_spec.rb +3 -1
- data/spec/test_data.rb +100 -100
- data/spec/vault_spec.rb +37 -1
- metadata +36 -64
- data/.ruby-version +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '09a65355723c0ba7300141aa42b691b35072efe71328f6095dce6580c4ff0ccd'
|
4
|
+
data.tar.gz: 3a18f05b3a62ef6fc42568956cc5a99f0bb229597795333363e54fadd036c107
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e08bffaa03731f26519611ea40b52aec82097e3421cda2e0b68ebd785fdafaf9e9e9d6bb39ca8ae4c8df606d43e417003032d006e6a8966591a6db1727073328
|
7
|
+
data.tar.gz: b49b1995780a93c08b87396e78cb8d6718e0920336cd4981c0421290cfaee653904aaca4af23573aa2458a51a8aeb8d4dc4d1e0775dd20410602bb188b7cd7b4
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
ruby: [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7]
|
16
|
+
steps:
|
17
|
+
- uses: actions/checkout@v2
|
18
|
+
- uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby }}
|
21
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
22
|
+
- run: bundle install
|
23
|
+
- run: bundle exec rake
|
data/.gitignore
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
coverage
|
4
|
-
example/credentials.yaml
|
1
|
+
/pkg/
|
2
|
+
/Gemfile.lock
|
3
|
+
/coverage
|
4
|
+
/example/credentials.yaml
|
5
|
+
/vendor/
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
Version 1.7.0
|
2
|
+
-------------
|
3
|
+
|
4
|
+
- Parse generic secure notes (thanks to Michael Chui @saraid)
|
5
|
+
- Parse and store secure notes for accounts (see `Account.note` property)
|
6
|
+
|
7
|
+
Version 1.6.1
|
8
|
+
-------------
|
9
|
+
|
10
|
+
- Obsolete URI.encode is replaced with URI.encode_www_form_component to
|
11
|
+
inhibit the warning
|
12
|
+
- Travic CI runs on all 2.* latest minor version releases (2.0.0 to 2.7.1)
|
13
|
+
|
14
|
+
Version 1.6.0
|
15
|
+
-------------
|
16
|
+
|
17
|
+
- Changed the way the private keys are parsed
|
18
|
+
- OpenSSL 1.1.0 support
|
19
|
+
- Bug fixes
|
20
|
+
|
21
|
+
Version 1.5.0
|
22
|
+
-------------
|
23
|
+
|
24
|
+
- Fixed failing `get_iteraction_count`. POST parameters are moved from the
|
25
|
+
query (URL) to the body.
|
26
|
+
- pbkdf2-ruby gem is no longer used as it was causing problems. Relying on
|
27
|
+
built-in `OpenSSL::PKCS5.pbkdf2_hmac`
|
28
|
+
- Minimum supported Ruby version is 2.0.0
|
29
|
+
- Dependencies updated to their laters versions
|
30
|
+
- Travis CI fixed
|
31
|
+
|
32
|
+
Version 1.4.0
|
33
|
+
-------------
|
34
|
+
|
35
|
+
- Added device id (IMEI/UUID) support
|
36
|
+
- Log out after fetching the blob to close the newly open session on LP server
|
37
|
+
to prevent triggering anti-hacking logic (hopefully)
|
38
|
+
- Verify that the recieved blob is marked with ENDM chunk and hasn't been
|
39
|
+
truncated in the process
|
40
|
+
|
41
|
+
|
1
42
|
Version 1.3.0
|
2
43
|
-------------
|
3
44
|
|
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
LastPass Ruby API
|
2
2
|
=================
|
3
3
|
|
4
|
-
[![Build Status](https://travis-ci.org/detunized/lastpass-ruby.
|
5
|
-
[![Coverage Status](https://coveralls.io/repos/detunized/lastpass-ruby/badge.
|
6
|
-
[![Code Climate](https://codeclimate.com/github/detunized/lastpass-ruby.
|
7
|
-
[![Dependency Status](https://gemnasium.com/detunized/lastpass-ruby.
|
4
|
+
[![Build Status](https://travis-ci.org/detunized/lastpass-ruby.svg?branch=master)](https://travis-ci.org/detunized/lastpass-ruby)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/detunized/lastpass-ruby/badge.svg?branch=master)](https://coveralls.io/r/detunized/lastpass-ruby?branch=master)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/detunized/lastpass-ruby.svg)](https://codeclimate.com/github/detunized/lastpass-ruby)
|
7
|
+
[![Dependency Status](https://gemnasium.com/detunized/lastpass-ruby.svg)](https://gemnasium.com/detunized/lastpass-ruby)
|
8
8
|
|
9
9
|
**This is unofficial LastPass API.**
|
10
10
|
|
11
|
-
There
|
11
|
+
There are also [a C#/.NET port](https://github.com/detunized/lastpass-sharp) and [a Python port](https://github.com/konomae/lastpass-python) available.
|
12
12
|
|
13
13
|
This library implements fetching and parsing of LastPass data. The library is
|
14
14
|
still in the proof of concept stage and doesn't support all LastPass features
|
data/Rakefile
CHANGED
data/example/example.rb
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
require "lastpass"
|
8
8
|
require "yaml"
|
9
9
|
|
10
|
+
DEVICE_ID = "example.rb"
|
11
|
+
|
10
12
|
credentials = YAML.load_file File.join File.dirname(__FILE__), "credentials.yaml"
|
11
13
|
|
12
14
|
username = credentials["username"]
|
@@ -14,21 +16,21 @@ password = credentials["password"]
|
|
14
16
|
|
15
17
|
begin
|
16
18
|
# First try without a multifactor password
|
17
|
-
vault = LastPass::Vault.open_remote username, password
|
19
|
+
vault = LastPass::Vault.open_remote username, password, nil, DEVICE_ID
|
18
20
|
rescue LastPass::LastPassIncorrectGoogleAuthenticatorCodeError => e
|
19
21
|
# Get the code
|
20
22
|
puts "Enter Google Authenticator code:"
|
21
23
|
multifactor_password = gets.chomp
|
22
24
|
|
23
25
|
# And now retry with the code
|
24
|
-
vault = LastPass::Vault.open_remote username, password, multifactor_password
|
26
|
+
vault = LastPass::Vault.open_remote username, password, multifactor_password, DEVICE_ID
|
25
27
|
rescue LastPass::LastPassIncorrectYubikeyPasswordError => e
|
26
28
|
# Get the password
|
27
29
|
puts "Enter Yubikey password:"
|
28
30
|
multifactor_password = gets.chomp
|
29
31
|
|
30
32
|
# And now retry with the Yubikey password
|
31
|
-
vault = LastPass::Vault.open_remote username, password, multifactor_password
|
33
|
+
vault = LastPass::Vault.open_remote username, password, multifactor_password, DEVICE_ID
|
32
34
|
end
|
33
35
|
|
34
36
|
vault.accounts.each_with_index do |i, index|
|
data/lastpass.gemspec
CHANGED
@@ -12,17 +12,16 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.email = "detunized@gmail.com"
|
13
13
|
s.homepage = "https://github.com/detunized/lastpass-ruby"
|
14
14
|
s.summary = "Unofficial LastPass API"
|
15
|
-
s.description = "
|
15
|
+
s.description = "Read only access to the online LastPass vault"
|
16
16
|
|
17
|
-
s.required_ruby_version = ">=
|
17
|
+
s.required_ruby_version = ">= 2.0.0"
|
18
18
|
|
19
|
-
s.add_dependency "httparty", "~> 0.
|
20
|
-
s.add_dependency "pbkdf2-ruby", "~> 0.2.0"
|
19
|
+
s.add_dependency "httparty", "~> 0.14.0"
|
21
20
|
|
22
|
-
s.add_development_dependency "rake", "~>
|
23
|
-
s.add_development_dependency "rspec", "~> 3.
|
24
|
-
s.add_development_dependency "rspec-its", "~> 1.
|
25
|
-
s.add_development_dependency "coveralls", "~> 0.
|
21
|
+
s.add_development_dependency "rake", "~> 12.0"
|
22
|
+
s.add_development_dependency "rspec", "~> 3.5"
|
23
|
+
s.add_development_dependency "rspec-its", "~> 1.2"
|
24
|
+
s.add_development_dependency "coveralls", "~> 0.8.19"
|
26
25
|
|
27
26
|
s.files = `git ls-files`.split "\n"
|
28
27
|
s.test_files = `git ls-files spec`.split "\n"
|
data/lib/lastpass.rb
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
require "base64"
|
5
5
|
require "httparty"
|
6
6
|
require "openssl"
|
7
|
-
require "pbkdf2"
|
8
7
|
require "stringio"
|
9
8
|
|
10
9
|
require "lastpass/account"
|
@@ -13,6 +12,7 @@ require "lastpass/chunk"
|
|
13
12
|
require "lastpass/exceptions"
|
14
13
|
require "lastpass/http"
|
15
14
|
require "lastpass/fetcher"
|
15
|
+
require "lastpass/note"
|
16
16
|
require "lastpass/parser"
|
17
17
|
require "lastpass/session"
|
18
18
|
require "lastpass/vault"
|
data/lib/lastpass/account.rb
CHANGED
@@ -8,14 +8,16 @@ module LastPass
|
|
8
8
|
:username,
|
9
9
|
:password,
|
10
10
|
:url,
|
11
|
+
:notes,
|
11
12
|
:group
|
12
13
|
|
13
|
-
def initialize id, name, username, password, url, group
|
14
|
+
def initialize id, name, username, password, url, notes, group
|
14
15
|
@id = id
|
15
16
|
@name = name
|
16
17
|
@username = username
|
17
18
|
@password = password
|
18
19
|
@url = url
|
20
|
+
@notes = notes
|
19
21
|
@group = group
|
20
22
|
end
|
21
23
|
end
|
data/lib/lastpass/blob.rb
CHANGED
@@ -4,11 +4,13 @@
|
|
4
4
|
module LastPass
|
5
5
|
class Blob
|
6
6
|
attr_reader :bytes,
|
7
|
-
:key_iteration_count
|
7
|
+
:key_iteration_count,
|
8
|
+
:encrypted_private_key
|
8
9
|
|
9
|
-
def initialize bytes, key_iteration_count
|
10
|
+
def initialize bytes, key_iteration_count, encrypted_private_key
|
10
11
|
@bytes = bytes
|
11
12
|
@key_iteration_count = key_iteration_count
|
13
|
+
@encrypted_private_key = encrypted_private_key
|
12
14
|
end
|
13
15
|
|
14
16
|
def encryption_key username, password
|
data/lib/lastpass/fetcher.rb
CHANGED
@@ -3,24 +3,33 @@
|
|
3
3
|
|
4
4
|
module LastPass
|
5
5
|
class Fetcher
|
6
|
-
def self.login username, password, multifactor_password = nil
|
6
|
+
def self.login username, password, multifactor_password = nil, client_id = nil
|
7
7
|
key_iteration_count = request_iteration_count username
|
8
|
-
request_login username, password, key_iteration_count, multifactor_password
|
8
|
+
request_login username, password, key_iteration_count, multifactor_password, client_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.logout session, web_client = http
|
12
|
+
response = web_client.get "https://lastpass.com/logout.php?method=cli&noredirect=1",
|
13
|
+
cookies: {"PHPSESSID" => URI.encode_www_form_component(session.id)}
|
14
|
+
|
15
|
+
raise NetworkError unless response.response.is_a? Net::HTTPOK
|
9
16
|
end
|
10
17
|
|
11
18
|
def self.fetch session, web_client = http
|
12
|
-
response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=
|
19
|
+
response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=cli",
|
13
20
|
format: :plain,
|
14
|
-
cookies: {"PHPSESSID" => URI.
|
21
|
+
cookies: {"PHPSESSID" => URI.encode_www_form_component(session.id)}
|
15
22
|
|
16
23
|
raise NetworkError unless response.response.is_a? Net::HTTPOK
|
17
24
|
|
18
|
-
Blob.new decode_blob(response.parsed_response),
|
25
|
+
Blob.new decode_blob(response.parsed_response),
|
26
|
+
session.key_iteration_count,
|
27
|
+
session.encrypted_private_key
|
19
28
|
end
|
20
29
|
|
21
30
|
def self.request_iteration_count username, web_client = http
|
22
31
|
response = web_client.post "https://lastpass.com/iterations.php",
|
23
|
-
|
32
|
+
body: {email: username}
|
24
33
|
|
25
34
|
raise NetworkError unless response.response.is_a? Net::HTTPOK
|
26
35
|
|
@@ -39,18 +48,20 @@ module LastPass
|
|
39
48
|
password,
|
40
49
|
key_iteration_count,
|
41
50
|
multifactor_password = nil,
|
51
|
+
client_id = nil,
|
42
52
|
web_client = http
|
43
53
|
|
44
54
|
body = {
|
45
|
-
method: "
|
46
|
-
|
47
|
-
xml: 1,
|
55
|
+
method: "cli",
|
56
|
+
xml: 2,
|
48
57
|
username: username,
|
49
58
|
hash: make_hash(username, password, key_iteration_count),
|
50
|
-
iterations: key_iteration_count
|
59
|
+
iterations: key_iteration_count,
|
60
|
+
includeprivatekeyenc: 1
|
51
61
|
}
|
52
62
|
|
53
63
|
body[:otp] = multifactor_password if multifactor_password
|
64
|
+
body[:imei] = client_id if client_id
|
54
65
|
|
55
66
|
response = web_client.post "https://lastpass.com/login.php",
|
56
67
|
format: :xml,
|
@@ -66,11 +77,14 @@ module LastPass
|
|
66
77
|
end
|
67
78
|
|
68
79
|
def self.create_session parsed_response, key_iteration_count
|
69
|
-
ok = parsed_response["ok"]
|
80
|
+
ok = (parsed_response["response"] || {})["ok"]
|
70
81
|
if ok.is_a? Hash
|
71
82
|
session_id = ok["sessionid"]
|
72
83
|
if session_id.is_a? String
|
73
|
-
|
84
|
+
private_key = ok["privatekeyenc"]
|
85
|
+
private_key = nil if private_key == ""
|
86
|
+
|
87
|
+
return Session.new session_id, key_iteration_count, private_key
|
74
88
|
end
|
75
89
|
end
|
76
90
|
|
@@ -86,7 +100,7 @@ module LastPass
|
|
86
100
|
"unknownpassword" => LastPassInvalidPasswordError,
|
87
101
|
"googleauthrequired" => LastPassIncorrectGoogleAuthenticatorCodeError,
|
88
102
|
"googleauthfailed" => LastPassIncorrectGoogleAuthenticatorCodeError,
|
89
|
-
"
|
103
|
+
"otprequired" => LastPassIncorrectYubikeyPasswordError,
|
90
104
|
}
|
91
105
|
|
92
106
|
cause = error["cause"]
|
@@ -108,13 +122,7 @@ module LastPass
|
|
108
122
|
if key_iteration_count == 1
|
109
123
|
Digest::SHA256.digest username + password
|
110
124
|
else
|
111
|
-
|
112
|
-
.new(password: password,
|
113
|
-
salt: username,
|
114
|
-
iterations: key_iteration_count,
|
115
|
-
key_length: 32)
|
116
|
-
.bin_string
|
117
|
-
.force_encoding "BINARY"
|
125
|
+
OpenSSL::PKCS5.pbkdf2_hmac password, username, key_iteration_count, 32, "sha256"
|
118
126
|
end
|
119
127
|
end
|
120
128
|
|
@@ -122,12 +130,11 @@ module LastPass
|
|
122
130
|
if key_iteration_count == 1
|
123
131
|
Digest::SHA256.hexdigest Digest.hexencode(make_key(username, password, 1)) + password
|
124
132
|
else
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
.hex_string
|
133
|
+
Digest.hexencode OpenSSL::PKCS5.pbkdf2_hmac make_key(username, password, key_iteration_count),
|
134
|
+
password,
|
135
|
+
1,
|
136
|
+
32,
|
137
|
+
"sha256"
|
131
138
|
end
|
132
139
|
end
|
133
140
|
|
data/lib/lastpass/http.rb
CHANGED
data/lib/lastpass/parser.rb
CHANGED
@@ -7,7 +7,7 @@ module LastPass
|
|
7
7
|
RSA_PKCS1_OAEP_PADDING = 4
|
8
8
|
|
9
9
|
# Secure note types that contain account-like information
|
10
|
-
|
10
|
+
ACCOUNT_LIKE_SECURE_NOTE_TYPES = {
|
11
11
|
"Server" => true,
|
12
12
|
"Email Account" => true,
|
13
13
|
"Database" => true,
|
@@ -28,9 +28,9 @@ module LastPass
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Parses an account chunk, decrypts and creates an Account object.
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# information.
|
31
|
+
# Returns either an Account or a Note object, in case of a generic
|
32
|
+
# note that doesn't represent an account. All secure notes are ACCTs
|
33
|
+
# but not all of them store account information.
|
34
34
|
#
|
35
35
|
# TODO: Make a test case that covers secure note account
|
36
36
|
def self.parse_ACCT chunk, encryption_key
|
@@ -48,44 +48,20 @@ module LastPass
|
|
48
48
|
|
49
49
|
# Parse secure note
|
50
50
|
if secure_note == "1"
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if !ALLOWED_SECURE_NOTE_TYPES.key? secure_note_type
|
55
|
-
return nil
|
51
|
+
parsed = parse_secure_note_server notes
|
52
|
+
if !ACCOUNT_LIKE_SECURE_NOTE_TYPES.key? parsed[:type]
|
53
|
+
return Note.new id, name, notes, group
|
56
54
|
end
|
57
55
|
|
58
|
-
url
|
56
|
+
url = parsed[:url] if parsed.key? :url
|
57
|
+
username = parsed[:username] if parsed.key? :username
|
58
|
+
password = parsed[:password] if parsed.key? :password
|
59
59
|
end
|
60
60
|
|
61
|
-
Account.new id, name, username, password, url, group
|
61
|
+
Account.new id, name, username, password, url, notes, group
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
# Parse PRIK chunk which contains private RSA key
|
66
|
-
def self.parse_PRIK chunk, encryption_key
|
67
|
-
decrypted = decode_aes256 "cbc",
|
68
|
-
encryption_key[0, 16],
|
69
|
-
decode_hex(chunk.payload),
|
70
|
-
encryption_key
|
71
|
-
|
72
|
-
/^LastPassPrivateKey<(?<hex_key>.*)>LastPassPrivateKey$/ =~ decrypted
|
73
|
-
asn1_encoded_all = OpenSSL::ASN1.decode decode_hex hex_key
|
74
|
-
asn1_encoded_key = OpenSSL::ASN1.decode asn1_encoded_all.value[2].value
|
75
|
-
|
76
|
-
rsa_key = OpenSSL::PKey::RSA.new
|
77
|
-
rsa_key.n = asn1_encoded_key.value[1].value
|
78
|
-
rsa_key.e = asn1_encoded_key.value[2].value
|
79
|
-
rsa_key.d = asn1_encoded_key.value[3].value
|
80
|
-
rsa_key.p = asn1_encoded_key.value[4].value
|
81
|
-
rsa_key.q = asn1_encoded_key.value[5].value
|
82
|
-
rsa_key.dmp1 = asn1_encoded_key.value[6].value
|
83
|
-
rsa_key.dmq1 = asn1_encoded_key.value[7].value
|
84
|
-
rsa_key.iqmp = asn1_encoded_key.value[8].value
|
85
|
-
|
86
|
-
rsa_key
|
87
|
-
end
|
88
|
-
|
89
65
|
# TODO: Fake some data and make a test
|
90
66
|
def self.parse_SHAR chunk, encryption_key, rsa_key
|
91
67
|
StringIO.open chunk.payload do |io|
|
@@ -112,24 +88,63 @@ module LastPass
|
|
112
88
|
end
|
113
89
|
end
|
114
90
|
|
91
|
+
# Parse and decrypt the encrypted private RSA key
|
92
|
+
def self.parse_private_key encrypted_private_key, encryption_key
|
93
|
+
decrypted = decode_aes256 "cbc",
|
94
|
+
encryption_key[0, 16],
|
95
|
+
decode_hex(encrypted_private_key),
|
96
|
+
encryption_key
|
97
|
+
|
98
|
+
/^LastPassPrivateKey<(?<hex_key>.*)>LastPassPrivateKey$/ =~ decrypted
|
99
|
+
asn1_encoded_all = OpenSSL::ASN1.decode decode_hex hex_key
|
100
|
+
asn1_encoded_key = OpenSSL::ASN1.decode asn1_encoded_all.value[2].value
|
101
|
+
|
102
|
+
rsa_key = OpenSSL::PKey::RSA.new
|
103
|
+
n = asn1_encoded_key.value[1].value
|
104
|
+
e = asn1_encoded_key.value[2].value
|
105
|
+
d = asn1_encoded_key.value[3].value
|
106
|
+
p = asn1_encoded_key.value[4].value
|
107
|
+
q = asn1_encoded_key.value[5].value
|
108
|
+
dmp1 = asn1_encoded_key.value[6].value
|
109
|
+
dmq1 = asn1_encoded_key.value[7].value
|
110
|
+
iqmp = asn1_encoded_key.value[8].value
|
111
|
+
|
112
|
+
if rsa_key.respond_to? :set_key
|
113
|
+
rsa_key.set_key n, e, d
|
114
|
+
rsa_key.set_factors p, q
|
115
|
+
rsa_key.set_crt_params dmp1, dmq1, iqmp
|
116
|
+
else
|
117
|
+
rsa_key.n = n
|
118
|
+
rsa_key.e = e
|
119
|
+
rsa_key.d = d
|
120
|
+
rsa_key.p = p
|
121
|
+
rsa_key.q = q
|
122
|
+
rsa_key.dmp1 = dmp1
|
123
|
+
rsa_key.dmq1 = dmq1
|
124
|
+
rsa_key.iqmp = iqmp
|
125
|
+
end
|
126
|
+
|
127
|
+
rsa_key
|
128
|
+
end
|
129
|
+
|
115
130
|
def self.parse_secure_note_server notes
|
116
|
-
|
117
|
-
username = nil
|
118
|
-
password = nil
|
131
|
+
info = {}
|
119
132
|
|
120
133
|
notes.split("\n").each do |i|
|
121
134
|
key, value = i.split ":", 2
|
122
135
|
case key
|
136
|
+
when "NoteType"
|
137
|
+
info[:type] = value
|
123
138
|
when "Hostname"
|
124
|
-
url = value
|
139
|
+
info[:url] = value
|
125
140
|
when "Username"
|
126
|
-
username = value
|
141
|
+
info[:username] = value
|
127
142
|
when "Password"
|
128
|
-
password = value
|
143
|
+
info[:password] = value
|
129
144
|
end
|
130
145
|
end
|
131
146
|
|
132
|
-
|
147
|
+
info
|
133
148
|
end
|
134
149
|
|
135
150
|
# Reads one chunk from a stream and creates a Chunk object with the data read.
|
@@ -275,7 +290,7 @@ module LastPass
|
|
275
290
|
# Allowed ciphers are: :ecb, :cbc.
|
276
291
|
# If for :ecb iv is not used and should be set to "".
|
277
292
|
def self.decode_aes256 cipher, iv, data, encryption_key
|
278
|
-
aes = OpenSSL::Cipher
|
293
|
+
aes = OpenSSL::Cipher.new "aes-256-#{cipher}"
|
279
294
|
aes.decrypt
|
280
295
|
aes.key = encryption_key
|
281
296
|
aes.iv = iv
|