rubeepass 3.2.0 → 3.3.0

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.
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