mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-22 17:22:17 -05:00
Implemented loading of Keepass 1 (kdb) files. First test passed!
This commit is contained in:
parent
12dbe597ce
commit
8bbd18d3f8
@ -9,5 +9,7 @@ namespace KeePassLib
|
|||||||
void PopulateDatabaseFromStream(PwDatabase db, CompositeKey key, Stream s, IStatusLogger slLogger);
|
void PopulateDatabaseFromStream(PwDatabase db, CompositeKey key, Stream s, IStatusLogger slLogger);
|
||||||
|
|
||||||
byte[] HashOfLastStream { get; }
|
byte[] HashOfLastStream { get; }
|
||||||
|
|
||||||
|
bool CanWrite { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,7 +20,7 @@
|
|||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
<DefineConstants>TRACE;DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_KEYTRANSFORM;INCLUDE_FILECHOOSER;INCLUDE_JAVAFILESTORAGE</DefineConstants>
|
<DefineConstants>TRACE;DEBUG;EXCLUDE_TWOFISH;EXCLUDE_KEYBOARD;EXCLUDE_KEYTRANSFORM;EXCLUDE_FILECHOOSER;EXCLUDE_JAVAFILESTORAGE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -55,6 +55,9 @@
|
|||||||
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
<Compile Include="database\CheckDatabaseForChanges.cs" />
|
||||||
<Compile Include="database\edit\EditGroup.cs" />
|
<Compile Include="database\edit\EditGroup.cs" />
|
||||||
<Compile Include="database\edit\MoveElement.cs" />
|
<Compile Include="database\edit\MoveElement.cs" />
|
||||||
|
<Compile Include="database\DatabaseV1.cs" />
|
||||||
|
<Compile Include="database\KdbDatabaseLoader.cs" />
|
||||||
|
<Compile Include="database\KdbxDatabaseLoader.cs" />
|
||||||
<Compile Include="database\SynchronizeCachedDatabase.cs" />
|
<Compile Include="database\SynchronizeCachedDatabase.cs" />
|
||||||
<Compile Include="Io\BuiltInFileStorage.cs" />
|
<Compile Include="Io\BuiltInFileStorage.cs" />
|
||||||
<Compile Include="Io\CachingFileStorage.cs" />
|
<Compile Include="Io\CachingFileStorage.cs" />
|
||||||
@ -112,6 +115,10 @@
|
|||||||
<Project>{545b4a6b-8bba-4fbe-92fc-4ac060122a54}</Project>
|
<Project>{545b4a6b-8bba-4fbe-92fc-4ac060122a54}</Project>
|
||||||
<Name>KeePassLib2Android</Name>
|
<Name>KeePassLib2Android</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\KP2AKdbLibraryBinding\KP2AKdbLibraryBinding.csproj">
|
||||||
|
<Project>{70d3844a-d9fa-4a64-b205-a84c6a822196}</Project>
|
||||||
|
<Name>KP2AKdbLibraryBinding</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
@ -112,8 +112,15 @@ namespace keepass2android
|
|||||||
Loaded = true;
|
Loaded = true;
|
||||||
KpDatabase = pwDatabase;
|
KpDatabase = pwDatabase;
|
||||||
SearchHelper = new SearchDbHelper(app);
|
SearchHelper = new SearchDbHelper(app);
|
||||||
|
|
||||||
|
CanWrite = databaseLoader.CanWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether it is possible to make changes to this database
|
||||||
|
/// </summary>
|
||||||
|
public bool CanWrite { get; set; }
|
||||||
|
|
||||||
protected virtual void PopulateDatabaseFromStream(PwDatabase pwDatabase, Stream s, IOConnectionInfo iocInfo, CompositeKey compositeKey, ProgressDialogStatusLogger status, IDatabaseLoader databaseLoader)
|
protected virtual void PopulateDatabaseFromStream(PwDatabase pwDatabase, Stream s, IOConnectionInfo iocInfo, CompositeKey compositeKey, ProgressDialogStatusLogger status, IDatabaseLoader databaseLoader)
|
||||||
{
|
{
|
||||||
IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
|
IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
|
||||||
|
@ -1,27 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using Android.Content;
|
|
||||||
using Com.Keepassdroid.Database;
|
using Com.Keepassdroid.Database;
|
||||||
using Com.Keepassdroid.Database.Exception;
|
using Com.Keepassdroid.Database.Exception;
|
||||||
using Java.Lang;
|
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
using KeePassLib.Cryptography;
|
using KeePassLib.Cryptography;
|
||||||
using KeePassLib.Cryptography.Cipher;
|
|
||||||
using KeePassLib.Interfaces;
|
using KeePassLib.Interfaces;
|
||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
|
using KeePassLib.Security;
|
||||||
using Exception = System.Exception;
|
using Exception = System.Exception;
|
||||||
|
using PwIcon = KeePassLib.PwIcon;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
class KdbDatabaseLoader: IDatabaseLoader
|
class KdbDatabaseLoader: IDatabaseLoader
|
||||||
{
|
{
|
||||||
private Context _ctx;
|
private Dictionary<PwUuid, AdditionalGroupData> _groupData = new Dictionary<PwUuid, AdditionalGroupData>();
|
||||||
|
|
||||||
public KdbDatabaseLoader(Context ctx)
|
|
||||||
{
|
|
||||||
_ctx = ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PopulateDatabaseFromStream(PwDatabase db, CompositeKey key, Stream s, IStatusLogger slLogger)
|
public void PopulateDatabaseFromStream(PwDatabase db, CompositeKey key, Stream s, IStatusLogger slLogger)
|
||||||
{
|
{
|
||||||
@ -49,6 +45,8 @@ namespace keepass2android
|
|||||||
var dbv3 = importer.OpenDatabase(hashingStream, password, keyfile);
|
var dbv3 = importer.OpenDatabase(hashingStream, password, keyfile);
|
||||||
|
|
||||||
db.Name = dbv3.Name;
|
db.Name = dbv3.Name;
|
||||||
|
db.RootGroup = ConvertGroup(dbv3.RootGroup);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (InvalidPasswordException e) {
|
catch (InvalidPasswordException e) {
|
||||||
|
|
||||||
@ -71,6 +69,98 @@ namespace keepass2android
|
|||||||
throw new Exception("hashing didn't work"); //todo remove
|
throw new Exception("hashing didn't work"); //todo remove
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] HashOfLastStream { get; private set; }
|
public byte[] HashOfLastStream { get; private set; }
|
||||||
|
public bool CanWrite { get { return false; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AdditionalGroupData
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Flags { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,5 +27,6 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] HashOfLastStream { get; private set; }
|
public byte[] HashOfLastStream { get; private set; }
|
||||||
|
public bool CanWrite { get { return true; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,7 +19,6 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Android.App;
|
|
||||||
using KeePassLib;
|
using KeePassLib;
|
||||||
using KeePassLib.Keys;
|
using KeePassLib.Keys;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
@ -33,6 +32,7 @@ namespace keepass2android
|
|||||||
private readonly string _keyfileOrProvider;
|
private readonly string _keyfileOrProvider;
|
||||||
private readonly IKp2aApp _app;
|
private readonly IKp2aApp _app;
|
||||||
private readonly bool _rememberKeyfile;
|
private readonly bool _rememberKeyfile;
|
||||||
|
IDatabaseLoader _loader;
|
||||||
|
|
||||||
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish): base(finish)
|
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish): base(finish)
|
||||||
{
|
{
|
||||||
@ -68,8 +68,8 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
|
|
||||||
//ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess:
|
//ok, try to load the database. Let's start with Kdbx format and retry later if that is the wrong guess:
|
||||||
IDatabaseLoader loader = new KdbxDatabaseLoader(KdbpFile.GetFormatToUse(_ioc));
|
_loader = new KdbxDatabaseLoader(KdbpFile.GetFormatToUse(_ioc));
|
||||||
TryLoad(databaseStream, loader);
|
TryLoad(databaseStream);
|
||||||
}
|
}
|
||||||
catch (KeyFileException)
|
catch (KeyFileException)
|
||||||
{
|
{
|
||||||
@ -99,7 +99,7 @@ namespace keepass2android
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TryLoad(MemoryStream databaseStream, IDatabaseLoader loader)
|
private void TryLoad(MemoryStream databaseStream)
|
||||||
{
|
{
|
||||||
//create a copy of the stream so we can try again if we get an exception which indicates we should change parameters
|
//create a copy of the stream so we can try again if we get an exception which indicates we should change parameters
|
||||||
//This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors.
|
//This is not optimal in terms of (short-time) memory usage but is hard to avoid because the Keepass library closes streams also in case of errors.
|
||||||
@ -112,14 +112,15 @@ namespace keepass2android
|
|||||||
//now let's go:
|
//now let's go:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, loader);
|
_app.LoadDatabase(_ioc, workingCopy, _compositeKey, StatusLogger, _loader);
|
||||||
SaveFileData(_ioc, _keyfileOrProvider);
|
SaveFileData(_ioc, _keyfileOrProvider);
|
||||||
Kp2aLog.Log("LoadDB OK");
|
Kp2aLog.Log("LoadDB OK");
|
||||||
Finish(true);
|
Finish(true);
|
||||||
}
|
}
|
||||||
catch (OldFormatException)
|
catch (OldFormatException)
|
||||||
{
|
{
|
||||||
TryLoad(databaseStream, new KdbDatabaseLoader(Application.Context));
|
_loader = new KdbDatabaseLoader();
|
||||||
|
TryLoad(databaseStream);
|
||||||
}
|
}
|
||||||
catch (InvalidCompositeKeyException)
|
catch (InvalidCompositeKeyException)
|
||||||
{
|
{
|
||||||
@ -131,7 +132,7 @@ namespace keepass2android
|
|||||||
//retry without password:
|
//retry without password:
|
||||||
_compositeKey.RemoveUserKey(passwordKey);
|
_compositeKey.RemoveUserKey(passwordKey);
|
||||||
//retry:
|
//retry:
|
||||||
TryLoad(databaseStream, loader);
|
TryLoad(databaseStream);
|
||||||
}
|
}
|
||||||
else throw;
|
else throw;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
|
using KeePassLib;
|
||||||
using KeePassLib.Serialization;
|
using KeePassLib.Serialization;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using keepass2android;
|
using keepass2android;
|
||||||
@ -14,7 +15,15 @@ namespace Kp2aUnitTests
|
|||||||
{
|
{
|
||||||
private void RunLoadTest(string filenameWithoutDir, string password, string keyfile)
|
private void RunLoadTest(string filenameWithoutDir, string password, string keyfile)
|
||||||
{
|
{
|
||||||
Android.Util.Log.Debug("KP2ATest", "Starting for " + filenameWithoutDir+" with " + password+"/"+keyfile);
|
var app = PerformLoad(filenameWithoutDir, password, keyfile);
|
||||||
|
|
||||||
|
Assert.AreEqual(6,app.GetDb().KpDatabase.RootGroup.Groups.Count());
|
||||||
|
Assert.AreEqual(2,app.GetDb().KpDatabase.RootGroup.Entries.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IKp2aApp PerformLoad(string filenameWithoutDir, string password, string keyfile)
|
||||||
|
{
|
||||||
|
Android.Util.Log.Debug("KP2ATest", "Starting for " + filenameWithoutDir + " with " + password + "/" + keyfile);
|
||||||
|
|
||||||
IKp2aApp app = new TestKp2aApp();
|
IKp2aApp app = new TestKp2aApp();
|
||||||
app.CreateNewDatabase();
|
app.CreateNewDatabase();
|
||||||
@ -22,7 +31,7 @@ namespace Kp2aUnitTests
|
|||||||
var key = CreateKey(password, keyfile);
|
var key = CreateKey(password, keyfile);
|
||||||
string loadErrorMessage = "";
|
string loadErrorMessage = "";
|
||||||
|
|
||||||
LoadDb task = new LoadDb(app, new IOConnectionInfo { Path = TestDbDirectory+filenameWithoutDir }, null,
|
LoadDb task = new LoadDb(app, new IOConnectionInfo {Path = TestDbDirectory + filenameWithoutDir}, null,
|
||||||
key, keyfile, new ActionOnFinish((success, message) =>
|
key, keyfile, new ActionOnFinish((success, message) =>
|
||||||
{
|
{
|
||||||
loadErrorMessage = message;
|
loadErrorMessage = message;
|
||||||
@ -36,26 +45,29 @@ namespace Kp2aUnitTests
|
|||||||
pt.Run();
|
pt.Run();
|
||||||
pt.JoinWorkerThread();
|
pt.JoinWorkerThread();
|
||||||
Android.Util.Log.Debug("KP2ATest", "PT.run finished");
|
Android.Util.Log.Debug("KP2ATest", "PT.run finished");
|
||||||
Assert.IsTrue(loadSuccesful, "didn't succesfully load database :-( "+loadErrorMessage);
|
Assert.IsTrue(loadSuccesful, "didn't succesfully load database :-( " + loadErrorMessage);
|
||||||
|
return app;
|
||||||
Assert.AreEqual(6,app.GetDb().KpDatabase.RootGroup.Groups.Count());
|
|
||||||
Assert.AreEqual(2,app.GetDb().KpDatabase.RootGroup.Entries.Count());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestLoadWithPasswordOnly()
|
public void TestLoadWithPasswordOnly()
|
||||||
{
|
{
|
||||||
RunLoadTest("passwordonly.kdbx", DefaultPassword, "");
|
RunLoadTest("passwordonly.kdbx", DefaultPassword, "");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestLoadKdb1()
|
public void TestLoadKdb1()
|
||||||
{
|
{
|
||||||
RunLoadTest("test1.kdb", "12345", "");
|
var app = PerformLoad("keepass.kdb", "test", "");
|
||||||
|
|
||||||
|
//contents of the kdb file are a little different because the root group cannot have entries
|
||||||
|
Assert.AreEqual(6, app.GetDb().KpDatabase.RootGroup.Groups.Count());
|
||||||
|
PwGroup generalGroup = app.GetDb().KpDatabase.RootGroup.Groups.Single(g => g.Name == "General");
|
||||||
|
Assert.AreEqual(2, generalGroup.Entries.Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -310,7 +310,7 @@ public class PwDatabaseV3 {
|
|||||||
* ID number to check for
|
* ID number to check for
|
||||||
* @return True if the ID is used, false otherwise
|
* @return True if the ID is used, false otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean isGroupIdUsed(PwGroupId id) {
|
protected boolean isGroupIdUsed(PwGroupIdV3 id) {
|
||||||
List<PwGroupV3> groups = getGroups();
|
List<PwGroupV3> groups = getGroups();
|
||||||
|
|
||||||
for (int i = 0; i < groups.size(); i++) {
|
for (int i = 0; i < groups.size(); i++) {
|
||||||
@ -382,9 +382,9 @@ public class PwDatabaseV3 {
|
|||||||
groups = grp;
|
groups = grp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PwGroupV3> getGrpRoots() {
|
public ArrayList<PwGroupV3> getGrpRoots() {
|
||||||
int target = 0;
|
int target = 0;
|
||||||
List<PwGroupV3> kids = new ArrayList<PwGroupV3>();
|
ArrayList<PwGroupV3> kids = new ArrayList<PwGroupV3>();
|
||||||
for (int i = 0; i < groups.size(); i++) {
|
for (int i = 0; i < groups.size(); i++) {
|
||||||
PwGroupV3 grp = (PwGroupV3) groups.get(i);
|
PwGroupV3 grp = (PwGroupV3) groups.get(i);
|
||||||
if (grp.level == target)
|
if (grp.level == target)
|
||||||
@ -404,10 +404,10 @@ public class PwDatabaseV3 {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PwGroupV3> getGrpChildren(PwGroupV3 parent) {
|
public ArrayList<PwGroupV3> getGrpChildren(PwGroupV3 parent) {
|
||||||
int idx = groups.indexOf(parent);
|
int idx = groups.indexOf(parent);
|
||||||
int target = parent.level + 1;
|
int target = parent.level + 1;
|
||||||
List<PwGroupV3> kids = new ArrayList<PwGroupV3>();
|
ArrayList<PwGroupV3> kids = new ArrayList<PwGroupV3>();
|
||||||
while (++idx < groups.size()) {
|
while (++idx < groups.size()) {
|
||||||
PwGroupV3 grp = (PwGroupV3) groups.get(idx);
|
PwGroupV3 grp = (PwGroupV3) groups.get(idx);
|
||||||
if (grp.level < target)
|
if (grp.level < target)
|
||||||
@ -418,8 +418,8 @@ public class PwDatabaseV3 {
|
|||||||
return kids;
|
return kids;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PwEntryV3> getEntries(PwGroupV3 parent) {
|
public ArrayList<PwEntryV3> getEntries(PwGroupV3 parent) {
|
||||||
List<PwEntryV3> kids = new ArrayList<PwEntryV3>();
|
ArrayList<PwEntryV3> kids = new ArrayList<PwEntryV3>();
|
||||||
/*
|
/*
|
||||||
* for( Iterator i = entries.iterator(); i.hasNext(); ) { PwEntryV3 ent
|
* for( Iterator i = entries.iterator(); i.hasNext(); ) { PwEntryV3 ent
|
||||||
* = (PwEntryV3)i.next(); if( ent.groupId == parent.groupId ) kids.add(
|
* = (PwEntryV3)i.next(); if( ent.groupId == parent.groupId ) kids.add(
|
||||||
@ -443,7 +443,7 @@ public class PwDatabaseV3 {
|
|||||||
PwGroupV3 root = new PwGroupV3();
|
PwGroupV3 root = new PwGroupV3();
|
||||||
rootGroup = root;
|
rootGroup = root;
|
||||||
|
|
||||||
List<PwGroupV3> rootChildGroups = getGrpRoots();
|
ArrayList<PwGroupV3> rootChildGroups = getGrpRoots();
|
||||||
root.setGroups(rootChildGroups);
|
root.setGroups(rootChildGroups);
|
||||||
root.childEntries = new ArrayList<PwEntryV3>();
|
root.childEntries = new ArrayList<PwEntryV3>();
|
||||||
root.level = -1;
|
root.level = -1;
|
||||||
|
@ -90,7 +90,7 @@ protected static final String PMS_TAN_ENTRY = "<TAN>";
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public PwIcon getIcon() {
|
public PwIconStandard getIcon() {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ protected static final String PMS_TAN_ENTRY = "<TAN>";
|
|||||||
public int groupId;
|
public int groupId;
|
||||||
public String username;
|
public String username;
|
||||||
private byte[] password;
|
private byte[] password;
|
||||||
private byte[] uuid;
|
public byte[] uuid;
|
||||||
public String title;
|
public String title;
|
||||||
public String url;
|
public String url;
|
||||||
public String additional;
|
public String additional;
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
package com.keepassdroid.database;
|
package com.keepassdroid.database;
|
||||||
|
|
||||||
public abstract class PwGroupId {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.keepassdroid.database;
|
package com.keepassdroid.database;
|
||||||
|
|
||||||
public class PwGroupIdV3 extends PwGroupId {
|
public class PwGroupIdV3 {
|
||||||
|
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
@ -46,17 +46,29 @@ public class PwGroupV3 {
|
|||||||
public PwGroupV3() {
|
public PwGroupV3() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PwGroupV3> childGroups = new ArrayList<PwGroupV3>();
|
//Mono for Android binding somehow doesn't return List<PwGroupV3> but only IList and casting of the contents doesn't work.
|
||||||
|
//therefore, getGroupAt() must be used in C#, see below
|
||||||
|
public ArrayList<PwGroupV3> childGroups = new ArrayList<PwGroupV3>();
|
||||||
|
|
||||||
public List<PwEntryV3> childEntries = new ArrayList<PwEntryV3>();
|
public ArrayList<PwEntryV3> childEntries = new ArrayList<PwEntryV3>();
|
||||||
public String name = "";
|
public String name = "";
|
||||||
public PwIconStandard icon;
|
public PwIconStandard icon;
|
||||||
|
|
||||||
public PwIcon getIcon() {
|
|
||||||
|
public PwGroupV3 getGroupAt(int i)
|
||||||
|
{
|
||||||
|
return childGroups.get(i);
|
||||||
|
}
|
||||||
|
public PwEntryV3 getEntryAt(int i)
|
||||||
|
{
|
||||||
|
return childEntries.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PwIconStandard getIcon() {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void super_initNewGroup(String nm, PwGroupId newId) {
|
public void super_initNewGroup(String nm, PwGroupIdV3 newId) {
|
||||||
setId(newId);
|
setId(newId);
|
||||||
name = nm;
|
name = nm;
|
||||||
}
|
}
|
||||||
@ -113,7 +125,7 @@ public class PwGroupV3 {
|
|||||||
/** Used by KeePass internally, don't use */
|
/** Used by KeePass internally, don't use */
|
||||||
public int flags;
|
public int flags;
|
||||||
|
|
||||||
public void setGroups(List<PwGroupV3> groups) {
|
public void setGroups(ArrayList<PwGroupV3> groups) {
|
||||||
childGroups = groups;
|
childGroups = groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,11 +133,11 @@ public class PwGroupV3 {
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PwGroupId getId() {
|
public PwGroupIdV3 getId() {
|
||||||
return new PwGroupIdV3(groupId);
|
return new PwGroupIdV3(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(PwGroupId id) {
|
public void setId(PwGroupIdV3 id) {
|
||||||
PwGroupIdV3 id3 = (PwGroupIdV3) id;
|
PwGroupIdV3 id3 = (PwGroupIdV3) id;
|
||||||
groupId = id3.getId();
|
groupId = id3.getId();
|
||||||
}
|
}
|
||||||
@ -144,7 +156,7 @@ public class PwGroupV3 {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initNewGroup(String nm, PwGroupId newId) {
|
public void initNewGroup(String nm, PwGroupIdV3 newId) {
|
||||||
super_initNewGroup(nm, newId);
|
super_initNewGroup(nm, newId);
|
||||||
|
|
||||||
Date now = Calendar.getInstance().getTime();
|
Date now = Calendar.getInstance().getTime();
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package com.keepassdroid.database;
|
|
||||||
|
|
||||||
public abstract class PwIcon {
|
|
||||||
|
|
||||||
public boolean isMetaStreamIcon() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeBytes() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -19,8 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.keepassdroid.database;
|
package com.keepassdroid.database;
|
||||||
|
|
||||||
public class PwIconStandard extends PwIcon {
|
public class PwIconStandard {
|
||||||
public final int iconId;
|
public /*final*/ int iconId;
|
||||||
|
|
||||||
public static PwIconStandard FIRST = new PwIconStandard(1);
|
public static PwIconStandard FIRST = new PwIconStandard(1);
|
||||||
|
|
||||||
@ -30,7 +30,6 @@ public class PwIconStandard extends PwIcon {
|
|||||||
this.iconId = iconId;
|
this.iconId = iconId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMetaStreamIcon() {
|
public boolean isMetaStreamIcon() {
|
||||||
return iconId == 0;
|
return iconId == 0;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
|
|
||||||
package com.keepassdroid.database.load;
|
package com.keepassdroid.database.load;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
@ -135,11 +136,30 @@ public class ImporterV3 {
|
|||||||
|
|
||||||
|
|
||||||
// Load entire file, most of it's encrypted.
|
// Load entire file, most of it's encrypted.
|
||||||
int fileSize = inStream.available();
|
|
||||||
byte[] filebuf = new byte[fileSize + 16]; // Pad with a blocksize (Twofish uses 128 bits), since Android 4.3 tries to write more to the buffer
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
inStream.read(filebuf, 0, fileSize);
|
|
||||||
|
int nRead;
|
||||||
|
byte[] data = new byte[16384];
|
||||||
|
|
||||||
|
while ((nRead = inStream.read(data, 0, data.length)) != -1) {
|
||||||
|
buffer.write(data, 0, nRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.flush();
|
||||||
|
|
||||||
|
int fileSize = buffer.size();
|
||||||
|
|
||||||
|
// Pad with a blocksize (Twofish uses 128 bits), since Android 4.3 tries to write more to the buffer
|
||||||
|
for (int i=0;i<16;i++)
|
||||||
|
{
|
||||||
|
buffer.write(0);
|
||||||
|
}
|
||||||
|
|
||||||
inStream.close();
|
inStream.close();
|
||||||
|
|
||||||
|
byte[] filebuf = buffer.toByteArray();
|
||||||
|
|
||||||
// Parse header (unencrypted)
|
// Parse header (unencrypted)
|
||||||
if( fileSize < PwDbHeaderV3.BUF_SIZE )
|
if( fileSize < PwDbHeaderV3.BUF_SIZE )
|
||||||
throw new IOException( "File too short for header: "+fileSize+"<"+PwDbHeaderV3.BUF_SIZE );
|
throw new IOException( "File too short for header: "+fileSize+"<"+PwDbHeaderV3.BUF_SIZE );
|
||||||
|
Loading…
Reference in New Issue
Block a user