public void Save(Stream sSaveTo, PwGroup pgDataSource, Kdb4Format format,
IStatusLogger slLogger)
{
Debug.Assert(sSaveTo != null);
if(sSaveTo == null) throw new ArgumentNullException("sSaveTo");
m_format = format;
m_slLogger = slLogger;
HashingStreamEx hashedStream = new HashingStreamEx(sSaveTo, true, null);
UTF8Encoding encNoBom = new UTF8Encoding(false, false);
CryptoRandom cr = CryptoRandom.Instance;
try
{
m_pbMasterSeed = cr.GetRandomBytes(32);
m_pbTransformSeed = cr.GetRandomBytes(32);
m_pbEncryptionIV = cr.GetRandomBytes(16);
m_pbProtectedStreamKey = cr.GetRandomBytes(32);
m_craInnerRandomStream = CrsAlgorithm.Salsa20;
m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbProtectedStreamKey);
m_pbStreamStartBytes = cr.GetRandomBytes(32);
Stream writerStream;
BinaryWriter bw = null;
if(m_format == Kdb4Format.Default)
{
bw = new BinaryWriter(hashedStream, encNoBom);
WriteHeader(bw); // Also flushes bw
Stream sEncrypted = AttachStreamEncryptor(hashedStream);
if((sEncrypted == null) || (sEncrypted == hashedStream))
throw new SecurityException(KLRes.CryptoStreamFailed);
sEncrypted.Write(m_pbStreamStartBytes, 0, m_pbStreamStartBytes.Length);
Stream sHashed = new HashedBlockStream(sEncrypted, true);
if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip)
writerStream = new GZipStream(sHashed, CompressionMode.Compress);
else
writerStream = sHashed;
}
else if(m_format == Kdb4Format.PlainXml)
writerStream = hashedStream;
else { Debug.Assert(false); throw new FormatException("KdbFormat"); }
m_xmlWriter = new XmlTextWriter(writerStream, encNoBom);
WriteDocument(pgDataSource);
m_xmlWriter.Flush();
m_xmlWriter.Close();
writerStream.Close();
GC.KeepAlive(bw);
}
finally { CommonCleanUpWrite(sSaveTo, hashedStream); }
}