Save the database to specified file/stream with password and/or keyfile.
         
        :param dbfile: The path to the file we wish to save.
        :type dbfile: The path to the database file or a file-like object.
        
        :param password: The password to use for the database encryption key.
        :type password: str
        :param keyfile: The path to keyfile (or a stream) to use instead of or in conjunction with password for encryption key.
        :type keyfile: str or file-like object
        :raise keepassdb.exc.ReadOnlyDatabase: If database was opened with readonly flag.

def save(self, dbfile=None, password=None, keyfile=None):
        """
        Save the database to specified file/stream with password and/or keyfile.
         
        :param dbfile: The path to the file we wish to save.
        :type dbfile: The path to the database file or a file-like object.
        
        :param password: The password to use for the database encryption key.
        :type password: str
        :param keyfile: The path to keyfile (or a stream) to use instead of or in conjunction with password for encryption key.
        :type keyfile: str or file-like object
        :raise keepassdb.exc.ReadOnlyDatabase: If database was opened with readonly flag.
        """
        if self.readonly:
            # We might wish to make this more sophisticated.  E.g. if a new path is specified
            # as a parameter, then it's probably ok to ignore a readonly flag?  In general
            # this flag doens't make a ton of sense for a library ...
            raise exc.ReadOnlyDatabase()
        
        if dbfile is not None and not hasattr(dbfile, 'write'):
            self.filepath = dbfile
            
        if password is not None or self.keyfile is not None:
            # Do these together so we don't end up with some hybrid of old & new key material
            self.password = password
            self.keyfile = keyfile  
        else: 
            raise ValueError("Password and/or keyfile is required.")
        
        if self.filepath is None and dbfile is None:
            raise ValueError("Unable to save without target file.")
        
        buf = bytearray()
        
        # First, serialize the groups
        for group in self.groups:
            # Get the packed bytes
            group_struct = group.to_struct()
            self.log.debug("Group struct: {0!r}".format(group_struct))
            buf += group_struct.encode()
            
        # Then the entries.
        for entry in self.entries:
            entry_struct = entry.to_struct()
            buf += entry_struct.encode()

        # Hmmmm ... these defaults should probably be set elsewhere....?
        header = HeaderStruct()
        header.signature1 = const.DB_SIGNATURE1
        header.signature2 = const.DB_SIGNATURE2
        header.flags = header.AES
        header.version = 0x00030002
        header.key_enc_rounds = 50000
        header.seed_key = get_random_bytes(32)
        
        # Convert buffer to bytes for API simplicity
        buf = bytes(buf)
        
        # Generate new seed & vector; update content hash        
        header.encryption_iv = get_random_bytes(16)
        header.seed_rand = get_random_bytes(16)
        header.contents_hash = hashlib.sha256(buf).digest()
        
        self.log.debug("(Unencrypted) content: {0!r}".format(buf))
        self.log.debug("Generating hash for {0}-byte content: {1}".format(len(buf), hashlib.sha256(buf).digest()))
        # Update num groups/entries to match curr state
        header.nentries = len(self.entries)
        header.ngroups = len(self.groups)
        
        final_key = util.derive_key(seed_key=header.seed_key,
                                    seed_rand=header.seed_rand,
                                    rounds=header.key_enc_rounds,
                                    password=password, keyfile=keyfile)
        
        # FIXME: Remove this once we've tracked down issues.
        self.log.debug("(save) Final key: {0!r}, pass={1}".format(final_key, password))
        
        encrypted_content = util.encrypt_aes_cbc(buf, key=final_key, iv=header.encryption_iv)
        
        if hasattr(dbfile, 'write'):
            dbfile.write(header.encode() + encrypted_content)
        else:
            with open(self.filepath, "wb") as fp:
                fp.write(header.encode() + encrypted_content)