onepass 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 780ae33029de7cf60dfa6a1b16feb41dbff4c4e7
4
- data.tar.gz: 087efe99c57afbc5e782b01b7dfd1774c30b731f
3
+ metadata.gz: f081e63d2a0fc4f35b2ca7698facbc79a27dbe68
4
+ data.tar.gz: 26e4b49e1e270d90ae4c00262d4b0d0bd68cf3fa
5
5
  SHA512:
6
- metadata.gz: 01fa89e1b5ee6a87c8ebd1cab37f88c4f98fc0fb638ad52f7b0d8e96d3799778c67c90a7dcf47ad4b41cecbbac53c481166b6ab06af865668932ce66f84df954
7
- data.tar.gz: 4ae603513c043f6545973729efcc40d3e1863e2566d725b05d1aa9ab5356f8538e5fdd6c8c6a38a768eb5d1b7c5f5b9fb27553e20fabfa6d435f7ab57b4884cd
6
+ metadata.gz: fa0258a8c9ab35aeba1062fbe697f7f46172d2d355158080d80597c7246d21225d32a32bf42a7315bfb29df1ccf8fe52a4dc03e17c7d488c04119d43602b12a1
7
+ data.tar.gz: 1f16989a6776547b046f6c80eb3075186c0c9c76297061c23b14debb9215cb8211298563f741db47fc6cbff7316690cbd7c5b0e4f326ff308b7bfb3f2f13ff99
data/OnePass.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "sqlite3", "~> 1.3.9"
22
+ spec.add_dependency "CFPropertyList"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.7"
24
25
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,3 +1,3 @@
1
1
  module OnePass
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/OnePass.rb CHANGED
@@ -3,6 +3,7 @@ require "openssl"
3
3
  require "sqlite3"
4
4
  require "json"
5
5
  require "tempfile"
6
+ require "cfpropertylist"
6
7
 
7
8
  module OnePass
8
9
  class VerifyException < Exception
@@ -18,7 +19,7 @@ module OnePass
18
19
  if buf[0..7] != "opdata01"
19
20
  raise OnePass::Opdata::InvalidException.new("Header was incorrect")
20
21
  end
21
- @length = buf[8..15].unpack("V")[0]
22
+ @length = buf[8..15].unpack("Q<")[0]
22
23
  @mac = buf[-32..-1]
23
24
  if OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, mac, buf[0..-33]) != @mac
24
25
  raise OnePass::VerifyException.new("MAC doesn't match; verify failed. Check your encryption/mac keys.")
@@ -60,33 +61,48 @@ module OnePass
60
61
  db = SQLite3::Database.new(sqlite_file)
61
62
  db.execute "VACUUM;"
62
63
 
63
- # read profile data
64
+ @master_keys = []
65
+ @overview_keys = []
64
66
  @overviews = []
65
- @masters = []
66
- db.execute "SELECT id,master_key_data,overview_key_data,salt,iterations FROM profiles" do |profile|
67
-
68
- # derive the key from the password
69
- derived_key = OpenSSL::PKCS5.pbkdf2_hmac(master_password, profile[3], profile[4], 64, OpenSSL::Digest::SHA512.new)
70
- derived_encryption_key = derived_key[0..31]
71
- derived_mac_key = derived_key[32..-1]
72
-
73
- # try to unlock profile data. return fail if failed login
74
- overview_key_data = OnePass::Opdata.new(profile[2], derived_encryption_key, derived_mac_key)
75
- overview_key = OpenSSL::Digest::SHA512.new.digest(overview_key_data.data)
76
- overview_encryption_key, overview_mac_key = overview_key[0..31], overview_key[32..-1]
77
-
78
- # load overview opdata into object based format. overviews are stored decrypted for use later.
79
- # the encrypted data for the keys is included, but is not decrypted unless requested later
80
- db.execute "SELECT items.key_data, items.overview_data, item_details.data FROM items INNER JOIN item_details ON items.id=item_details.item_id WHERE items.profile_id=#{profile[0]};" do |row|
81
- overview = OnePass::Opdata.new(row[1], overview_encryption_key, overview_mac_key)
82
- json = JSON.parse(overview.data).merge({profile: profile[0], key_data: row[0], data: row[2]})
83
- @overviews << json
84
- end
85
-
86
- # decrypt the master key for use later
87
- master_key_data = OnePass::Opdata.new(profile[1], derived_encryption_key, derived_mac_key)
88
- master_key = OpenSSL::Digest::SHA512.new.digest(master_key_data.data)
89
- @masters[profile[0]] = {enc_key: master_key[0..31], mac_key: master_key[32..-1]}
67
+ # read master profile
68
+ master_profile = db.execute "SELECT id,master_key_data,overview_key_data,salt,iterations FROM profiles WHERE attributes_data IS NULL"
69
+ raise "Found more than one master profile!" unless master_profile.length == 1
70
+ master_profile.flatten!
71
+ master_profile_id = master_profile[0]
72
+
73
+ # derive the key from the password
74
+ derived_key = OpenSSL::PKCS5.pbkdf2_hmac(master_password, master_profile[3], master_profile[4], 64, OpenSSL::Digest::SHA512.new)
75
+ derived_encryption_key = derived_key[0..31]
76
+ derived_mac_key = derived_key[32..-1]
77
+
78
+ # Obtain the master profile master keys
79
+ master_key_data = OnePass::Opdata.new(master_profile[1], derived_encryption_key, derived_mac_key)
80
+ master_key = OpenSSL::Digest::SHA512.new.digest(master_key_data.data)
81
+ @master_keys[master_profile_id] = {enc_key: master_key[0..31], mac_key: master_key[32..-1]}
82
+
83
+ # Obtain the master profile overview keys
84
+ overview_key_data = OnePass::Opdata.new(master_profile[2], derived_encryption_key, derived_mac_key)
85
+ overview_key = OpenSSL::Digest::SHA512.new.digest(overview_key_data.data)
86
+ @overview_keys[master_profile_id] = { enc_key: overview_key[0..31], mac_key: overview_key[32..-1] }
87
+
88
+ # Obtain keys for remaining profiles
89
+ db.execute "SELECT id,attributes_data FROM profiles WHERE attributes_data IS NOT NULL" do |profile|
90
+ attributes_data = OnePass::Opdata.new(profile[1], @overview_keys[master_profile_id][:enc_key], @overview_keys[master_profile_id][:mac_key])
91
+ plist = CFPropertyList.native_types(CFPropertyList::List.new(:data => attributes_data.data).value)
92
+ overview_key_data = plist['$objects'][plist['$top']['overviewKey']]
93
+ overview_key = OpenSSL::Digest::SHA512.new.digest(overview_key_data)
94
+ @overview_keys[profile[0]] = { enc_key: overview_key[0..31], mac_key: overview_key[32..-1] }
95
+ master_key_data = plist['$objects'][plist['$top']['masterKey']]
96
+ master_key = OpenSSL::Digest::SHA512.new.digest(master_key_data)
97
+ @master_keys[profile[0]] = { enc_key: master_key[0..31], mac_key: master_key[32..-1] }
98
+ end
99
+
100
+ # load overview opdata into object based format. overviews are stored decrypted for use later.
101
+ # the encrypted data for the keys is included, but is not decrypted unless requested later
102
+ db.execute "SELECT items.profile_id, items.key_data, items.overview_data, item_details.data FROM items INNER JOIN item_details ON items.id=item_details.item_id" do |item|
103
+ overview = OnePass::Opdata.new(item[2], @overview_keys[item[0]][:enc_key], @overview_keys[item[0]][:mac_key])
104
+ json = JSON.parse(overview.data).merge({profile: item[0], key_data: item[1], data: item[3]})
105
+ @overviews << json
90
106
  end
91
107
 
92
108
  db.close
@@ -104,20 +120,26 @@ module OnePass
104
120
  return nil
105
121
  end
106
122
 
107
- def decrypt(overview)
123
+ def decrypt(overview, all = nil)
108
124
  key_data = overview[:key_data][0..-33]
109
125
  mac = overview[:key_data][-32..-1]
110
126
  profile = overview[:profile]
111
- if OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, @masters[profile][:mac_key], key_data) != mac
127
+ if OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, @master_keys[profile][:mac_key], key_data) != mac
112
128
  raise VerifyException.new("The item's encryption key couldn't be verified.")
113
129
  end
114
130
  cipher = OpenSSL::Cipher::AES.new(256, :CBC)
115
131
  cipher.decrypt
116
132
  cipher.padding = 0
117
133
  cipher.iv = key_data[0..15]
118
- cipher.key = @masters[profile][:enc_key]
134
+ cipher.key = @master_keys[profile][:enc_key]
119
135
  key_data = cipher.update(key_data[16..-1]) + cipher.final
120
- return JSON.parse(OnePass::Opdata.new(overview[:data],key_data[0..31],key_data[32..-1]).data)["password"]
136
+ results = JSON.parse(OnePass::Opdata.new(overview[:data],key_data[0..31],key_data[32..-1]).data)
137
+ password = if results.has_key?("password")
138
+ results["password"]
139
+ elsif results.has_key?("fields")
140
+ results["fields"].find { |h| h["designation"] == "password" }["value"]
141
+ end
142
+ return all ? results : password
121
143
  end
122
144
  end
123
145
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onepass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kai Lieth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-10 00:00:00.000000000 Z
11
+ date: 2015-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.3.9
27
+ - !ruby/object:Gem::Dependency
28
+ name: CFPropertyList
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -104,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
118
  version: '0'
105
119
  requirements: []
106
120
  rubyforge_project:
107
- rubygems_version: 2.4.2
121
+ rubygems_version: 2.4.6
108
122
  signing_key:
109
123
  specification_version: 4
110
124
  summary: Decrypt the secrets stored in 1Password 4