rubeepass 3.2.0 → 3.3.0

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
  SHA256:
3
- metadata.gz: 6389189519412fd7b336eea64280403924c313955e78f3b6eaea377303a3552a
4
- data.tar.gz: d4c77407fa1c2b92764f2dc314e8ac31c472b0c9c01a9c3158bca3a08ddecc8d
3
+ metadata.gz: 5ed30495bfd8a7608b35323c3869c6125ab65d823322a2d8c353260a251430ff
4
+ data.tar.gz: a278f095195446d1d8e892b25e674945f4ed377caf3b56eaa0a3b818e13521b0
5
5
  SHA512:
6
- metadata.gz: c90641b9ff5afcf3272464a4c2a45383d48c648869eb5d485ff593af5838aca8d137a77c2006a0a3cc2d446b89cee2d30308190154a913df341f3c4db87b1cdd
7
- data.tar.gz: 380cb82f98469fe27e4a7ab4d21883835d9855b78f863a40d2a2fc4eec50ac0119043200545fa94b9148d72be34692d5010330bb09690154c9f5ae14f0e148e3
6
+ metadata.gz: 9386f560553334d3ecacd4d06fa183e1e68ddee4d1353011b928ebc109f8eaad54ffe635c66b713afb9cd5b3493ced91b48f1e6873135848e3c91c85373bf749
7
+ data.tar.gz: 0fc3c5fdce2ab15331a927e11e59585d2bf3122b6b796c23f345d7e983adfda564acf15b90fcf7d1933a016ee56bf7a638a2db492c66cc10341641870725a16b
data/lib/rubeepass.rb CHANGED
@@ -11,34 +11,48 @@ require "zlib"
11
11
 
12
12
  class RubeePass
13
13
  # Header fields
14
- @@END_OF_HEADER = 0
15
- @@COMMENT = 1
16
- @@CIPHER_ID = 2
17
- @@COMPRESSION = 3
18
- @@MASTER_SEED = 4
19
- @@TRANSFORM_SEED = 5
20
- @@TRANSFORM_ROUNDS = 6
21
- @@ENCRYPTION_IV = 7
22
- @@PROTECTED_STREAM_KEY = 8
23
- @@STREAM_START_BYTES = 9
24
- @@INNER_RANDOM_STREAM_ID = 10
14
+ module Header
15
+ END_OF_HEADER = 0
16
+ COMMENT = 1
17
+ CIPHER_ID = 2
18
+ COMPRESSION = 3
19
+ MASTER_SEED = 4
20
+ TRANSFORM_SEED = 5
21
+ TRANSFORM_ROUNDS = 6
22
+ ENCRYPTION_IV = 7
23
+ PROTECTED_STREAM_KEY = 8
24
+ STREAM_START_BYTES = 9
25
+ INNER_RANDOM_STREAM_ID = 10
26
+ KDF_PARAMETERS = 11
27
+ PUBLIC_CUSTOM_DATA = 12
28
+ end
29
+
30
+ # Inner header fields
31
+ module InnerHeader
32
+ END_OF_HEADER = 0
33
+ RANDOM_STREAM_ID = 1
34
+ RANDOM_STREAM_KEY = 2
35
+ BINARY = 3
36
+ end
25
37
 
26
38
  # Magic values
27
- @@MAGIC_SIG1 = 0x9aa2d903
28
- @@MAGIC_SIG2 = 0xb54bfb67
29
- @@VERSION = 0x00030000
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"
39
+ module Magic
40
+ SIG1 = 0x9aa2d903
41
+ SIG2 = 0xb54bfb67
42
+ VERSION3 = 0x00030000
43
+ VERSION31 = 0x00030001
44
+ VERSION4 = 0x00040000
45
+ end
46
+
47
+ # Stream algorithm
48
+ module StreamAlgorithm
49
+ ARC_FOUR_VARIANT = 1
50
+ SALSA20 = 2
51
+ CHACHA20 = 3
52
+ end
38
53
 
39
54
  attr_reader :attachment_decoder
40
55
  attr_reader :db
41
- attr_reader :gzip
42
56
  attr_reader :protected_decryptor
43
57
  attr_reader :xml
44
58
 
@@ -145,43 +159,136 @@ class RubeePass
145
159
  end
146
160
  end
147
161
 
148
- def derive_aeskdf3_key(header)
162
+ def decompress(compressed)
163
+ if (!@header[Header::COMPRESSION])
164
+ # This feels like a hack
165
+ m = compressed.read.match(
166
+ /\<KeePassFile\>.+\<\/KeePassFile\>/m
167
+ )
168
+ return m[0] if (m.length > 0)
169
+ return nil
170
+ end
171
+
172
+ gzip = ""
173
+ block_id = 0
174
+
175
+ loop do
176
+ # Read block ID
177
+ data = compressed.read(4)
178
+ raise Error::InvalidGzip.new if (data.nil?)
179
+ id = data.unpack("L*")[0]
180
+ raise Error::InvalidGzip.new if (block_id != id)
181
+
182
+ block_id += 1
183
+
184
+ # Read expected hash
185
+ data = compressed.read(32)
186
+ raise Error::InvalidGzip.new if (data.nil?)
187
+ expected_hash = data
188
+
189
+ # Read size
190
+ data = compressed.read(4)
191
+ raise Error::InvalidGzip.new if (data.nil?)
192
+ size = data.unpack("L*")[0]
193
+
194
+ # Break if size is 0 and expected hash is all 0's
195
+ if (size == 0)
196
+ expected_hash.each_byte do |byte|
197
+ raise Error::InvalidGzip.new if (byte != 0)
198
+ end
199
+ break
200
+ end
201
+
202
+ # Read data and get actual hash
203
+ data = compressed.read(size)
204
+ actual_hash = Digest::SHA256.digest(data)
205
+
206
+ # Check that actual hash is same as expected hash
207
+ if (actual_hash != expected_hash)
208
+ raise Error::InvalidGzip.new
209
+ end
210
+
211
+ # Append data
212
+ gzip += data
213
+ end
214
+
215
+ # Unzip gzip data
216
+ return Zlib::GzipReader.new(StringIO.new(gzip)).read
217
+ end
218
+ private :decompress
219
+
220
+ def derive_kdf3_key
221
+ case @version
222
+ when Magic::VERSION4
223
+ raise Error::InvalidHeader.new("KDF3 with version 4")
224
+ end
225
+
149
226
  irsi = "\x02\x00\x00\x00"
150
227
  if (
151
- (header[@@MASTER_SEED].length != 32) ||
152
- (header[@@TRANSFORM_SEED].length != 32)
228
+ (@header[Header::MASTER_SEED].length != 32) ||
229
+ (@header[Header::TRANSFORM_SEED].length != 32)
153
230
  )
154
- raise Error::InvalidHeader.new
155
- elsif (header[@@INNER_RANDOM_STREAM_ID] != irsi)
231
+ raise Error::InvalidHeader.new("Invalid seed size")
232
+ elsif (@header[Header::INNER_RANDOM_STREAM_ID] != irsi)
156
233
  raise Error::NotSalsa.new
157
234
  end
158
235
 
159
236
  cipher = OpenSSL::Cipher::AES.new(256, :ECB)
160
237
  cipher.encrypt
161
- cipher.key = @header[@@TRANSFORM_SEED]
238
+ cipher.key = @header[Header::TRANSFORM_SEED]
162
239
  cipher.padding = 0
163
240
 
164
241
  key = @initial_key
165
- @header[@@TRANSFORM_ROUNDS].times do
242
+ @header[Header::TRANSFORM_ROUNDS].times do
166
243
  key = cipher.update(key) + cipher.final
167
244
  end
168
245
 
169
246
  transform_key = Digest::SHA256::digest(key)
170
- combined_key = @header[@@MASTER_SEED] + transform_key
247
+ combined_key = @header[Header::MASTER_SEED] + transform_key
171
248
 
172
- @cipher = OpenSSL::Cipher::AES.new(256, :CBC)
173
- @key = Digest::SHA256::digest(combined_key)
174
- @iv = @header[@@ENCRYPTION_IV]
249
+ @cipher = Cipher.new(
250
+ @header[Header::CIPHER_ID],
251
+ @header[Header::ENCRYPTION_IV],
252
+ Digest::SHA256::digest(combined_key)
253
+ )
175
254
  end
176
- private :derive_aeskdf3_key
255
+ private :derive_kdf3_key
256
+
257
+ def derive_kdf4_key(file)
258
+ case @version
259
+ when Magic::VERSION3, Magic::VERSION31
260
+ raise Error::InvalidHeader.new("KDF4 with version 3")
261
+ end
177
262
 
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
263
+ sha = file.read(32)
264
+ hmac = file.read(32)
265
+
266
+ if (sha.nil? || (sha.length != 32))
267
+ raise Error::InvalidHeader.new("Invalid SHA size")
268
+ end
269
+ if (hmac.nil? || (hmac.length != 32))
270
+ raise Error::InvalidHeader.new("Invalid HMAC size")
271
+ end
272
+
273
+ # TODO check SHA and HMAC (eh, later)
274
+
275
+ # TODO implement kdf4 key derivation
276
+
277
+ raise Error::NotSupported.new("AES with new KDF")
183
278
  end
184
- private :derive_aeskdf4_or_argon2_key
279
+ private :derive_kdf4_key
280
+
281
+ def derive_key(file)
282
+ if (
283
+ @header[Header::TRANSFORM_ROUNDS].nil? ||
284
+ @header[Header::TRANSFORM_SEED].nil?
285
+ )
286
+ derive_kdf4_key(file)
287
+ else
288
+ derive_kdf3_key
289
+ end
290
+ end
291
+ private :derive_key
185
292
 
186
293
  def export(export_file, format)
187
294
  start_opening
@@ -189,18 +296,15 @@ class RubeePass
189
296
  File.open(export_file, "w") do |f|
190
297
  case format
191
298
  when "gzip"
192
- f.write(@gzip)
299
+ gz = Zlib::GzipWriter.new(f)
300
+ gz.write(@xml)
301
+ gz.close
193
302
  when "xml"
194
303
  f.write(@xml)
195
304
  end
196
305
  end
197
306
  end
198
307
 
199
- def extract_xml
200
- @xml = Zlib::GzipReader.new(StringIO.new(@gzip)).read
201
- end
202
- private :extract_xml
203
-
204
308
  def find_group(path)
205
309
  return @db.find_group(path)
206
310
  end
@@ -221,7 +325,7 @@ class RubeePass
221
325
  @password = password
222
326
 
223
327
  if (@kdbx.nil?)
224
- # TODO
328
+ raise RubeePass::Error::FileNotFound.new("null")
225
329
  elsif (!@kdbx.exist?)
226
330
  raise RubeePass::Error::FileNotFound.new(@kdbx)
227
331
  elsif (!@kdbx.readable?)
@@ -247,26 +351,11 @@ class RubeePass
247
351
  contents = contents.unpack("H*").pack("H*")
248
352
  end
249
353
  if (contents[0..4] == "<?xml")
250
- # XML Key file
251
- # My ugly attempt to parse a small XML Key file with a
252
- # poor attempt at schema validation
253
- keyfile_line = false
254
- key_line = false
255
- contents.each_line do |line|
256
- line.strip!
257
- case line
258
- when "<KeyFile>"
259
- keyfile_line = true
260
- when "<Key>"
261
- key_line = true
262
- when %r{<Data>.*</Data>}
263
- data = line.gsub(%r{^<Data>|</Data>$}, "")
264
- data = data.unpack("m*")[0]
265
- break if (!keyfile_line || !key_line)
266
- break if (data.length != 32)
267
- filehash = data
268
- end
269
- end
354
+ # Parse XML for data
355
+ doc = REXML::Document.new(contents)
356
+ data = doc.elements["KeyFile/Key/Data"]
357
+ raise Error::InvalidXML.new if (data.nil?)
358
+ filehash = data.text.unpack("m*")[0]
270
359
  elsif (contents.length == 32)
271
360
  # Not XML but a 32 byte Key file
272
361
  filehash = contents
@@ -308,7 +397,7 @@ class RubeePass
308
397
 
309
398
  @protected_decryptor = ProtectedDecryptor.new(
310
399
  Digest::SHA256.digest(
311
- @header[@@PROTECTED_STREAM_KEY]
400
+ @header[Header::PROTECTED_STREAM_KEY]
312
401
  ),
313
402
  ["E830094B97205D2A"].pack("H*")
314
403
  )
@@ -318,79 +407,6 @@ class RubeePass
318
407
  return self
319
408
  end
320
409
 
321
- def parse_gzip(file)
322
- gzip = ""
323
- block_id = 0
324
-
325
- loop do
326
- # Read block ID
327
- data = file.read(4)
328
- raise Error::InvalidGzip.new if (data.nil?)
329
- id = data.unpack("L*")[0]
330
- raise Error::InvalidGzip.new if (block_id != id)
331
-
332
- block_id += 1
333
-
334
- # Read expected hash
335
- data = file.read(32)
336
- raise Error::InvalidGzip.new if (data.nil?)
337
- expected_hash = data
338
-
339
- # Read size
340
- data = file.read(4)
341
- raise Error::InvalidGzip.new if (data.nil?)
342
- size = data.unpack("L*")[0]
343
-
344
- # Break is size is 0 and expected hash is all 0's
345
- if (size == 0)
346
- expected_hash.each_byte do |byte|
347
- raise Error::InvalidGzip.new if (byte != 0)
348
- end
349
- break
350
- end
351
-
352
- # Read data and get actual hash
353
- data = file.read(size)
354
- actual_hash = Digest::SHA256.digest(data)
355
-
356
- # Check that actual hash is same as expected hash
357
- if (actual_hash != expected_hash)
358
- raise Error::InvalidGzip.new
359
- end
360
-
361
- # Append data
362
- gzip += data
363
- end
364
-
365
- return gzip
366
- end
367
- private :parse_gzip
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
-
394
410
  def parse_xml
395
411
  doc = REXML::Document.new(@xml)
396
412
  if (doc.elements["KeePassFile/Root"].nil?)
@@ -406,30 +422,6 @@ class RubeePass
406
422
  end
407
423
  private :parse_xml
408
424
 
409
- def read_gzip(file)
410
- cipher = @cipher.clone
411
- cipher.decrypt
412
- cipher.key = @key
413
- cipher.iv = @iv
414
-
415
- encrypted = file.read
416
-
417
- begin
418
- data = StringIO.new(
419
- cipher.update(encrypted) + cipher.final
420
- )
421
- rescue OpenSSL::Cipher::CipherError
422
- raise Error::InvalidPassword.new
423
- end
424
-
425
- if (data.read(32) != @header[@@STREAM_START_BYTES])
426
- raise Error::InvalidPassword.new
427
- end
428
-
429
- @gzip = parse_gzip(data)
430
- end
431
- private :read_gzip
432
-
433
425
  def read_header(file)
434
426
  header = Hash.new
435
427
  loop do
@@ -437,7 +429,14 @@ class RubeePass
437
429
  break if (data.nil?)
438
430
  id = data.unpack("C*")[0]
439
431
 
440
- data = file.read(2)
432
+ case @version
433
+ when Magic::VERSION3, Magic::VERSION31
434
+ data = file.read(2)
435
+ when Magic::VERSION4
436
+ data = file.read(4)
437
+ else
438
+ raise Error::InvalidHeader.new
439
+ end
441
440
  raise Error::InvalidHeader.new if (data.nil?)
442
441
  size = data.unpack("S*")[0]
443
442
 
@@ -447,11 +446,40 @@ class RubeePass
447
446
  end
448
447
 
449
448
  case id
450
- when @@END_OF_HEADER
449
+ when Header::CIPHER_ID
450
+ header[id] = data.unpack("H*")[0]
451
+ when Header::COMPRESSION
452
+ header[id] = (data.unpack("L*")[0] > 0)
453
+ when Header::END_OF_HEADER
451
454
  break
452
- when @@TRANSFORM_ROUNDS
455
+ when Header::KDF_PARAMETERS
456
+ case @version
457
+ when Magic::VERSION3, Magic::VERSION31
458
+ raise Error::InvalidHeader.new
459
+ end
460
+ # raise Error::NotSupported.new("Custom KDF params")
461
+ when Header::PUBLIC_CUSTOM_DATA
462
+ case @version
463
+ when Magic::VERSION3, Magic::VERSION31
464
+ raise Error::InvalidHeader.new
465
+ end
466
+ raise Error::NotSupported.new("Public custom data")
467
+ when Header::TRANSFORM_ROUNDS
453
468
  header[id] = data.unpack("Q*")[0]
454
469
  else
470
+ case @version
471
+ when Magic::VERSION4
472
+ case id
473
+ when Header::INNER_RANDOM_STREAM_ID,
474
+ Header::PROTECTED_STREAM_KEY,
475
+ Header::STREAM_START_BYTES,
476
+ Header::TRANSFORM_ROUNDS,
477
+ Header::TRANSFORM_SEED
478
+ raise Error::InvalidHeader.new(
479
+ "Legacy header ID"
480
+ )
481
+ end
482
+ end
455
483
  header[id] = data
456
484
  end
457
485
  end
@@ -463,43 +491,54 @@ class RubeePass
463
491
  def read_magic_and_version(file)
464
492
  data = file.read(4)
465
493
  raise Error::InvalidMagic.new if (data.nil?)
466
- sig1 = data.unpack("L*")[0]
467
- raise Error::InvalidMagic.new if (sig1 != @@MAGIC_SIG1)
494
+ @sig1 = data.unpack("L*")[0]
495
+ # raise Error::InvalidMagic.new if (@sig1 != Magic::SIG1)
468
496
 
469
497
  data = file.read(4)
470
498
  raise Error::InvalidMagic.new if (data.nil?)
471
- sig2 = data.unpack("L*")[0]
472
- raise Error::InvalidMagic.new if (sig2 != @@MAGIC_SIG2)
499
+ @sig2 = data.unpack("L*")[0]
500
+ # raise Error::InvalidMagic.new if (@sig2 != Magic::SIG2)
473
501
 
474
502
  data = file.read(4)
475
503
  raise Error::InvalidVersion.new if (data.nil?)
476
- ver = data.unpack("L*")[0]
477
- if ((ver & 0xffff0000) != @@VERSION)
478
- raise Error::InvalidVersion.new if (data.nil?)
504
+ @version = data.unpack("L*")[0]
505
+ case @version
506
+ when Magic::VERSION3, Magic::VERSION31, Magic::VERSION4
507
+ else
508
+ raise Error::InvalidVersion.new
479
509
  end
480
510
  end
481
511
  private :read_magic_and_version
482
512
 
483
513
  def start_opening
514
+ @cipher = nil
484
515
  @db = nil
485
- @gzip = nil
486
516
  @header = nil
487
517
  @initial_key = nil
488
- @iv = nil
489
- @key = nil
518
+ @sig1 = nil
519
+ @sig2 = nil
520
+ @version = nil
490
521
  @xml = nil
491
522
 
492
523
  file = File.open(@kdbx)
493
524
 
525
+ # Read metadata and derive key
494
526
  read_magic_and_version(file)
495
- header = read_header(file)
527
+ read_header(file)
496
528
  join_key_and_keyfile
497
- parse_header(header)
498
- read_gzip(file)
529
+ derive_key(file)
499
530
 
500
- file.close
531
+ # Decrypt file
532
+ encrypted = file.read
533
+ decrypted = @cipher.decrypt(encrypted)
534
+ if (decrypted.read(32) != @header[Header::STREAM_START_BYTES])
535
+ raise Error::InvalidPassword.new
536
+ end
501
537
 
502
- extract_xml
538
+ # Decompress (if necessary)
539
+ @xml = decompress(decrypted)
540
+
541
+ file.close
503
542
  end
504
543
  private :start_opening
505
544
 
@@ -518,6 +557,7 @@ class RubeePass
518
557
  end
519
558
 
520
559
  require "rubeepass/attachment_decoder"
560
+ require "rubeepass/cipher"
521
561
  require "rubeepass/entry"
522
562
  require "rubeepass/error"
523
563
  require "rubeepass/group"
@@ -0,0 +1,57 @@
1
+ require "openssl"
2
+ require "twofish"
3
+
4
+ class RubeePass::Cipher
5
+ # Encryption schemes
6
+ module ID
7
+ AES = "31c1f2e6bf714350be5805216afc5aff"
8
+ CHACHA20 = "d6038a2b8b6f4cb5a524339a31dbb59a"
9
+ TWOFISH = "ad68f29f576f4bb9a36ad47af965346c"
10
+ end
11
+
12
+ def decrypt(enc)
13
+ # Setup
14
+ case @id
15
+ when ID::AES
16
+ cipher = OpenSSL::Cipher::AES.new(256, :CBC)
17
+ when ID::CHACHA20
18
+ cipher = OpenSSL::Cipher.new("chacha20")
19
+ when ID::TWOFISH
20
+ cipher = Twofish.new(
21
+ @key,
22
+ {
23
+ :iv => @iv,
24
+ :mode => :cbc,
25
+ :padding => :none
26
+ }
27
+ )
28
+ else
29
+ raise RubeePass::Error::NotSupported.new
30
+ end
31
+
32
+ # Decrypt
33
+ case @id
34
+ when ID::AES, ID::CHACHA20
35
+ begin
36
+ cipher.decrypt
37
+ cipher.key = @key
38
+ cipher.iv = @iv
39
+ return StringIO.new(cipher.update(enc) + cipher.final)
40
+ rescue OpenSSL::Cipher::CipherError
41
+ raise RubeePass::Error::InvalidPassword.new
42
+ end
43
+ when ID::TWOFISH
44
+ begin
45
+ return StringIO.new(cipher.decrypt(enc))
46
+ rescue ArgumentError
47
+ raise RubeePass::Error::InvalidPassword.new
48
+ end
49
+ end
50
+ end
51
+
52
+ def initialize(id, iv, key)
53
+ @id = id
54
+ @iv = iv
55
+ @key = key
56
+ end
57
+ end
@@ -154,9 +154,11 @@ class RubeePass::Entry
154
154
  data = data.unpack("H*").pack("H*")
155
155
  end
156
156
  rescue ArgumentError
157
- raise Error::InvalidProtectedData.new
157
+ raise RubeePass::Error::InvalidProtectedData.new
158
+ end
159
+ if (data.nil?)
160
+ raise RubeePass::Error::InvalidProtectedData.new
158
161
  end
159
- raise Error::InvalidProtectedData.new if (data.nil?)
160
162
 
161
163
  return keepass.protected_decryptor.add_to_stream(data)
162
164
  end
@@ -1,5 +1,9 @@
1
1
  class RubeePass::Error::InvalidHeader < RubeePass::Error
2
- def initialize
3
- super("Invalid header format!")
2
+ def initialize(msg = nil)
3
+ if (msg.nil?)
4
+ super("Invalid header format!")
5
+ else
6
+ super("Invalid header: #{msg}")
7
+ end
4
8
  end
5
9
  end
@@ -1,5 +1,9 @@
1
1
  class RubeePass::Error::NotSupported < RubeePass::Error
2
- def initialize
3
- super("Encryption scheme not currently supported")
2
+ def initialize(msg = nil)
3
+ if (msg.nil?)
4
+ super("Encryption scheme not currently supported")
5
+ else
6
+ super("Encryption scheme not currently supported: #{msg}")
7
+ end
4
8
  end
5
9
  end
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.2.0
4
+ version: 3.3.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-15 00:00:00.000000000 Z
11
+ date: 2018-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -139,7 +139,7 @@ dependencies:
139
139
  version: '0.1'
140
140
  - - ">="
141
141
  - !ruby/object:Gem::Version
142
- version: 0.1.2
142
+ version: 0.1.3
143
143
  type: :runtime
144
144
  prerelease: false
145
145
  version_requirements: !ruby/object:Gem::Requirement
@@ -149,7 +149,7 @@ dependencies:
149
149
  version: '0.1'
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
- version: 0.1.2
152
+ version: 0.1.3
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: scoobydoo
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -170,6 +170,26 @@ dependencies:
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
172
  version: 0.1.6
173
+ - !ruby/object:Gem::Dependency
174
+ name: twofish
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '1.0'
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: 1.0.8
183
+ type: :runtime
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '1.0'
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: 1.0.8
173
193
  description: Ruby KeePass 2.x client. Currently it is read-only.
174
194
  email: mjwhitta@gmail.com
175
195
  executables:
@@ -180,6 +200,7 @@ files:
180
200
  - bin/rpass
181
201
  - lib/rubeepass.rb
182
202
  - lib/rubeepass/attachment_decoder.rb
203
+ - lib/rubeepass/cipher.rb
183
204
  - lib/rubeepass/entry.rb
184
205
  - lib/rubeepass/error.rb
185
206
  - lib/rubeepass/error/file_not_found.rb