| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -6,6 +6,7 @@ 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_salt_generator.dart'; | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/crypto/protected_salt_generator.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:kdbx/src/crypto/protected_value.dart'; | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/crypto/protected_value.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/async_utils.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/byte_utils.dart'; | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/byte_utils.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/crypto_utils.dart'; | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/internal/crypto_utils.dart'; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import 'package:kdbx/src/kdbx_group.dart'; | 
					 | 
					 | 
					 | 
					import 'package:kdbx/src/kdbx_group.dart'; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -34,8 +35,10 @@ class Credentials { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					class KdbxFile { | 
					 | 
					 | 
					 | 
					class KdbxFile with Changeable<KdbxFile> { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  KdbxFile(this.credentials, this.header, this.body); | 
					 | 
					 | 
					 | 
					  KdbxFile(this.credentials, this.header, this.body) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    _subscribeToChildren(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static final protectedValues = Expando<ProtectedValue>(); | 
					 | 
					 | 
					 | 
					  static final protectedValues = Expando<ProtectedValue>(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -43,23 +46,57 @@ class KdbxFile { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return protectedValues[node]; | 
					 | 
					 | 
					 | 
					    return protectedValues[node]; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static void setProtectedValueForNode(xml.XmlElement node, ProtectedValue value) { | 
					 | 
					 | 
					 | 
					  static void setProtectedValueForNode( | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      xml.XmlElement node, ProtectedValue value) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    protectedValues[node] = value; | 
					 | 
					 | 
					 | 
					    protectedValues[node] = value; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  final StreamSubscriptions _subscriptions = StreamSubscriptions(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  final Credentials credentials; | 
					 | 
					 | 
					 | 
					  final Credentials credentials; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  final KdbxHeader header; | 
					 | 
					 | 
					 | 
					  final KdbxHeader header; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  final KdbxBody body; | 
					 | 
					 | 
					 | 
					  final KdbxBody body; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  Uint8List save() { | 
					 | 
					 | 
					 | 
					  Uint8List save() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    assert(header.versionMajor == 3); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final output = BytesBuilder(); | 
					 | 
					 | 
					 | 
					    final output = BytesBuilder(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final writer = WriterHelper(output); | 
					 | 
					 | 
					 | 
					    final writer = WriterHelper(output); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    header.generateSalts(); | 
					 | 
					 | 
					 | 
					    header.generateSalts(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    header.write(writer); | 
					 | 
					 | 
					 | 
					    header.write(writer); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    body.write(writer, this); | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    final streamKey = | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        header.fields[HeaderFields.ProtectedStreamKey].bytes.asUint8List(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    final gen = ProtectedSaltGenerator(streamKey); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    body.meta.headerHash.set( | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        (crypto.sha256.convert(writer.output.toBytes()).bytes as Uint8List) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            .buffer); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    body.writeV3(writer, this, gen); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return output.toBytes(); | 
					 | 
					 | 
					 | 
					    return output.toBytes(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  Iterable<KdbxObject> get _allObjects => body.rootGroup | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      .getAllGroups() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      .cast<KdbxObject>() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      .followedBy(body.rootGroup.getAllEntries()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  void _subscribeToChildren() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    final allObjects = _allObjects; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    for (final obj in allObjects) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      _subscriptions.handle(obj.changes.listen((event) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        if (event.isDirty) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          isDirty = true; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          if (event.object is KdbxGroup) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            Future(() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              // resubscribe, just in case some child groups/entries have changed. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              _subscriptions.cancelSubscriptions(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					              _subscribeToChildren(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            }); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      })); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					class KdbxBody extends KdbxNode { | 
					 | 
					 | 
					 | 
					class KdbxBody extends KdbxNode { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -77,35 +114,32 @@ class KdbxBody extends KdbxNode { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  final KdbxMeta meta; | 
					 | 
					 | 
					 | 
					  final KdbxMeta meta; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  final KdbxGroup rootGroup; | 
					 | 
					 | 
					 | 
					  final KdbxGroup rootGroup; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  void write(WriterHelper writer, KdbxFile kdbxFile) { | 
					 | 
					 | 
					 | 
					  void writeV3(WriterHelper writer, KdbxFile kdbxFile, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    assert(kdbxFile.header.versionMajor == 3); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final streamKey = kdbxFile | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        .header.fields[HeaderFields.ProtectedStreamKey].bytes | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        .asUint8List(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final gen = ProtectedSaltGenerator(streamKey); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    _writeV3(writer, kdbxFile, gen); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  void _writeV3(WriterHelper writer, KdbxFile kdbxFile, | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      ProtectedSaltGenerator saltGenerator) { | 
					 | 
					 | 
					 | 
					      ProtectedSaltGenerator saltGenerator) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    meta.headerHash.set( | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        (crypto.sha256.convert(writer.output.toBytes()).bytes as Uint8List) | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            .buffer); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final xml = generateXml(saltGenerator); | 
					 | 
					 | 
					 | 
					    final xml = generateXml(saltGenerator); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final xmlBytes = utf8.encode(xml.toXmlString()); | 
					 | 
					 | 
					 | 
					    final xmlBytes = utf8.encode(xml.toXmlString()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final Uint8List compressedBytes = (kdbxFile.header.compression == Compression.gzip ? | 
					 | 
					 | 
					 | 
					    final Uint8List compressedBytes = | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      GZipCodec().encode(xmlBytes) : xmlBytes) as Uint8List; | 
					 | 
					 | 
					 | 
					        (kdbxFile.header.compression == Compression.gzip | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ? GZipCodec().encode(xmlBytes) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            : xmlBytes) as Uint8List; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    final encrypted = _encryptV3(kdbxFile, compressedBytes); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    writer.writeBytes(encrypted); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					  Uint8List _encryptV3(KdbxFile kdbxFile, Uint8List compressedBytes) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final byteWriter = WriterHelper(); | 
					 | 
					 | 
					 | 
					    final byteWriter = WriterHelper(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    byteWriter.writeBytes(kdbxFile.header.fields[HeaderFields.StreamStartBytes].bytes.asUint8List()); | 
					 | 
					 | 
					 | 
					    byteWriter.writeBytes(kdbxFile | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .header.fields[HeaderFields.StreamStartBytes].bytes | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .asUint8List()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    HashedBlockReader.writeBlocks(ReaderHelper(compressedBytes), byteWriter); | 
					 | 
					 | 
					 | 
					    HashedBlockReader.writeBlocks(ReaderHelper(compressedBytes), byteWriter); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final bytes = byteWriter.output.toBytes(); | 
					 | 
					 | 
					 | 
					    final bytes = byteWriter.output.toBytes(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final masterKey = KdbxFormat._generateMasterKeyV3(kdbxFile.header, kdbxFile.credentials); | 
					 | 
					 | 
					 | 
					    final masterKey = | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final encrypted = KdbxFormat._encryptDataAes(masterKey, bytes, kdbxFile.header.fields[HeaderFields.EncryptionIV].bytes.asUint8List()); | 
					 | 
					 | 
					 | 
					        KdbxFormat._generateMasterKeyV3(kdbxFile.header, kdbxFile.credentials); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//    writer.writeBytes(kdbxFile.header.fields[HeaderFields.StreamStartBytes].bytes.asUint8List()); | 
					 | 
					 | 
					 | 
					    final encrypted = KdbxFormat._encryptDataAes(masterKey, bytes, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    writer.writeBytes(encrypted); | 
					 | 
					 | 
					 | 
					        kdbxFile.header.fields[HeaderFields.EncryptionIV].bytes.asUint8List()); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    return encrypted; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  xml.XmlDocument generateXml(ProtectedSaltGenerator saltGenerator) { | 
					 | 
					 | 
					 | 
					  xml.XmlDocument generateXml(ProtectedSaltGenerator saltGenerator) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -124,12 +158,16 @@ class KdbxBody extends KdbxNode { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      } | 
					 | 
					 | 
					 | 
					      } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final builder = xml.XmlBuilder(); | 
					 | 
					 | 
					 | 
					    final builder = xml.XmlBuilder(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    builder.processing('xml', 'version="1.0" encoding="utf-8" standalone="yes"'); | 
					 | 
					 | 
					 | 
					    builder.processing( | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    builder.element('KeePassFile', nest: [ | 
					 | 
					 | 
					 | 
					        'xml', 'version="1.0" encoding="utf-8" standalone="yes"'); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    builder.element( | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      'KeePassFile', | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      nest: [ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        meta.toXml(), | 
					 | 
					 | 
					 | 
					        meta.toXml(), | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      () => builder.element('Root', nest: rootGroupNode),],); | 
					 | 
					 | 
					 | 
					        () => builder.element('Root', nest: rootGroupNode), | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      ], | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    ); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//    final doc = xml.XmlDocument(); | 
					 | 
					 | 
					 | 
					//    final doc = xml.XmlDocument(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//    doc.children.add(xml.XmlProcessing( | 
					 | 
					 | 
					 | 
					//    doc.children.add(xml.XmlProcessing( | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					//        'xml', 'version="1.0" encoding="utf-8" standalone="yes"')); | 
					 | 
					 | 
					 | 
					//        'xml', 'version="1.0" encoding="utf-8" standalone="yes"')); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -224,7 +262,8 @@ class KdbxFormat { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final decryptCipher = CBCBlockCipher(AESFastEngine()); | 
					 | 
					 | 
					 | 
					    final decryptCipher = CBCBlockCipher(AESFastEngine()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    decryptCipher.init(false, | 
					 | 
					 | 
					 | 
					    decryptCipher.init(false, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        ParametersWithIV(KeyParameter(masterKey), encryptionIv.asUint8List())); | 
					 | 
					 | 
					 | 
					        ParametersWithIV(KeyParameter(masterKey), encryptionIv.asUint8List())); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final paddedDecrypted = AesHelper.processBlocks(decryptCipher, encryptedPayload); | 
					 | 
					 | 
					 | 
					    final paddedDecrypted = | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        AesHelper.processBlocks(decryptCipher, encryptedPayload); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final decrypted = AesHelper.unpad(paddedDecrypted); | 
					 | 
					 | 
					 | 
					    final decrypted = AesHelper.unpad(paddedDecrypted); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final streamStart = header.fields[HeaderFields.StreamStartBytes].bytes; | 
					 | 
					 | 
					 | 
					    final streamStart = header.fields[HeaderFields.StreamStartBytes].bytes; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -265,11 +304,12 @@ class KdbxFormat { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return masterKey; | 
					 | 
					 | 
					 | 
					    return masterKey; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static Uint8List _encryptDataAes(Uint8List masterKey, Uint8List payload, Uint8List encryptionIv) { | 
					 | 
					 | 
					 | 
					  static Uint8List _encryptDataAes( | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      Uint8List masterKey, Uint8List payload, Uint8List encryptionIv) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    final encryptCipher = CBCBlockCipher(AESFastEngine()); | 
					 | 
					 | 
					 | 
					    final encryptCipher = CBCBlockCipher(AESFastEngine()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    encryptCipher.init(true, | 
					 | 
					 | 
					 | 
					    encryptCipher.init( | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        ParametersWithIV(KeyParameter(masterKey), encryptionIv)); | 
					 | 
					 | 
					 | 
					        true, ParametersWithIV(KeyParameter(masterKey), encryptionIv)); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return AesHelper.processBlocks(encryptCipher, AesHelper.pad(payload, encryptCipher.blockSize)); | 
					 | 
					 | 
					 | 
					    return AesHelper.processBlocks( | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					        encryptCipher, AesHelper.pad(payload, encryptCipher.blockSize)); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
					 | 
					 | 
					
  |