rubeepass 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rpass +26 -12
- data/lib/rubeepass.rb +73 -28
- data/lib/rubeepass/error.rb +1 -1
- data/lib/rubeepass/error/not_supported.rb +5 -0
- metadata +3 -3
- data/lib/rubeepass/error/not_aes.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6389189519412fd7b336eea64280403924c313955e78f3b6eaea377303a3552a
|
4
|
+
data.tar.gz: d4c77407fa1c2b92764f2dc314e8ac31c472b0c9c01a9c3158bca3a08ddecc8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c90641b9ff5afcf3272464a4c2a45383d48c648869eb5d485ff593af5838aca8d137a77c2006a0a3cc2d446b89cee2d30308190154a913df341f3c4db87b1cdd
|
7
|
+
data.tar.gz: 380cb82f98469fe27e4a7ab4d21883835d9855b78f863a40d2a2fc4eec50ac0119043200545fa94b9148d72be34692d5010330bb09690154c9f5ae14f0e148e3
|
data/bin/rpass
CHANGED
@@ -77,10 +77,10 @@ def parse(args)
|
|
77
77
|
|
78
78
|
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] [kdbx]"
|
79
79
|
|
80
|
-
opts.on("")
|
80
|
+
opts.on("", "DESCRIPTION")
|
81
81
|
|
82
|
-
info.scan(/\S.{0,
|
83
|
-
opts.on("#{line}")
|
82
|
+
info.scan(/\S.{0,66}\S(?=\s|$)|\S+/).each do |line|
|
83
|
+
opts.on(" #{line}")
|
84
84
|
end
|
85
85
|
|
86
86
|
opts.on("", "OPTIONS")
|
@@ -148,6 +148,13 @@ def parse(args)
|
|
148
148
|
options["verbose"] = true
|
149
149
|
end
|
150
150
|
|
151
|
+
opts.on("-V", "--version", "Show version") do
|
152
|
+
__FILE__.match(/rubeepass-(\d+\.\d+\.\d+)/) do |m|
|
153
|
+
puts m[1]
|
154
|
+
end
|
155
|
+
exit RubeePassExit::GOOD
|
156
|
+
end
|
157
|
+
|
151
158
|
opts.on(
|
152
159
|
"",
|
153
160
|
"FORMATS",
|
@@ -295,24 +302,31 @@ rescue SystemExit
|
|
295
302
|
# Quit from djinni
|
296
303
|
# Exit gracefully
|
297
304
|
rescue Interrupt
|
298
|
-
# ^C
|
299
|
-
# Exit gracefully
|
305
|
+
# Exit gracefully on ^C
|
300
306
|
rescue Errno::EPIPE
|
301
307
|
# Do nothing. This can happen if piping to another program such as
|
302
308
|
# less. Usually if less is closed before we're done with STDOUT.
|
303
309
|
rescue RubeePass::Error => e
|
304
|
-
puts e.message
|
310
|
+
$stderr.puts e.message.red
|
311
|
+
if (options["verbose"])
|
312
|
+
e.backtrace.each do |line|
|
313
|
+
$stderr.puts line.yellow
|
314
|
+
end
|
315
|
+
end
|
305
316
|
exit RubeePassExit::EXCEPTION
|
306
317
|
rescue Exception => e
|
307
|
-
$stderr.puts
|
308
|
-
|
309
|
-
"
|
318
|
+
$stderr.puts [
|
319
|
+
"Oops! Looks like an error has occured! If the error",
|
320
|
+
"persists, file a bug at:"
|
321
|
+
].join(" ").wrap
|
310
322
|
$stderr.puts
|
311
323
|
$stderr.puts " https://gitlab.com/mjwhitta/rubeepass/issues"
|
312
324
|
$stderr.puts
|
313
|
-
$stderr.puts
|
314
|
-
"
|
315
|
-
|
325
|
+
$stderr.puts [
|
326
|
+
"Maybe the message below will help. If not, you can use the",
|
327
|
+
"--verbose flag to get a backtrace."
|
328
|
+
].join(" ").wrap
|
329
|
+
$stderr.puts
|
316
330
|
|
317
331
|
$stderr.puts e.message.white.on_red
|
318
332
|
if (options["verbose"])
|
data/lib/rubeepass.rb
CHANGED
@@ -10,6 +10,7 @@ require "uri"
|
|
10
10
|
require "zlib"
|
11
11
|
|
12
12
|
class RubeePass
|
13
|
+
# Header fields
|
13
14
|
@@END_OF_HEADER = 0
|
14
15
|
@@COMMENT = 1
|
15
16
|
@@CIPHER_ID = 2
|
@@ -22,10 +23,19 @@ class RubeePass
|
|
22
23
|
@@STREAM_START_BYTES = 9
|
23
24
|
@@INNER_RANDOM_STREAM_ID = 10
|
24
25
|
|
26
|
+
# Magic values
|
25
27
|
@@MAGIC_SIG1 = 0x9aa2d903
|
26
28
|
@@MAGIC_SIG2 = 0xb54bfb67
|
27
29
|
@@VERSION = 0x00030000
|
28
30
|
|
31
|
+
# Encryption schemes
|
32
|
+
@@AES_AESKDF3 = "31c1f2e6bf714350be5805216afc5aff"
|
33
|
+
@@AES_AESKDF4_OR_ARGON2 = "000031c1f2e6bf714350be5805216afc"
|
34
|
+
@@CHACHA20_AESKDF3 = "d6038a2b8b6f4cb5a524339a31dbb59a"
|
35
|
+
@@CHACHA20_AESKDF4_OR_ARGON2 = "0000d6038a2b8b6f4cb5a524339a31db"
|
36
|
+
@@TWOFISH_AESKDF3 = "ad68f29f576f4bb9a36ad47af965346c"
|
37
|
+
@@TWOFISH_AESKDF4_OR_ARGON2 = "0000ad68f29f576f4bb9a36ad47af965"
|
38
|
+
|
29
39
|
attr_reader :attachment_decoder
|
30
40
|
attr_reader :db
|
31
41
|
attr_reader :gzip
|
@@ -135,23 +145,43 @@ class RubeePass
|
|
135
145
|
end
|
136
146
|
end
|
137
147
|
|
138
|
-
def
|
148
|
+
def derive_aeskdf3_key(header)
|
149
|
+
irsi = "\x02\x00\x00\x00"
|
150
|
+
if (
|
151
|
+
(header[@@MASTER_SEED].length != 32) ||
|
152
|
+
(header[@@TRANSFORM_SEED].length != 32)
|
153
|
+
)
|
154
|
+
raise Error::InvalidHeader.new
|
155
|
+
elsif (header[@@INNER_RANDOM_STREAM_ID] != irsi)
|
156
|
+
raise Error::NotSalsa.new
|
157
|
+
end
|
158
|
+
|
139
159
|
cipher = OpenSSL::Cipher::AES.new(256, :ECB)
|
140
160
|
cipher.encrypt
|
141
161
|
cipher.key = @header[@@TRANSFORM_SEED]
|
142
162
|
cipher.padding = 0
|
143
163
|
|
164
|
+
key = @initial_key
|
144
165
|
@header[@@TRANSFORM_ROUNDS].times do
|
145
|
-
|
166
|
+
key = cipher.update(key) + cipher.final
|
146
167
|
end
|
147
168
|
|
148
|
-
transform_key = Digest::SHA256::digest(
|
169
|
+
transform_key = Digest::SHA256::digest(key)
|
149
170
|
combined_key = @header[@@MASTER_SEED] + transform_key
|
150
171
|
|
151
|
-
@
|
152
|
-
@
|
172
|
+
@cipher = OpenSSL::Cipher::AES.new(256, :CBC)
|
173
|
+
@key = Digest::SHA256::digest(combined_key)
|
174
|
+
@iv = @header[@@ENCRYPTION_IV]
|
153
175
|
end
|
154
|
-
private :
|
176
|
+
private :derive_aeskdf3_key
|
177
|
+
|
178
|
+
def derive_aeskdf4_or_argon2_key(header)
|
179
|
+
# require "pry"
|
180
|
+
# binding.pry
|
181
|
+
# puts "AES with AES-KDF4 or Argon2"
|
182
|
+
raise Error::NotSupported.new # TODO
|
183
|
+
end
|
184
|
+
private :derive_aeskdf4_or_argon2_key
|
155
185
|
|
156
186
|
def export(export_file, format)
|
157
187
|
start_opening
|
@@ -251,7 +281,7 @@ class RubeePass
|
|
251
281
|
end
|
252
282
|
end
|
253
283
|
|
254
|
-
@
|
284
|
+
@initial_key = Digest::SHA256.digest(passhash + filehash)
|
255
285
|
end
|
256
286
|
private :join_key_and_keyfile
|
257
287
|
|
@@ -336,6 +366,31 @@ class RubeePass
|
|
336
366
|
end
|
337
367
|
private :parse_gzip
|
338
368
|
|
369
|
+
def parse_header(header)
|
370
|
+
case header[@@CIPHER_ID].unpack("H*")[0]
|
371
|
+
when @@AES_AESKDF3
|
372
|
+
derive_aeskdf3_key(header)
|
373
|
+
when @@AES_AESKDF4_OR_ARGON2
|
374
|
+
derive_aeskdf4_or_argon2_key(header)
|
375
|
+
when @@CHACHA20_AESKDF3
|
376
|
+
# puts "ChaCha20 with AES-KDF3"
|
377
|
+
raise Error::NotSupported.new # TODO
|
378
|
+
when @@CHACHA20_AESKDF4_OR_ARGON2
|
379
|
+
# puts "ChaCha20 with AES-KDF4 or Argon2"
|
380
|
+
raise Error::NotSupported.new # TODO
|
381
|
+
when @@TWOFISH_AESKDF3
|
382
|
+
# puts "Twofish with AES-KDF3"
|
383
|
+
raise Error::NotSupported.new # TODO
|
384
|
+
when @@TWOFISH_AESKDF4_OR_ARGON2
|
385
|
+
# puts "Twofish with AES-KDF4 or Argon2"
|
386
|
+
raise Error::NotSupported.new # TODO
|
387
|
+
else
|
388
|
+
# puts header[@@CIPHER_ID].unpack("H*")[0]
|
389
|
+
raise Error::NotSupported.new
|
390
|
+
end
|
391
|
+
end
|
392
|
+
private :parse_header
|
393
|
+
|
339
394
|
def parse_xml
|
340
395
|
doc = REXML::Document.new(@xml)
|
341
396
|
if (doc.elements["KeePassFile/Root"].nil?)
|
@@ -352,10 +407,10 @@ class RubeePass
|
|
352
407
|
private :parse_xml
|
353
408
|
|
354
409
|
def read_gzip(file)
|
355
|
-
cipher =
|
410
|
+
cipher = @cipher.clone
|
356
411
|
cipher.decrypt
|
357
|
-
cipher.key = @
|
358
|
-
cipher.iv = @
|
412
|
+
cipher.key = @key
|
413
|
+
cipher.iv = @iv
|
359
414
|
|
360
415
|
encrypted = file.read
|
361
416
|
|
@@ -379,7 +434,7 @@ class RubeePass
|
|
379
434
|
header = Hash.new
|
380
435
|
loop do
|
381
436
|
data = file.read(1)
|
382
|
-
|
437
|
+
break if (data.nil?)
|
383
438
|
id = data.unpack("C*")[0]
|
384
439
|
|
385
440
|
data = file.read(2)
|
@@ -387,6 +442,9 @@ class RubeePass
|
|
387
442
|
size = data.unpack("S*")[0]
|
388
443
|
|
389
444
|
data = file.read(size)
|
445
|
+
if (data.nil? && (size > 0))
|
446
|
+
raise Error::InvalidHeader.new
|
447
|
+
end
|
390
448
|
|
391
449
|
case id
|
392
450
|
when @@END_OF_HEADER
|
@@ -398,19 +456,6 @@ class RubeePass
|
|
398
456
|
end
|
399
457
|
end
|
400
458
|
|
401
|
-
irsi = "\x02\x00\x00\x00"
|
402
|
-
aes = "31c1f2e6bf714350be5805216afc5aff"
|
403
|
-
if (
|
404
|
-
(header[@@MASTER_SEED].length != 32) ||
|
405
|
-
(header[@@TRANSFORM_SEED].length != 32)
|
406
|
-
)
|
407
|
-
raise Error::InvalidHeader.new
|
408
|
-
elsif (header[@@INNER_RANDOM_STREAM_ID] != irsi)
|
409
|
-
raise Error::NotSalsa.new
|
410
|
-
elsif (header[@@CIPHER_ID].unpack("H*")[0] != aes)
|
411
|
-
raise Error::NotAES.new
|
412
|
-
end
|
413
|
-
|
414
459
|
@header = header
|
415
460
|
end
|
416
461
|
private :read_header
|
@@ -436,20 +481,20 @@ class RubeePass
|
|
436
481
|
private :read_magic_and_version
|
437
482
|
|
438
483
|
def start_opening
|
439
|
-
@aes_iv = nil
|
440
|
-
@aes_key = nil
|
441
484
|
@db = nil
|
442
485
|
@gzip = nil
|
443
486
|
@header = nil
|
487
|
+
@initial_key = nil
|
488
|
+
@iv = nil
|
444
489
|
@key = nil
|
445
490
|
@xml = nil
|
446
491
|
|
447
492
|
file = File.open(@kdbx)
|
448
493
|
|
449
494
|
read_magic_and_version(file)
|
450
|
-
read_header(file)
|
495
|
+
header = read_header(file)
|
451
496
|
join_key_and_keyfile
|
452
|
-
|
497
|
+
parse_header(header)
|
453
498
|
read_gzip(file)
|
454
499
|
|
455
500
|
file.close
|
data/lib/rubeepass/error.rb
CHANGED
@@ -10,5 +10,5 @@ require "rubeepass/error/invalid_protected_data"
|
|
10
10
|
require "rubeepass/error/invalid_protected_stream_key"
|
11
11
|
require "rubeepass/error/invalid_version"
|
12
12
|
require "rubeepass/error/invalid_xml"
|
13
|
-
require "rubeepass/error/not_aes"
|
14
13
|
require "rubeepass/error/not_salsa20"
|
14
|
+
require "rubeepass/error/not_supported"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubeepass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Whittaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -192,8 +192,8 @@ files:
|
|
192
192
|
- lib/rubeepass/error/invalid_protected_stream_key.rb
|
193
193
|
- lib/rubeepass/error/invalid_version.rb
|
194
194
|
- lib/rubeepass/error/invalid_xml.rb
|
195
|
-
- lib/rubeepass/error/not_aes.rb
|
196
195
|
- lib/rubeepass/error/not_salsa20.rb
|
196
|
+
- lib/rubeepass/error/not_supported.rb
|
197
197
|
- lib/rubeepass/group.rb
|
198
198
|
- lib/rubeepass/protected_decryptor.rb
|
199
199
|
- lib/rubeepass/wish/cd_wish.rb
|