| 
						
						
						
					 | 
					 | 
					@ -1,8 +1,6 @@ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'dart:typed_data'; | 
					 | 
					 | 
					 | 
					import 'dart:typed_data'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:convert/convert.dart' as convert; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:crypto/crypto.dart' as crypto; | 
					 | 
					 | 
					 | 
					import 'package:crypto/crypto.dart' as crypto; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:kdbx/src/crypto/protected_value.dart'; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/byte_utils.dart'; | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/byte_utils.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:logging/logging.dart'; | 
					 | 
					 | 
					 | 
					import 'package:logging/logging.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -51,14 +49,21 @@ class HeaderField { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					class KdbxHeader { | 
					 | 
					 | 
					 | 
					class KdbxHeader { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  KdbxHeader({this.sig1, this.sig2, this.versionMinor, this.versionMajor, this.fields}); | 
					 | 
					 | 
					 | 
					  KdbxHeader( | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					      {this.sig1, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static Future<KdbxHeader> read(ReaderHelper reader) async { | 
					 | 
					 | 
					 | 
					      this.sig2, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      this.versionMinor, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      this.versionMajor, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      this.fields}); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  static KdbxHeader read(ReaderHelper reader) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // reading signature | 
					 | 
					 | 
					 | 
					    // reading signature | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final sig1 = reader.readUint32(); | 
					 | 
					 | 
					 | 
					    final sig1 = reader.readUint32(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final sig2 = reader.readUint32(); | 
					 | 
					 | 
					 | 
					    final sig2 = reader.readUint32(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if (!(sig1 == Consts.FileMagic && sig2 == Consts.Sig2Kdbx)) { | 
					 | 
					 | 
					 | 
					    if (!(sig1 == Consts.FileMagic && sig2 == Consts.Sig2Kdbx)) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      throw UnsupportedError('Unsupported file structure. ${ByteUtils.toHex(sig1)}, ${ByteUtils.toHex(sig2)}'); | 
					 | 
					 | 
					 | 
					      throw UnsupportedError( | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          'Unsupported file structure. ${ByteUtils.toHex(sig1)}, ' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          '${ByteUtils.toHex(sig2)}'); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // reading version | 
					 | 
					 | 
					 | 
					    // reading version | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -66,7 +71,8 @@ class KdbxHeader { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final versionMajor = reader.readUint16(); | 
					 | 
					 | 
					 | 
					    final versionMajor = reader.readUint16(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _logger.finer('Reading version: $versionMajor.$versionMinor'); | 
					 | 
					 | 
					 | 
					    _logger.finer('Reading version: $versionMajor.$versionMinor'); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final headerFields = Map.fromEntries(readField(reader, versionMajor).map((field) => MapEntry(field.field, field))); | 
					 | 
					 | 
					 | 
					    final headerFields = Map.fromEntries(readField(reader, versionMajor) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .map((field) => MapEntry(field.field, field))); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return KdbxHeader( | 
					 | 
					 | 
					 | 
					    return KdbxHeader( | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      sig1: sig1, | 
					 | 
					 | 
					 | 
					      sig1: sig1, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      sig2: sig2, | 
					 | 
					 | 
					 | 
					      sig2: sig2, | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -76,10 +82,12 @@ class KdbxHeader { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ); | 
					 | 
					 | 
					 | 
					    ); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static Iterable<HeaderField> readField(ReaderHelper reader, int versionMajor) sync* { | 
					 | 
					 | 
					 | 
					  static Iterable<HeaderField> readField( | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      ReaderHelper reader, int versionMajor) sync* { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    while (true) { | 
					 | 
					 | 
					 | 
					    while (true) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      final headerId = reader.readUint8(); | 
					 | 
					 | 
					 | 
					      final headerId = reader.readUint8(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      final int bodySize = versionMajor >= 4 ? reader.readUint32() : reader.readUint16(); | 
					 | 
					 | 
					 | 
					      final int bodySize = | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          versionMajor >= 4 ? reader.readUint32() : reader.readUint16(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      _logger.finer('Read header ${HeaderFields.values[headerId]}'); | 
					 | 
					 | 
					 | 
					      _logger.finer('Read header ${HeaderFields.values[headerId]}'); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      final bodyBytes = bodySize > 0 ? reader.readBytes(bodySize) : null; | 
					 | 
					 | 
					 | 
					      final bodyBytes = bodySize > 0 ? reader.readBytes(bodySize) : null; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (headerId > 0) { | 
					 | 
					 | 
					 | 
					      if (headerId > 0) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -108,7 +116,8 @@ class KdbxHeader { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  PotectedValueEncryption get innerRandomStreamEncryption => | 
					 | 
					 | 
					 | 
					  PotectedValueEncryption get innerRandomStreamEncryption => | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      PotectedValueEncryption.values[fields[HeaderFields.InnerRandomStreamID].bytes.asUint32List().single]; | 
					 | 
					 | 
					 | 
					      PotectedValueEncryption.values[ | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          fields[HeaderFields.InnerRandomStreamID].bytes.asUint32List().single]; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					class KdbxException implements Exception {} | 
					 | 
					 | 
					 | 
					class KdbxException implements Exception {} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -134,7 +143,8 @@ class HashedBlockReader { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      final blockSize = reader.readUint32(); | 
					 | 
					 | 
					 | 
					      final blockSize = reader.readUint32(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (blockSize > 0) { | 
					 | 
					 | 
					 | 
					      if (blockSize > 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        final blockData = reader.readBytes(blockSize).asUint8List(); | 
					 | 
					 | 
					 | 
					        final blockData = reader.readBytes(blockSize).asUint8List(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (!ByteUtils.eq(crypto.sha256.convert(blockData).bytes as Uint8List, blockHash.asUint8List())) { | 
					 | 
					 | 
					 | 
					        if (!ByteUtils.eq(crypto.sha256.convert(blockData).bytes as Uint8List, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            blockHash.asUint8List())) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          throw KdbxCorruptedFileException(); | 
					 | 
					 | 
					 | 
					          throw KdbxCorruptedFileException(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        yield blockData; | 
					 | 
					 | 
					 | 
					        yield blockData; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -151,7 +161,8 @@ class ReaderHelper { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  final Uint8List data; | 
					 | 
					 | 
					 | 
					  final Uint8List data; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  int pos = 0; | 
					 | 
					 | 
					 | 
					  int pos = 0; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  ByteBuffer _nextByteBuffer(int byteCount) => (data.sublist(pos, pos += byteCount) as Uint8List).buffer; | 
					 | 
					 | 
					 | 
					  ByteBuffer _nextByteBuffer(int byteCount) => | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      (data.sublist(pos, pos += byteCount) as Uint8List).buffer; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  int readUint32() => _nextByteBuffer(4).asUint32List().first; | 
					 | 
					 | 
					 | 
					  int readUint32() => _nextByteBuffer(4).asUint32List().first; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |