public void TestGenerateKey32() { var originalKey = new byte[32]; var expectedKey = new byte[] { 0xF0, 0xED, 0x57, 0xD5, 0xF0, 0xDA, 0xF3, 0x47, 0x90, 0xD0, 0xDB, 0x43, 0x25, 0xC6, 0x81, 0x2C, 0x81, 0x6A, 0x0D, 0x94, 0x96, 0xA9, 0x03, 0xE1, 0x20, 0xD4, 0x3A, 0x3E, 0x45, 0xAD, 0x02, 0x65 }; const ulong rounds = 1; var composite = new CompositeKey(); AesKdf kdf = new AesKdf(); KdfParameters p = kdf.GetDefaultParameters(); p.SetUInt64(AesKdf.ParamRounds, rounds); p.SetByteArray(AesKdf.ParamSeed, originalKey); var key = composite.GenerateKey32(p); Assert.NotNull(key); var keyData = key.ReadData(); Assert.True(MemUtil.ArraysEqual(keyData, expectedKey)); }
public void TestAesKdf() { // Up to KeePass 2.34, the OtpKeyProv plugin used the public // CompositeKey.TransformKeyManaged method (and a finalizing // SHA-256 computation), which became an internal method of // the AesKdf class in KeePass 2.35, thus OtpKeyProv now // uses the AesKdf class; here we ensure that the results // are the same var r = CryptoRandom.NewWeakRandom(); var pbKey = new byte[32]; r.NextBytes(pbKey); var pbSeed = new byte[32]; r.NextBytes(pbSeed); var uRounds = (ulong)r.Next(1, 0x7FFF); var pbMan = new byte[pbKey.Length]; Array.Copy(pbKey, pbMan, pbKey.Length); Assert.True(AesKdf.TransformKeyManaged(pbMan, pbSeed, uRounds)); pbMan = CryptoUtil.HashSha256(pbMan); var kdf = new AesKdf(); var p = kdf.GetDefaultParameters(); p.SetUInt64(AesKdf.ParamRounds, uRounds); p.SetByteArray(AesKdf.ParamSeed, pbSeed); var pbKdf = kdf.Transform(pbKey, p); Assert.True(MemUtil.ArraysEqual(pbMan, pbKdf)); }
public ProtectedBinary GenerateKey32(byte[] pbKeySeed32, ulong uNumRounds) { Debug.Assert(pbKeySeed32 != null); if (pbKeySeed32 == null) { throw new ArgumentNullException("pbKeySeed32"); } Debug.Assert(pbKeySeed32.Length == 32); if (pbKeySeed32.Length != 32) { throw new ArgumentException("pbKeySeed32"); } AesKdf kdf = new AesKdf(); KdfParameters p = kdf.GetDefaultParameters(); p.SetUInt64(AesKdf.ParamRounds, uNumRounds); p.SetByteArray(AesKdf.ParamSeed, pbKeySeed32); return(GenerateKey32(p)); }
public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, IStatusLogger slLogger) { PwDatabase pd = pwExportInfo.ContextDatabase; PwGroup pgRoot = pwExportInfo.DataGroup; // Remove everything that requires KDBX 4 or higher; // see also KdbxFile.GetMinKdbxVersion PwUuid puCipher = pd.DataCipherUuid; if (puCipher.Equals(ChaCha20Engine.ChaCha20Uuid)) { pd.DataCipherUuid = StandardAesEngine.AesUuid; } KdfParameters pKdf = pd.KdfParameters; AesKdf kdfAes = new AesKdf(); if (!pKdf.KdfUuid.Equals(kdfAes.Uuid)) { pd.KdfParameters = kdfAes.GetDefaultParameters(); } VariantDictionary vdPublic = pd.PublicCustomData; pd.PublicCustomData = new VariantDictionary(); List <PwGroup> lCustomGK = new List <PwGroup>(); List <StringDictionaryEx> lCustomGV = new List <StringDictionaryEx>(); List <PwEntry> lCustomEK = new List <PwEntry>(); List <StringDictionaryEx> lCustomEV = new List <StringDictionaryEx>(); GroupHandler gh = delegate(PwGroup pg) { if (pg == null) { Debug.Assert(false); return(true); } if (pg.CustomData.Count > 0) { lCustomGK.Add(pg); lCustomGV.Add(pg.CustomData); pg.CustomData = new StringDictionaryEx(); } return(true); }; EntryHandler eh = delegate(PwEntry pe) { if (pe == null) { Debug.Assert(false); return(true); } if (pe.CustomData.Count > 0) { lCustomEK.Add(pe); lCustomEV.Add(pe.CustomData); pe.CustomData = new StringDictionaryEx(); } return(true); }; gh(pgRoot); pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh); try { KdbxFile kdbx = new KdbxFile(pd); kdbx.ForceVersion = KdbxFile.FileVersion32_3_1; kdbx.Save(sOutput, pgRoot, KdbxFormat.Default, slLogger); } finally { // Restore pd.DataCipherUuid = puCipher; pd.KdfParameters = pKdf; pd.PublicCustomData = vdPublic; for (int i = 0; i < lCustomGK.Count; ++i) { lCustomGK[i].CustomData = lCustomGV[i]; } for (int i = 0; i < lCustomEK.Count; ++i) { lCustomEK[i].CustomData = lCustomEV[i]; } } return(true); }
private bool ReadHeaderField(BinaryReaderEx brSource) { Debug.Assert(brSource != null); if (brSource == null) { throw new ArgumentNullException("brSource"); } byte btFieldID = brSource.ReadByte(); int cbSize; Debug.Assert(m_uFileVersion > 0); if (m_uFileVersion < FileVersion32_4) { cbSize = (int)MemUtil.BytesToUInt16(brSource.ReadBytes(2)); } else { cbSize = MemUtil.BytesToInt32(brSource.ReadBytes(4)); } if (cbSize < 0) { throw new FormatException(KLRes.FileCorrupted); } byte[] pbData = MemUtil.EmptyByteArray; if (cbSize > 0) { pbData = brSource.ReadBytes(cbSize); } bool bResult = true; KdbxHeaderFieldID kdbID = (KdbxHeaderFieldID)btFieldID; switch (kdbID) { case KdbxHeaderFieldID.EndOfHeader: bResult = false; // Returning false indicates end of header break; case KdbxHeaderFieldID.CipherID: SetCipher(pbData); break; case KdbxHeaderFieldID.CompressionFlags: SetCompressionFlags(pbData); break; case KdbxHeaderFieldID.MasterSeed: m_pbMasterSeed = pbData; CryptoRandom.Instance.AddEntropy(pbData); break; // Obsolete; for backward compatibility only case KdbxHeaderFieldID.TransformSeed: Debug.Assert(m_uFileVersion < FileVersion32_4); AesKdf kdfS = new AesKdf(); if (!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfS.Uuid)) { m_pwDatabase.KdfParameters = kdfS.GetDefaultParameters(); } // m_pbTransformSeed = pbData; m_pwDatabase.KdfParameters.SetByteArray(AesKdf.ParamSeed, pbData); CryptoRandom.Instance.AddEntropy(pbData); break; // Obsolete; for backward compatibility only case KdbxHeaderFieldID.TransformRounds: Debug.Assert(m_uFileVersion < FileVersion32_4); AesKdf kdfR = new AesKdf(); if (!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfR.Uuid)) { m_pwDatabase.KdfParameters = kdfR.GetDefaultParameters(); } // m_pwDatabase.KeyEncryptionRounds = MemUtil.BytesToUInt64(pbData); m_pwDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, MemUtil.BytesToUInt64(pbData)); break; case KdbxHeaderFieldID.EncryptionIV: m_pbEncryptionIV = pbData; break; case KdbxHeaderFieldID.InnerRandomStreamKey: Debug.Assert(m_uFileVersion < FileVersion32_4); Debug.Assert(m_pbInnerRandomStreamKey == null); m_pbInnerRandomStreamKey = pbData; CryptoRandom.Instance.AddEntropy(pbData); break; case KdbxHeaderFieldID.StreamStartBytes: Debug.Assert(m_uFileVersion < FileVersion32_4); m_pbStreamStartBytes = pbData; break; case KdbxHeaderFieldID.InnerRandomStreamID: Debug.Assert(m_uFileVersion < FileVersion32_4); SetInnerRandomStreamID(pbData); break; case KdbxHeaderFieldID.KdfParameters: m_pwDatabase.KdfParameters = KdfParameters.DeserializeExt(pbData); break; case KdbxHeaderFieldID.PublicCustomData: Debug.Assert(m_pwDatabase.PublicCustomData.Count == 0); m_pwDatabase.PublicCustomData = VariantDictionary.Deserialize(pbData); break; default: Debug.Assert(false); if (m_slLogger != null) { m_slLogger.SetText(KLRes.UnknownHeaderId + ": " + kdbID.ToString() + "!", LogStatusType.Warning); } break; } return(bResult); }