private void OnKdfChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) { var db = App.Kp2a.GetDb(); var previousKdfParams = db.KpDatabase.KdfParameters; Kp2aLog.Log("previous kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString()); db.KpDatabase.KdfParameters = KdfPool.Get( new PwUuid(MemUtil.HexStringToByteArray((string)preferenceChangeEventArgs.NewValue))) .GetDefaultParameters(); Kp2aLog.Log("--new kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString()); SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish((success, message) => { if (!success) { db.KpDatabase.KdfParameters = previousKdfParams; Toast.MakeText(Activity, message, ToastLength.Long).Show(); return; } UpdateKdfScreen(); })); ProgressTask pt = new ProgressTask(App.Kp2a, Activity, save); pt.Run(); }
public async Task Create(Credentials credentials, string name, DatabaseVersion version = DatabaseVersion.V4) { try { await Task.Run(() => { var compositeKey = CreateCompositeKey(credentials); var ioConnection = IOConnectionInfo.FromByteArray(new byte[] {}); _pwDatabase.New(ioConnection, compositeKey); _pwDatabase.Name = name; _pwDatabase.RootGroup.Name = name; _credentials = credentials; switch (version) { case DatabaseVersion.V4: _pwDatabase.KdfParameters = KdfPool.Get("Argon2").GetDefaultParameters(); _pwDatabase.DataCipherUuid = CipherPool.GlobalPool[1].CipherUuid; break; } }); } catch (Exception ex) { throw new ArgumentException(ex.Message, ex); } }
/// <summary> /// Generate a 32-byte (256-bit) key from the composite key. /// </summary> public ProtectedBinary GenerateKey32(KdfParameters p) { if (p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); } byte[] pbRaw32 = null, pbTrf32 = null; ProtectedBinary pbRet = null; try { pbRaw32 = CreateRawCompositeKey32(); if ((pbRaw32 == null) || (pbRaw32.Length != 32)) { Debug.Assert(false); return(null); } KdfEngine kdf = KdfPool.Get(p.KdfUuid); if (kdf == null) // CryptographicExceptions are translated to "file corrupted" { throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph + KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph + "UUID: " + p.KdfUuid.ToHexString() + "."); } pbTrf32 = kdf.Transform(pbRaw32, p); if (pbTrf32 == null) { Debug.Assert(false); return(null); } if (pbTrf32.Length != 32) { Debug.Assert(false); pbTrf32 = CryptoUtil.HashSha256(pbTrf32); } pbRet = new ProtectedBinary(true, pbTrf32); } finally { if (pbRaw32 != null) { MemUtil.ZeroByteArray(pbRaw32); } if (pbTrf32 != null) { MemUtil.ZeroByteArray(pbTrf32); } } return(pbRet); }
private void KdfTestTh(object o) { string strMsg = KLRes.UnknownError; try { KdfParameters p = (o as KdfParameters); if (p == null) { Debug.Assert(false); return; } KdfEngine kdf = KdfPool.Get(p.KdfUuid); if (kdf == null) { Debug.Assert(false); return; } byte[] pbMsg = new byte[32]; Program.GlobalRandom.NextBytes(pbMsg); kdf.Randomize(p); Stopwatch sw = Stopwatch.StartNew(); kdf.Transform(pbMsg, p); sw.Stop(); long lMS = sw.ElapsedMilliseconds; lMS = Math.Max(lMS, 1L); double dS = (double)lMS / 1000.0; strMsg = KPRes.TestSuccess + MessageService.NewParagraph + KPRes.TransformTime.Replace(@"{PARAM}", dS.ToString()); } catch (ThreadAbortException) { try { Thread.ResetAbort(); } catch (Exception) { Debug.Assert(false); } return; } catch (Exception ex) { Debug.Assert(false); if ((ex != null) && !string.IsNullOrEmpty(ex.Message)) { strMsg = ex.Message; } } finally { m_thKdf = null; } // Before continuation, to enable controls try { m_btnOK.Invoke(new KdfsDelegate(this.KdfTestPost), strMsg); } catch (Exception) { Debug.Assert(false); } }
private void SetKdfParameters(KdfParameters p) { if (p == null) { Debug.Assert(false); return; } KdfEngine kdf = KdfPool.Get(p.KdfUuid); if (kdf == null) { Debug.Assert(false); return; } for (int i = 0; i < m_cmbKdf.Items.Count; ++i) { string strKdf = (m_cmbKdf.Items[i] as string); if (string.IsNullOrEmpty(strKdf)) { Debug.Assert(false); continue; } if (strKdf.Equals(kdf.Name, StrUtil.CaseIgnoreCmp)) { bool bPrevInit = m_bInitializing; m_bInitializing = true; // Prevent selection handler m_cmbKdf.SelectedIndex = i; m_bInitializing = bPrevInit; break; } } if (kdf is AesKdf) { ulong uIt = p.GetUInt64(AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds); SetKdfParameters(uIt, 1024, 2); } else if (kdf is Argon2Kdf) { ulong uIt = p.GetUInt64(Argon2Kdf.ParamIterations, Argon2Kdf.DefaultIterations); ulong uMem = p.GetUInt64(Argon2Kdf.ParamMemory, Argon2Kdf.DefaultMemory); uint uPar = p.GetUInt32(Argon2Kdf.ParamParallelism, Argon2Kdf.DefaultParallelism); SetKdfParameters(uIt, uMem, uPar); } // else { Debug.Assert(false); } // Plugins may provide other KDFs }
private void UpdateKdfScreen() { var db = App.Kp2a.GetDb(); var kdf = KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid); var kdfpref = FindPreference(GetString(Resource.String.kdf_key)); kdfpref.Summary = kdf.Name; var kdfscreen = ((PreferenceScreen)FindPreference(GetString(Resource.String.kdf_screen_key))); if (kdf is AesKdf) { if (kdfscreen.FindPreference(GetString(Resource.String.rounds_key)) == null) { kdfscreen.AddPreference(aesRounds); } kdfscreen.RemovePreference(argon2rounds); kdfscreen.RemovePreference(argon2memory); kdfscreen.RemovePreference(argon2parallelism); aesRounds.Enabled = db.CanWrite; UpdateKdfSummary(aesRounds); } else { kdfscreen.RemovePreference(aesRounds); if (kdfscreen.FindPreference("argon2rounds") == null) { kdfscreen.AddPreference(argon2rounds); kdfscreen.AddPreference(argon2memory); kdfscreen.AddPreference(argon2parallelism); } UpdateKdfSummary(argon2rounds); UpdateKdfSummary(argon2memory); UpdateKdfSummary(argon2parallelism); } }
// 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; m_xmlWriter = null; 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"); } m_xmlWriter = XmlUtilEx.CreateXmlWriter(sXml); WriteDocument(pgRoot); m_xmlWriter.Flush(); } finally { CommonCleanUpWrite(lStreams, sHashing); if (pbCipherKey != null) { MemUtil.ZeroByteArray(pbCipherKey); } if (pbHmacKey64 != null) { MemUtil.ZeroByteArray(pbHmacKey64); } } }
private KdfEngine GetKdf() { return(KdfPool.Get(m_cmbKdf.Text)); }
// 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; m_xmlWriter = null; PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup); UTF8Encoding encNoBom = StrUtil.Utf8; CryptoRandom cr = CryptoRandom.Instance; byte[] pbCipherKey = null; byte[] pbHmacKey64 = null; m_pbsBinaries = new ProtectedBinarySet(true); m_pbsBinaries.AddFrom(pgRoot); List <Stream> lStreams = new List <Stream>(); lStreams.Add(sSaveTo); HashingStreamEx sHashing = new HashingStreamEx(sSaveTo, true, null); lStreams.Add(sHashing); try { // Fix history entries (should not be necessary; just for safety, // as e.g. XPath searches depend on correct history entry UUIDs) if (m_pwDatabase.MaintainBackups()) { Debug.Assert(false); } 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 || m_format == KdbxFormat.ProtocolBuffers) { 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"); } var stopWatch = Stopwatch.StartNew(); if (m_format == KdbxFormat.ProtocolBuffers) { KdbpFile.WriteDocument(m_pwDatabase, sXml, m_pbInnerRandomStreamKey, m_pbHashOfHeader); } else { #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(); } Kp2aLog.Log(String.Format("{1}: {0}ms", stopWatch.ElapsedMilliseconds, m_format == KdbxFormat.ProtocolBuffers ? "KdbpFile.WriteDocument" : "Xml WriteDocument")); } finally { if (pbCipherKey != null) { MemUtil.ZeroByteArray(pbCipherKey); } if (pbHmacKey64 != null) { MemUtil.ZeroByteArray(pbHmacKey64); } CommonCleanUpWrite(lStreams, sHashing); } }