Flush() public method

public Flush ( ) : void
return void
コード例 #1
0
		// public void Save(string strFile, PwGroup pgDataSource, KdbxFormat fmt,
		//	IStatusLogger slLogger)
		// {
		//	bool bMadeUnhidden = UrlUtil.UnhideFile(strFile);
		//
		//	IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
		//	this.Save(IOConnection.OpenWrite(ioc), pgDataSource, format, slLogger);
		//
		//	if(bMadeUnhidden) UrlUtil.HideFile(strFile, true); // Hide again
		// }

		/// <summary>
		/// Save the contents of the current <c>PwDatabase</c> to a KDBX file.
		/// </summary>
		/// <param name="sSaveTo">Stream to write the KDBX file into.</param>
		/// <param name="pgDataSource">Group containing all groups and
		/// entries to write. If <c>null</c>, the complete database will
		/// be written.</param>
		/// <param name="fmt">Format of the file to create.</param>
		/// <param name="slLogger">Logger that recieves status information.</param>
		public void Save(Stream sSaveTo, PwGroup pgDataSource, KdbxFormat fmt,
			IStatusLogger slLogger)
		{
			Debug.Assert(sSaveTo != null);
			if(sSaveTo == null) throw new ArgumentNullException("sSaveTo");

			if(m_bUsedOnce)
				throw new InvalidOperationException("Do not reuse KdbxFile objects!");
			m_bUsedOnce = true;

			m_format = fmt;
			m_slLogger = slLogger;

			PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
			UTF8Encoding encNoBom = StrUtil.Utf8;
			CryptoRandom cr = CryptoRandom.Instance;
			byte[] pbCipherKey = null;
			byte[] pbHmacKey64 = null;

			m_pbsBinaries.Clear();
			m_pbsBinaries.AddFrom(pgRoot);

			List<Stream> lStreams = new List<Stream>();
			lStreams.Add(sSaveTo);

			HashingStreamEx sHashing = new HashingStreamEx(sSaveTo, true, null);
			lStreams.Add(sHashing);

			try
			{
				m_uFileVersion = GetMinKdbxVersion();

				int cbEncKey, cbEncIV;
				ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV);

				m_pbMasterSeed = cr.GetRandomBytes(32);
				m_pbEncryptionIV = cr.GetRandomBytes((uint)cbEncIV);

				// m_pbTransformSeed = cr.GetRandomBytes(32);
				PwUuid puKdf = m_pwDatabase.KdfParameters.KdfUuid;
				KdfEngine kdf = KdfPool.Get(puKdf);
				if(kdf == null)
					throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph +
						// KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
						"UUID: " + puKdf.ToHexString() + ".");
				kdf.Randomize(m_pwDatabase.KdfParameters);

				if(m_format == KdbxFormat.Default)
				{
					if(m_uFileVersion < FileVersion32_4)
					{
						m_craInnerRandomStream = CrsAlgorithm.Salsa20;
						m_pbInnerRandomStreamKey = cr.GetRandomBytes(32);
					}
					else // KDBX >= 4
					{
						m_craInnerRandomStream = CrsAlgorithm.ChaCha20;
						m_pbInnerRandomStreamKey = cr.GetRandomBytes(64);
					}

					m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
						m_pbInnerRandomStreamKey);
				}

				if(m_uFileVersion < FileVersion32_4)
					m_pbStreamStartBytes = cr.GetRandomBytes(32);

				Stream sXml;
				if(m_format == KdbxFormat.Default)
				{
					byte[] pbHeader = GenerateHeader();
					m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader);

					MemUtil.Write(sHashing, pbHeader);
					sHashing.Flush();

					ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64);

					Stream sPlain;
					if(m_uFileVersion < FileVersion32_4)
					{
						Stream sEncrypted = EncryptStream(sHashing, iCipher,
							pbCipherKey, cbEncIV, true);
						if((sEncrypted == null) || (sEncrypted == sHashing))
							throw new SecurityException(KLRes.CryptoStreamFailed);
						lStreams.Add(sEncrypted);

						MemUtil.Write(sEncrypted, m_pbStreamStartBytes);

						sPlain = new HashedBlockStream(sEncrypted, true);
					}
					else // KDBX >= 4
					{
						// For integrity checking (without knowing the master key)
						MemUtil.Write(sHashing, m_pbHashOfHeader);

						byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64);
						MemUtil.Write(sHashing, pbHeaderHmac);

						Stream sBlocks = new HmacBlockStream(sHashing, true,
							true, pbHmacKey64);
						lStreams.Add(sBlocks);

						sPlain = EncryptStream(sBlocks, iCipher, pbCipherKey,
							cbEncIV, true);
						if((sPlain == null) || (sPlain == sBlocks))
							throw new SecurityException(KLRes.CryptoStreamFailed);
					}
					lStreams.Add(sPlain);

					if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip)
					{
						sXml = new GZipStream(sPlain, CompressionMode.Compress);
						lStreams.Add(sXml);
					}
					else sXml = sPlain;

					if(m_uFileVersion >= FileVersion32_4)
						WriteInnerHeader(sXml); // Binary header before XML
				}
				else if(m_format == KdbxFormat.PlainXml)
					sXml = sHashing;
				else
				{
					Debug.Assert(false);
					throw new ArgumentOutOfRangeException("fmt");
				}

#if KeePassUAP
				XmlWriterSettings xws = new XmlWriterSettings();
				xws.Encoding = encNoBom;
				xws.Indent = true;
				xws.IndentChars = "\t";
				xws.NewLineOnAttributes = false;

				XmlWriter xw = XmlWriter.Create(sXml, xws);
#else
				XmlTextWriter xw = new XmlTextWriter(sXml, encNoBom);

				xw.Formatting = Formatting.Indented;
				xw.IndentChar = '\t';
				xw.Indentation = 1;
#endif
				m_xmlWriter = xw;

				WriteDocument(pgRoot);

				m_xmlWriter.Flush();
				m_xmlWriter.Close();
			}
			finally
			{
				if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey);
				if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64);

				CommonCleanUpWrite(lStreams, sHashing);
			}
		}