@@ -108,6 +108,11 @@ class WalletDatHandler extends AbstractImportExportHandler {
108
108
}
109
109
}
110
110
111
+ /**
112
+ * Parse a wallet.dat file and provide access
113
+ * to its keys. This class can not be used to
114
+ * write or create new wallets, its read-only.
115
+ */
111
116
class WalletDat {
112
117
val log = LoggerFactory . getLogger(this . class)
113
118
@@ -130,6 +135,17 @@ class WalletDat {
130
135
var int mkey_nDerivationIterations
131
136
var String mkey_other_params
132
137
138
+ /**
139
+ * Parse the file (or throw exception if unreadable).
140
+ * If the constructor returns then this WalletDat
141
+ * Object will hold collections of all parsed keys
142
+ * that can be read with the public methods that
143
+ * are provided for this purpose. It can only read
144
+ * existing and not write. The method isEncrypted()
145
+ * can be used to test whether it is encrypted and
146
+ * the decrypt() method should be used to decrypt
147
+ * all keys.
148
+ */
133
149
new (File file) throws Exception {
134
150
try {
135
151
log. info(" opening file {}" , file)
@@ -240,6 +256,14 @@ class WalletDat {
240
256
log. trace(" found: type 'pool' n={}" , n)
241
257
}
242
258
259
+ /**
260
+ * @return true if the wallet contains an encrypted
261
+ * master-key which means all keys are encrypted.
262
+ */
263
+ def isEncrypted (){
264
+ mkey_encrypted_key != null
265
+ }
266
+
243
267
private def readString (ByteBuffer buf ) {
244
268
new String (buf. readSizePrefixedByteArray)
245
269
}
@@ -273,13 +297,20 @@ class WalletDat {
273
297
}
274
298
}
275
299
276
-
277
300
/**
278
- * Decrypt (if encrypted) the keys in the raw key list,
279
- * do nothing if they are not encrypted
301
+ * Decrypt (if encrypted) the keys in the raw key list.
302
+ * If the wallet is not encrypted this does nothing.
303
+ * After decryption succeeded the keys can be accessed
304
+ * through the other methods, if it fails an exception
305
+ * might be thrown. Because it is not guaranteed that
306
+ * it will always throw when the password was wrong the
307
+ * code that will later try to use the decrypted keys
308
+ * must check that public and private keys actually make
309
+ * sense and fit together (which the importer will do
310
+ * anyways).
280
311
*/
281
312
def decrypt (String password ) throws Exception {
282
- if (mkey_encrypted_key != null ){
313
+ if (encrypted ){
283
314
if (password == null ){
284
315
throw new FormatFoundNeedPasswordException
285
316
}
@@ -311,7 +342,10 @@ class WalletDat {
311
342
/**
312
343
* Return the collection of all WalletDatRawKeyData objects.
313
344
* This is used by the importer after the wallet has been
314
- * completely parsed and decrypted.
345
+ * completely parsed and decrypted. They are not checked for
346
+ * consistency or decryption errors, this must be done
347
+ * separately by the application that uses them (must check
348
+ * that private key and public key actually fit together)!
315
349
*/
316
350
def getKeys () {
317
351
rawKeyList. keyData. values
@@ -400,6 +434,15 @@ class WalletDat {
400
434
}
401
435
}
402
436
437
+ /**
438
+ * Abstract base class for all bdb pages. A Page is a block
439
+ * of the file of fixed size, the entire file is made up of
440
+ * such pages. There are several types of pages but all of
441
+ * them share a minimum of information like page number,
442
+ * next/previous page, page type, etc. This class does not
443
+ * expose all these fields, only the bare minimum needed to
444
+ * read through a b-tree file.
445
+ */
403
446
abstract class BerkeleyDBPage {
404
447
// page types
405
448
static val P_LBTREE = 5 /* B-tree leaf. */
@@ -446,7 +489,13 @@ abstract class BerkeleyDBPage {
446
489
}
447
490
448
491
/**
449
- * this is a leaf page, it contains all the data
492
+ * this is a leaf page, it contains all the data. Data
493
+ * is organized as key/value pairs. Each of them consists
494
+ * of two entries, the page also contains a lookup table
495
+ * to find the offsets of these data items to be able to
496
+ * simply access them by index number. Even index numbers
497
+ * are the key and the odd number directly following it is
498
+ * its value. Its pretty simple actually.
450
499
*/
451
500
class BerkeleyDBLeafPage extends BerkeleyDBPage {
452
501
static val SIZE_LEAF_HEADER = 26
@@ -529,7 +578,13 @@ class BerkeleyDBLeafPage extends BerkeleyDBPage {
529
578
}
530
579
531
580
/**
532
- * this is only used for page 0 to read magic, version, page size, etc.
581
+ * This is only used for page #0 to read magic, version,
582
+ * page size, etc. Although we read only the first few
583
+ * bytes it should be noted that this is also a complete
584
+ * page, its just mostly empty. More similar meta data
585
+ * pages might appear later in the file but we only care
586
+ * about the first one right at the start of the file,
587
+ * it contains all we need.
533
588
*/
534
589
class BerkeleyDBHeaderPage extends BerkeleyDBPage {
535
590
static val SIZE_METADATA_HEADER = 72
@@ -660,6 +715,12 @@ class WalletDatRawKeyDataList {
660
715
* and optionally decrypting the wallet this contains
661
716
* all information about a key with the only exception
662
717
* of label which is stored in a separate map.
718
+ *
719
+ * Note: during decryption there is no check performed
720
+ * that public and private key actually fit together,
721
+ * this must be checked by the application that is going
722
+ * to use these keys. The WalletDatHandler import handler
723
+ * will perform this check (its needed anyways).
663
724
*/
664
725
class WalletDatRawKeyData {
665
726
public var byte [] encrypted_private_key
0 commit comments