176 lines
5.1 KiB
C#
176 lines
5.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
#if !EXCLUDE_KEYTRANSFORM
|
|
using Com.Keepassdroid.Database;
|
|
using Com.Keepassdroid.Database.Exception;
|
|
#endif
|
|
using KeePassLib;
|
|
using KeePassLib.Cryptography;
|
|
using KeePassLib.Interfaces;
|
|
using KeePassLib.Keys;
|
|
using KeePassLib.Security;
|
|
using Exception = System.Exception;
|
|
using PwIcon = KeePassLib.PwIcon;
|
|
|
|
namespace keepass2android
|
|
{
|
|
class KdbDatabaseLoader: IDatabaseLoader
|
|
{
|
|
private Dictionary<PwUuid, AdditionalGroupData> _groupData = new Dictionary<PwUuid, AdditionalGroupData>();
|
|
|
|
public void PopulateDatabaseFromStream(PwDatabase db, CompositeKey key, Stream s, IStatusLogger slLogger)
|
|
{
|
|
#if !EXCLUDE_KEYTRANSFORM
|
|
var importer = new Com.Keepassdroid.Database.Load.ImporterV3();
|
|
|
|
var hashingStream = new HashingStreamEx(s, false, new SHA256Managed());
|
|
|
|
string password = "";//no need to distinguish between null and "" because empty passwords are invalid (and null is not allowed)
|
|
KcpPassword passwordKey = (KcpPassword)key.GetUserKey(typeof(KcpPassword));
|
|
if (passwordKey != null)
|
|
{
|
|
password = passwordKey.Password.ReadString();
|
|
}
|
|
|
|
KcpKeyFile passwordKeyfile = (KcpKeyFile)key.GetUserKey(typeof(KcpKeyFile));
|
|
MemoryStream keyfileStream = null;
|
|
if (passwordKeyfile != null)
|
|
{
|
|
keyfileStream = new MemoryStream(passwordKeyfile.RawFileData.ReadData());
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
var dbv3 = importer.OpenDatabase(hashingStream, password, keyfileStream);
|
|
|
|
db.Name = dbv3.Name;
|
|
db.RootGroup = ConvertGroup(dbv3.RootGroup);
|
|
|
|
}
|
|
catch (Java.IO.FileNotFoundException e)
|
|
{
|
|
throw new FileNotFoundException(
|
|
e.Message, e);
|
|
}
|
|
catch (Java.Lang.Exception e)
|
|
{
|
|
throw new Exception(e.LocalizedMessage ??
|
|
e.Message ??
|
|
e.GetType().Name, e);
|
|
}
|
|
|
|
HashOfLastStream = hashingStream.Hash;
|
|
if (HashOfLastStream == null)
|
|
throw new Exception("hashing didn't work"); //todo remove
|
|
#else
|
|
throw new Exception("Kdb is excluded with Key transform!");
|
|
#endif
|
|
}
|
|
|
|
#if !EXCLUDE_KEYTRANSFORM
|
|
|
|
private PwGroup ConvertGroup(PwGroupV3 groupV3)
|
|
{
|
|
PwGroup pwGroup = new PwGroup(true, false);
|
|
pwGroup.Name = groupV3.Name;
|
|
|
|
pwGroup.CreationTime = ConvertTime(groupV3.TCreation);
|
|
pwGroup.LastAccessTime = ConvertTime(groupV3.TLastAccess);
|
|
pwGroup.LastModificationTime = ConvertTime(groupV3.TLastMod);
|
|
pwGroup.Expires = !PwGroupV3.NeverExpire.Equals(groupV3.TExpire);
|
|
if (pwGroup.Expires)
|
|
pwGroup.ExpiryTime = ConvertTime(groupV3.TExpire);
|
|
|
|
if (groupV3.Icon != null)
|
|
pwGroup.IconId = (PwIcon) groupV3.Icon.IconId;
|
|
_groupData.Add(pwGroup.Uuid, new AdditionalGroupData
|
|
{
|
|
Flags = groupV3.Flags,
|
|
Id = groupV3.Id.Id
|
|
});
|
|
|
|
|
|
for (int i = 0; i < groupV3.ChildGroups.Count;i++)
|
|
{
|
|
pwGroup.AddGroup(ConvertGroup(groupV3.GetGroupAt(i)), true);
|
|
}
|
|
for (int i = 0; i < groupV3.ChildEntries.Count; i++)
|
|
{
|
|
var entry = groupV3.GetEntryAt(i);
|
|
if (entry.IsMetaStream)
|
|
continue;
|
|
pwGroup.AddEntry(ConvertEntry(entry), true);
|
|
}
|
|
|
|
return pwGroup;
|
|
}
|
|
|
|
private PwEntry ConvertEntry(PwEntryV3 entryV3)
|
|
{
|
|
PwEntry pwEntry = new PwEntry(false, false);
|
|
pwEntry.Uuid = new PwUuid(entryV3.Uuid.ToArray());
|
|
pwEntry.CreationTime = ConvertTime(entryV3.TCreation);
|
|
pwEntry.LastAccessTime = ConvertTime(entryV3.TLastAccess);
|
|
pwEntry.LastModificationTime = ConvertTime(entryV3.TLastMod);
|
|
|
|
pwEntry.Expires = entryV3.Expires();
|
|
if (pwEntry.Expires)
|
|
pwEntry.ExpiryTime = ConvertTime(entryV3.TExpire);
|
|
|
|
if (entryV3.Icon != null)
|
|
pwEntry.IconId = (PwIcon) entryV3.Icon.IconId;
|
|
SetFieldIfAvailable(pwEntry, PwDefs.TitleField, false, entryV3.Title);
|
|
SetFieldIfAvailable(pwEntry, PwDefs.UserNameField, false, entryV3.Username);
|
|
SetFieldIfAvailable(pwEntry, PwDefs.UrlField, false, entryV3.Url);
|
|
SetFieldIfAvailable(pwEntry, PwDefs.PasswordField, true, entryV3.Password);
|
|
SetFieldIfAvailable(pwEntry, PwDefs.NotesField, true, entryV3.Additional);
|
|
|
|
if ((entryV3.GetBinaryData() != null) && (entryV3.GetBinaryData().Length > 0))
|
|
{
|
|
pwEntry.Binaries.Set(entryV3.BinaryDesc, new ProtectedBinary(true, entryV3.GetBinaryData()));
|
|
}
|
|
return pwEntry;
|
|
}
|
|
|
|
private void SetFieldIfAvailable(PwEntry pwEntry, string fieldName, bool makeProtected, string value)
|
|
{
|
|
if (value != null)
|
|
{
|
|
pwEntry.Strings.Set(fieldName, new ProtectedString(makeProtected, value));
|
|
}
|
|
|
|
}
|
|
|
|
private DateTime ConvertTime(PwDate date)
|
|
{
|
|
if (date == null)
|
|
return PwDefs.DtDefaultNow;
|
|
return JavaTimeToCSharp(date.JDate.Time);
|
|
}
|
|
|
|
private DateTime JavaTimeToCSharp(long javatime)
|
|
{
|
|
return new DateTime(1970, 1, 1).AddMilliseconds(javatime);
|
|
|
|
}
|
|
#endif
|
|
public byte[] HashOfLastStream { get; private set; }
|
|
public bool CanWrite { get { return false; } }
|
|
public string SuccessMessage { get
|
|
{
|
|
return
|
|
".kdb-support is read-only. Export as .kdbx if you want to modify the database. This app is for use with Keepass 2.x!";
|
|
} }
|
|
}
|
|
|
|
|
|
internal class AdditionalGroupData
|
|
{
|
|
public int Id { get; set; }
|
|
public int Flags { get; set; }
|
|
}
|
|
} |