mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Support for outputing the database header.
This commit is contained in:
51
src/com/android/keepass/keepasslib/PwDbHeaderOutput.java
Normal file
51
src/com/android/keepass/keepasslib/PwDbHeaderOutput.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Brian Pellin.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDroid.
|
||||||
|
*
|
||||||
|
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDroid is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.android.keepass.keepasslib;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import org.phoneid.keepassj2me.PwDbHeader;
|
||||||
|
import org.phoneid.keepassj2me.Types;
|
||||||
|
|
||||||
|
public class PwDbHeaderOutput {
|
||||||
|
private PwDbHeader mHeader;
|
||||||
|
private OutputStream mOS;
|
||||||
|
|
||||||
|
public PwDbHeaderOutput(PwDbHeader header, OutputStream os) {
|
||||||
|
mHeader = header;
|
||||||
|
mOS = os;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void output() throws IOException {
|
||||||
|
mOS.write(Types.writeInt(mHeader.signature1));
|
||||||
|
mOS.write(Types.writeInt(mHeader.signature2));
|
||||||
|
mOS.write(Types.writeInt(mHeader.flags));
|
||||||
|
mOS.write(Types.writeInt(mHeader.version));
|
||||||
|
mOS.write(mHeader.masterSeed);
|
||||||
|
mOS.write(mHeader.encryptionIV);
|
||||||
|
mOS.write(Types.writeInt(mHeader.numGroups));
|
||||||
|
mOS.write(Types.writeInt(mHeader.numEntries));
|
||||||
|
mOS.write(mHeader.contentsHash);
|
||||||
|
mOS.write(mHeader.masterSeed2);
|
||||||
|
mOS.write(Types.writeInt(mHeader.numKeyEncRounds));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,95 +26,7 @@ import org.phoneid.keepassj2me.PwEntry;
|
|||||||
import org.phoneid.keepassj2me.Types;
|
import org.phoneid.keepassj2me.Types;
|
||||||
|
|
||||||
public class PwEntryOutput {
|
public class PwEntryOutput {
|
||||||
private OutputStream mOS;
|
// Constants
|
||||||
private PwEntry mPE;
|
|
||||||
|
|
||||||
/** Output the PwGroup to the stream
|
|
||||||
* @param pe
|
|
||||||
* @param os
|
|
||||||
*/
|
|
||||||
public PwEntryOutput(PwEntry pe, OutputStream os) {
|
|
||||||
mPE = pe;
|
|
||||||
mOS = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: Need be to careful about using ints. The actual type written to file is a unsigned int
|
|
||||||
public void output() throws IOException {
|
|
||||||
|
|
||||||
// UUID
|
|
||||||
mOS.write(UUID_FIELD_TYPE);
|
|
||||||
mOS.write(UUID_FIELD_SIZE);
|
|
||||||
mOS.write(mPE.uuid);
|
|
||||||
|
|
||||||
// Group ID
|
|
||||||
mOS.write(GROUPID_FIELD_TYPE);
|
|
||||||
mOS.write(LONG_FOUR);
|
|
||||||
mOS.write(Types.writeInt(mPE.groupId));
|
|
||||||
|
|
||||||
// Image ID
|
|
||||||
mOS.write(IMAGEID_FIELD_TYPE);
|
|
||||||
mOS.write(LONG_FOUR);
|
|
||||||
mOS.write(Types.writeInt(mPE.imageId));
|
|
||||||
|
|
||||||
// Title
|
|
||||||
//byte[] title = mPE.title.getBytes("UTF-8");
|
|
||||||
mOS.write(TITLE_FIELD_TYPE);
|
|
||||||
Types.writeCString(mPE.title, mOS);
|
|
||||||
|
|
||||||
// URL
|
|
||||||
mOS.write(URL_FIELD_TYPE);
|
|
||||||
Types.writeCString(mPE.url, mOS);
|
|
||||||
|
|
||||||
// Username
|
|
||||||
mOS.write(USERNAME_FIELD_TYPE);
|
|
||||||
Types.writeCString(mPE.username, mOS);
|
|
||||||
|
|
||||||
// Password
|
|
||||||
byte[] password = mPE.getPassword();
|
|
||||||
mOS.write(PASSWORD_FIELD_TYPE);
|
|
||||||
mOS.write(Types.writeInt(password.length+1));
|
|
||||||
mOS.write(password);
|
|
||||||
mOS.write(0);
|
|
||||||
|
|
||||||
// Additional
|
|
||||||
mOS.write(ADDITIONAL_FIELD_TYPE);
|
|
||||||
Types.writeCString(mPE.additional, mOS);
|
|
||||||
|
|
||||||
// Create date
|
|
||||||
mOS.write(CREATE_FIELD_TYPE);
|
|
||||||
mOS.write(DATE_FIELD_SIZE);
|
|
||||||
mOS.write(Types.writeTime(mPE.tCreation));
|
|
||||||
|
|
||||||
// Modification date
|
|
||||||
mOS.write(MOD_FIELD_TYPE);
|
|
||||||
mOS.write(DATE_FIELD_SIZE);
|
|
||||||
mOS.write(Types.writeTime(mPE.tLastMod));
|
|
||||||
|
|
||||||
// Access date
|
|
||||||
mOS.write(ACCESS_FIELD_TYPE);
|
|
||||||
mOS.write(DATE_FIELD_SIZE);
|
|
||||||
mOS.write(Types.writeTime(mPE.tLastAccess));
|
|
||||||
|
|
||||||
// Expiration date
|
|
||||||
mOS.write(EXPIRE_FIELD_TYPE);
|
|
||||||
mOS.write(DATE_FIELD_SIZE);
|
|
||||||
mOS.write(Types.writeTime(mPE.tExpire));
|
|
||||||
|
|
||||||
// Binary desc
|
|
||||||
mOS.write(BINARY_DESC_FIELD_TYPE);
|
|
||||||
Types.writeCString(mPE.binaryDesc, mOS);
|
|
||||||
|
|
||||||
// Binary data
|
|
||||||
byte[] data = mPE.getBinaryData();
|
|
||||||
mOS.write(BINARY_DATA_FIELD_TYPE);
|
|
||||||
mOS.write(Types.writeInt(data.length));
|
|
||||||
mOS.write(data);
|
|
||||||
|
|
||||||
// End
|
|
||||||
mOS.write(END_FIELD_TYPE);
|
|
||||||
mOS.write(ZERO_FIELD_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final byte[] UUID_FIELD_TYPE = Types.writeShort(1);
|
public static final byte[] UUID_FIELD_TYPE = Types.writeShort(1);
|
||||||
public static final byte[] GROUPID_FIELD_TYPE = Types.writeShort(2);
|
public static final byte[] GROUPID_FIELD_TYPE = Types.writeShort(2);
|
||||||
public static final byte[] IMAGEID_FIELD_TYPE = Types.writeShort(3);
|
public static final byte[] IMAGEID_FIELD_TYPE = Types.writeShort(3);
|
||||||
@@ -139,5 +51,109 @@ public class PwEntryOutput {
|
|||||||
public static final byte[] ZERO_FIELD_SIZE = Types.writeInt(0);
|
public static final byte[] ZERO_FIELD_SIZE = Types.writeInt(0);
|
||||||
public static final byte[] TEST = {0x33, 0x33, 0x33, 0x33};
|
public static final byte[] TEST = {0x33, 0x33, 0x33, 0x33};
|
||||||
|
|
||||||
|
private OutputStream mOS;
|
||||||
|
private PwEntry mPE;
|
||||||
|
private long outputBytes = 0;
|
||||||
|
|
||||||
|
/** Output the PwGroup to the stream
|
||||||
|
* @param pe
|
||||||
|
* @param os
|
||||||
|
*/
|
||||||
|
public PwEntryOutput(PwEntry pe, OutputStream os) {
|
||||||
|
mPE = pe;
|
||||||
|
mOS = os;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: Need be to careful about using ints. The actual type written to file is a unsigned int
|
||||||
|
public void output() throws IOException {
|
||||||
|
|
||||||
|
outputBytes += 134; // Length of fixed size fields
|
||||||
|
|
||||||
|
// UUID
|
||||||
|
mOS.write(UUID_FIELD_TYPE);
|
||||||
|
mOS.write(UUID_FIELD_SIZE);
|
||||||
|
mOS.write(mPE.uuid);
|
||||||
|
|
||||||
|
// Group ID
|
||||||
|
mOS.write(GROUPID_FIELD_TYPE);
|
||||||
|
mOS.write(LONG_FOUR);
|
||||||
|
mOS.write(Types.writeInt(mPE.groupId));
|
||||||
|
|
||||||
|
// Image ID
|
||||||
|
mOS.write(IMAGEID_FIELD_TYPE);
|
||||||
|
mOS.write(LONG_FOUR);
|
||||||
|
mOS.write(Types.writeInt(mPE.imageId));
|
||||||
|
|
||||||
|
// Title
|
||||||
|
//byte[] title = mPE.title.getBytes("UTF-8");
|
||||||
|
mOS.write(TITLE_FIELD_TYPE);
|
||||||
|
int titleLen = Types.writeCString(mPE.title, mOS);
|
||||||
|
outputBytes += titleLen;
|
||||||
|
|
||||||
|
// URL
|
||||||
|
mOS.write(URL_FIELD_TYPE);
|
||||||
|
int urlLen = Types.writeCString(mPE.url, mOS);
|
||||||
|
outputBytes += urlLen;
|
||||||
|
|
||||||
|
// Username
|
||||||
|
mOS.write(USERNAME_FIELD_TYPE);
|
||||||
|
int userLen = Types.writeCString(mPE.username, mOS);
|
||||||
|
outputBytes += userLen;
|
||||||
|
|
||||||
|
// Password
|
||||||
|
byte[] password = mPE.getPassword();
|
||||||
|
mOS.write(PASSWORD_FIELD_TYPE);
|
||||||
|
mOS.write(Types.writeInt(password.length+1));
|
||||||
|
mOS.write(password);
|
||||||
|
mOS.write(0);
|
||||||
|
outputBytes += password.length + 1;
|
||||||
|
|
||||||
|
// Additional
|
||||||
|
mOS.write(ADDITIONAL_FIELD_TYPE);
|
||||||
|
int addlLen = Types.writeCString(mPE.additional, mOS);
|
||||||
|
outputBytes += addlLen;
|
||||||
|
|
||||||
|
// Create date
|
||||||
|
mOS.write(CREATE_FIELD_TYPE);
|
||||||
|
mOS.write(DATE_FIELD_SIZE);
|
||||||
|
mOS.write(Types.writeTime(mPE.tCreation));
|
||||||
|
|
||||||
|
// Modification date
|
||||||
|
mOS.write(MOD_FIELD_TYPE);
|
||||||
|
mOS.write(DATE_FIELD_SIZE);
|
||||||
|
mOS.write(Types.writeTime(mPE.tLastMod));
|
||||||
|
|
||||||
|
// Access date
|
||||||
|
mOS.write(ACCESS_FIELD_TYPE);
|
||||||
|
mOS.write(DATE_FIELD_SIZE);
|
||||||
|
mOS.write(Types.writeTime(mPE.tLastAccess));
|
||||||
|
|
||||||
|
// Expiration date
|
||||||
|
mOS.write(EXPIRE_FIELD_TYPE);
|
||||||
|
mOS.write(DATE_FIELD_SIZE);
|
||||||
|
mOS.write(Types.writeTime(mPE.tExpire));
|
||||||
|
|
||||||
|
// Binary desc
|
||||||
|
mOS.write(BINARY_DESC_FIELD_TYPE);
|
||||||
|
int descLen = Types.writeCString(mPE.binaryDesc, mOS);
|
||||||
|
outputBytes += descLen;
|
||||||
|
|
||||||
|
// Binary data
|
||||||
|
byte[] data = mPE.getBinaryData();
|
||||||
|
mOS.write(BINARY_DATA_FIELD_TYPE);
|
||||||
|
mOS.write(Types.writeInt(data.length));
|
||||||
|
mOS.write(data);
|
||||||
|
outputBytes += data.length;
|
||||||
|
|
||||||
|
// End
|
||||||
|
mOS.write(END_FIELD_TYPE);
|
||||||
|
mOS.write(ZERO_FIELD_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of bytes written by the stream
|
||||||
|
* @return Number of bytes written
|
||||||
|
*/
|
||||||
|
public long getLength() {
|
||||||
|
return outputBytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,28 @@ import org.phoneid.keepassj2me.PwGroup;
|
|||||||
import org.phoneid.keepassj2me.Types;
|
import org.phoneid.keepassj2me.Types;
|
||||||
|
|
||||||
public class PwGroupOutput {
|
public class PwGroupOutput {
|
||||||
|
// Constants
|
||||||
|
public static final byte[] GROUPID_FIELD_TYPE = Types.writeShort(1);
|
||||||
|
public static final byte[] NAME_FIELD_TYPE = Types.writeShort(2);
|
||||||
|
public static final byte[] CREATE_FIELD_TYPE = Types.writeShort(3);
|
||||||
|
public static final byte[] MOD_FIELD_TYPE = Types.writeShort(4);
|
||||||
|
public static final byte[] ACCESS_FIELD_TYPE = Types.writeShort(5);
|
||||||
|
public static final byte[] EXPIRE_FIELD_TYPE = Types.writeShort(6);
|
||||||
|
public static final byte[] IMAGEID_FIELD_TYPE = Types.writeShort(7);
|
||||||
|
public static final byte[] LEVEL_FIELD_TYPE = Types.writeShort(8);
|
||||||
|
public static final byte[] FLAGS_FIELD_TYPE = Types.writeShort(9);
|
||||||
|
public static final byte[] END_FIELD_TYPE = Types.writeShort(0xFFFF);
|
||||||
|
public static final byte[] LONG_FOUR = Types.writeInt(4);
|
||||||
|
public static final byte[] GROUPID_FIELD_SIZE = LONG_FOUR;
|
||||||
|
public static final byte[] DATE_FIELD_SIZE = Types.writeInt(5);
|
||||||
|
public static final byte[] IMAGEID_FIELD_SIZE = LONG_FOUR;
|
||||||
|
public static final byte[] LEVEL_FIELD_SIZE = Types.writeInt(2);
|
||||||
|
public static final byte[] FLAGS_FIELD_SIZE = LONG_FOUR;
|
||||||
|
public static final byte[] ZERO_FIELD_SIZE = Types.writeInt(0);
|
||||||
|
|
||||||
private OutputStream mOS;
|
private OutputStream mOS;
|
||||||
private PwGroup mPG;
|
private PwGroup mPG;
|
||||||
|
private long outputBytes = 0;
|
||||||
|
|
||||||
/** Output the PwGroup to the stream
|
/** Output the PwGroup to the stream
|
||||||
* @param pg
|
* @param pg
|
||||||
@@ -38,9 +58,11 @@ public class PwGroupOutput {
|
|||||||
mOS = os;
|
mOS = os;
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: Need be to careful about using ints. The actual type written to file is a unsigned int
|
|
||||||
public void output() throws IOException {
|
public void output() throws IOException {
|
||||||
|
//NOTE: Need be to careful about using ints. The actual type written to file is a unsigned int, but most values can't be greater than 2^31, so it probably doesn't matter.
|
||||||
|
|
||||||
|
outputBytes += 94; // Length of fixed size fields
|
||||||
|
|
||||||
// Group ID
|
// Group ID
|
||||||
mOS.write(GROUPID_FIELD_TYPE);
|
mOS.write(GROUPID_FIELD_TYPE);
|
||||||
mOS.write(GROUPID_FIELD_SIZE);
|
mOS.write(GROUPID_FIELD_SIZE);
|
||||||
@@ -48,8 +70,9 @@ public class PwGroupOutput {
|
|||||||
|
|
||||||
// Name
|
// Name
|
||||||
mOS.write(NAME_FIELD_TYPE);
|
mOS.write(NAME_FIELD_TYPE);
|
||||||
Types.writeCString(mPG.name, mOS);
|
int nameLen = Types.writeCString(mPG.name, mOS);
|
||||||
|
outputBytes += nameLen;
|
||||||
|
|
||||||
// Create date
|
// Create date
|
||||||
mOS.write(CREATE_FIELD_TYPE);
|
mOS.write(CREATE_FIELD_TYPE);
|
||||||
mOS.write(DATE_FIELD_SIZE);
|
mOS.write(DATE_FIELD_SIZE);
|
||||||
@@ -90,21 +113,11 @@ public class PwGroupOutput {
|
|||||||
mOS.write(ZERO_FIELD_SIZE);
|
mOS.write(ZERO_FIELD_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final byte[] GROUPID_FIELD_TYPE = Types.writeShort(1);
|
/** Returns the number of bytes written by the stream
|
||||||
public static final byte[] NAME_FIELD_TYPE = Types.writeShort(2);
|
* @return Number of bytes written
|
||||||
public static final byte[] CREATE_FIELD_TYPE = Types.writeShort(3);
|
*/
|
||||||
public static final byte[] MOD_FIELD_TYPE = Types.writeShort(4);
|
public long getLength() {
|
||||||
public static final byte[] ACCESS_FIELD_TYPE = Types.writeShort(5);
|
return outputBytes;
|
||||||
public static final byte[] EXPIRE_FIELD_TYPE = Types.writeShort(6);
|
}
|
||||||
public static final byte[] IMAGEID_FIELD_TYPE = Types.writeShort(7);
|
|
||||||
public static final byte[] LEVEL_FIELD_TYPE = Types.writeShort(8);
|
|
||||||
public static final byte[] FLAGS_FIELD_TYPE = Types.writeShort(9);
|
|
||||||
public static final byte[] END_FIELD_TYPE = Types.writeShort(0xFFFF);
|
|
||||||
public static final byte[] LONG_FOUR = Types.writeInt(4);
|
|
||||||
public static final byte[] GROUPID_FIELD_SIZE = LONG_FOUR;
|
|
||||||
public static final byte[] DATE_FIELD_SIZE = Types.writeInt(5);
|
|
||||||
public static final byte[] IMAGEID_FIELD_SIZE = LONG_FOUR;
|
|
||||||
public static final byte[] LEVEL_FIELD_SIZE = Types.writeInt(2);
|
|
||||||
public static final byte[] FLAGS_FIELD_SIZE = LONG_FOUR;
|
|
||||||
public static final byte[] ZERO_FIELD_SIZE = Types.writeInt(0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
179
src/com/android/keepass/keepasslib/PwManagerOutput.java
Normal file
179
src/com/android/keepass/keepasslib/PwManagerOutput.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Brian Pellin.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDroid.
|
||||||
|
*
|
||||||
|
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDroid is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.android.keepass.keepasslib;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.DigestOutputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import org.phoneid.keepassj2me.PwDbHeader;
|
||||||
|
import org.phoneid.keepassj2me.PwEntry;
|
||||||
|
import org.phoneid.keepassj2me.PwGroup;
|
||||||
|
import org.phoneid.keepassj2me.PwManager;
|
||||||
|
|
||||||
|
public class PwManagerOutput {
|
||||||
|
private PwManager mPM;
|
||||||
|
private OutputStream mOS;
|
||||||
|
private final boolean mDebug;
|
||||||
|
public static final boolean DEBUG = true;
|
||||||
|
|
||||||
|
public PwManagerOutput(PwManager pm, OutputStream os) {
|
||||||
|
mPM = pm;
|
||||||
|
mOS = os;
|
||||||
|
mDebug = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PwManagerOutput(PwManager pm, OutputStream os, boolean debug) {
|
||||||
|
mPM = pm;
|
||||||
|
mOS = os;
|
||||||
|
mDebug = debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void output() throws IOException, PwManagerOutputException {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
int filePadding = (int)(16 - (fileSize % 16)); // Pad file to 16-byte boundary
|
||||||
|
if ( filePadding > 0 ) {
|
||||||
|
byte[] padding = new byte[filePadding];
|
||||||
|
fos.write(padding);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void outputHeader(OutputStream os) throws PwManagerOutputException {
|
||||||
|
// Build header
|
||||||
|
PwDbHeader header = new PwDbHeader();
|
||||||
|
header.signature1 = PwDbHeader.PWM_DBSIG_1;
|
||||||
|
header.signature2 = PwDbHeader.PWM_DBSIG_2;
|
||||||
|
header.flags = PwDbHeader.PWM_FLAG_SHA2;
|
||||||
|
|
||||||
|
if ( mPM.getAlgorithm() == PwDbHeader.ALGO_AES ) {
|
||||||
|
header.flags |= PwDbHeader.PWM_FLAG_RIJNDAEL;
|
||||||
|
} else if ( mPM.getAlgorithm() == PwDbHeader.ALGO_TWOFISH ) {
|
||||||
|
header.flags |= PwDbHeader.PWM_FLAG_TWOFISH;
|
||||||
|
throw new PwManagerOutputException("Unsupported algorithm.");
|
||||||
|
} else {
|
||||||
|
throw new PwManagerOutputException("Unsupported algorithm.");
|
||||||
|
}
|
||||||
|
|
||||||
|
header.version = PwDbHeader.PWM_DBVER_DW;
|
||||||
|
header.numGroups = mPM.groups.size();
|
||||||
|
header.numEntries = mPM.entries.size();
|
||||||
|
header.numKeyEncRounds = mPM.getNumKeyEncRecords();
|
||||||
|
|
||||||
|
// Reuse random values to test equivalence in debug mode
|
||||||
|
if ( mDebug ) {
|
||||||
|
System.arraycopy(mPM.dbHeader.encryptionIV, 0, header.encryptionIV, 0, header.encryptionIV.length);
|
||||||
|
System.arraycopy(mPM.dbHeader.masterSeed, 0, header.masterSeed, 0, header.masterSeed.length);
|
||||||
|
System.arraycopy(mPM.dbHeader.masterSeed2, 0, header.masterSeed2, 0, header.masterSeed2.length);
|
||||||
|
} else {
|
||||||
|
SecureRandom random;
|
||||||
|
try {
|
||||||
|
random = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new PwManagerOutputException("Does not support secure random number generation.");
|
||||||
|
}
|
||||||
|
random.nextBytes(header.encryptionIV);
|
||||||
|
random.nextBytes(header.masterSeed);
|
||||||
|
random.nextBytes(header.masterSeed2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write checksum Checksum
|
||||||
|
MessageDigest md = null;
|
||||||
|
try {
|
||||||
|
md = MessageDigest.getInstance("SHA-256");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
assert true;
|
||||||
|
throw new PwManagerOutputException("SHA-256 not implemented here.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream fos;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream("/dev/null");
|
||||||
|
} catch (FileNotFoundException e1) {
|
||||||
|
throw new PwManagerOutputException("Could not open /dev/null");
|
||||||
|
}
|
||||||
|
DigestOutputStream dos = new DigestOutputStream(fos, md);
|
||||||
|
try {
|
||||||
|
outputPlanGroupAndEntries(dos);
|
||||||
|
dos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PwManagerOutputException("Failed to generate checksum.");
|
||||||
|
}
|
||||||
|
|
||||||
|
header.contentsHash = md.digest();
|
||||||
|
|
||||||
|
|
||||||
|
// Output header
|
||||||
|
PwDbHeaderOutput pho = new PwDbHeaderOutput(header, os);
|
||||||
|
try {
|
||||||
|
pho.output();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PwManagerOutputException("Failed to output the header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void outputPlanGroupAndEntries(OutputStream os) throws IOException {
|
||||||
|
//long size = 0;
|
||||||
|
|
||||||
|
// Groups
|
||||||
|
for (int i = 0; i < mPM.groups.size(); i++ ) {
|
||||||
|
PwGroup pg = mPM.groups.get(i);
|
||||||
|
PwGroupOutput pgo = new PwGroupOutput(pg, os);
|
||||||
|
pgo.output();
|
||||||
|
//size += pgo.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entries
|
||||||
|
for (int i = 0; i < mPM.entries.size(); i++ ) {
|
||||||
|
PwEntry pe = mPM.entries.get(i);
|
||||||
|
PwEntryOutput peo = new PwEntryOutput(pe, os);
|
||||||
|
peo.output();
|
||||||
|
//size += peo.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
//return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PwManagerOutputException extends Exception {
|
||||||
|
|
||||||
|
public PwManagerOutputException(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 3321212743159473368L;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Brian Pellin.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDroid.
|
||||||
|
*
|
||||||
|
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDroid is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.android.keepass.keepasslib;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
|
public class RandomFileOutputStream extends OutputStream {
|
||||||
|
|
||||||
|
RandomAccessFile mFile;
|
||||||
|
|
||||||
|
RandomFileOutputStream(RandomAccessFile file) {
|
||||||
|
mFile = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
super.close();
|
||||||
|
|
||||||
|
mFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buffer, int offset, int count) throws IOException {
|
||||||
|
super.write(buffer, offset, count);
|
||||||
|
|
||||||
|
mFile.write(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buffer) throws IOException {
|
||||||
|
super.write(buffer);
|
||||||
|
|
||||||
|
mFile.write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int oneByte) throws IOException {
|
||||||
|
mFile.write(oneByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void seek(long pos) throws IOException {
|
||||||
|
mFile.seek(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -58,8 +58,16 @@ import com.android.keepass.keepasslib.InvalidKeyFileException;
|
|||||||
*/
|
*/
|
||||||
public class ImporterV3 {
|
public class ImporterV3 {
|
||||||
|
|
||||||
|
public static final boolean DEBUG = true;
|
||||||
|
|
||||||
|
private final boolean mDebug;
|
||||||
|
|
||||||
public ImporterV3() {
|
public ImporterV3() {
|
||||||
//super();
|
mDebug = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImporterV3(boolean debug) {
|
||||||
|
mDebug = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,12 +110,12 @@ public class ImporterV3 {
|
|||||||
throw new IOException( "File too short for header" );
|
throw new IOException( "File too short for header" );
|
||||||
PwDbHeader hdr = new PwDbHeader( filebuf, 0 );
|
PwDbHeader hdr = new PwDbHeader( filebuf, 0 );
|
||||||
|
|
||||||
if( (hdr.signature1 != PwManager.PWM_DBSIG_1) || (hdr.signature2 != PwManager.PWM_DBSIG_2) ) {
|
if( (hdr.signature1 != PwDbHeader.PWM_DBSIG_1) || (hdr.signature2 != PwDbHeader.PWM_DBSIG_2) ) {
|
||||||
//KeePassMIDlet.logS ( "Bad database file signature" );
|
//KeePassMIDlet.logS ( "Bad database file signature" );
|
||||||
throw new IOException( "Bad database file signature" );
|
throw new IOException( "Bad database file signature" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hdr.version != PwManager.PWM_DBVER_DW ) {
|
if( hdr.version != PwDbHeader.PWM_DBVER_DW ) {
|
||||||
//KeePassMIDlet.logS ( "Bad database file version");
|
//KeePassMIDlet.logS ( "Bad database file version");
|
||||||
//throw new IOException( "Bad database file version" );
|
//throw new IOException( "Bad database file version" );
|
||||||
}
|
}
|
||||||
@@ -116,20 +124,22 @@ public class ImporterV3 {
|
|||||||
newManager.setMasterKey( password, keyfile );
|
newManager.setMasterKey( password, keyfile );
|
||||||
|
|
||||||
// Select algorithm
|
// Select algorithm
|
||||||
if( (hdr.flags & PwManager.PWM_FLAG_RIJNDAEL) != 0 ) {
|
if( (hdr.flags & PwDbHeader.PWM_FLAG_RIJNDAEL) != 0 ) {
|
||||||
//KeePassMIDlet.logS ( "Algorithm AES");
|
//KeePassMIDlet.logS ( "Algorithm AES");
|
||||||
newManager.algorithm = PwManager.ALGO_AES;
|
newManager.algorithm = PwDbHeader.ALGO_AES;
|
||||||
} else if( (hdr.flags & PwManager.PWM_FLAG_TWOFISH) != 0 ) {
|
} else if( (hdr.flags & PwDbHeader.PWM_FLAG_TWOFISH) != 0 ) {
|
||||||
//KeePassMIDlet.logS ( "Algorithm TWOFISH");
|
//KeePassMIDlet.logS ( "Algorithm TWOFISH");
|
||||||
newManager.algorithm = PwManager.ALGO_TWOFISH;
|
newManager.algorithm = PwDbHeader.ALGO_TWOFISH;
|
||||||
} else {
|
} else {
|
||||||
throw new IOException( "Unknown algorithm." );
|
throw new IOException( "Unknown algorithm." );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( newManager.algorithm == PwManager.ALGO_TWOFISH )
|
if( newManager.algorithm == PwDbHeader.ALGO_TWOFISH )
|
||||||
throw new IOException( "TwoFish algorithm is not supported" );
|
throw new IOException( "TwoFish algorithm is not supported" );
|
||||||
|
|
||||||
newManager.dbHeader = hdr;
|
if ( mDebug ) {
|
||||||
|
newManager.dbHeader = hdr;
|
||||||
|
}
|
||||||
|
|
||||||
newManager.numKeyEncRounds = hdr.numKeyEncRounds;
|
newManager.numKeyEncRounds = hdr.numKeyEncRounds;
|
||||||
|
|
||||||
@@ -180,10 +190,10 @@ public class ImporterV3 {
|
|||||||
System.arraycopy(filebuf, PwDbHeader.BUF_SIZE, plainContent, 0, encryptedPartSize);
|
System.arraycopy(filebuf, PwDbHeader.BUF_SIZE, plainContent, 0, encryptedPartSize);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: Delete Me, temp for debugging
|
if ( mDebug ) {
|
||||||
newManager.postHeader = new byte[encryptedPartSize];
|
newManager.postHeader = new byte[encryptedPartSize];
|
||||||
System.arraycopy(filebuf, PwDbHeader.BUF_SIZE, newManager.postHeader, 0, encryptedPartSize);
|
System.arraycopy(filebuf, PwDbHeader.BUF_SIZE, newManager.postHeader, 0, encryptedPartSize);
|
||||||
|
}
|
||||||
|
|
||||||
//if( pRepair == null ) {
|
//if( pRepair == null ) {
|
||||||
md = new SHA256Digest();
|
md = new SHA256Digest();
|
||||||
|
|||||||
@@ -25,6 +25,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
package org.phoneid.keepassj2me;
|
package org.phoneid.keepassj2me;
|
||||||
|
|
||||||
public class PwDbHeader {
|
public class PwDbHeader {
|
||||||
|
|
||||||
|
// DB sig from KeePass 1.03
|
||||||
|
public static final int PWM_DBSIG_1 = 0x9AA2D903;
|
||||||
|
// DB sig from KeePass 1.03
|
||||||
|
public static final int PWM_DBSIG_2 = 0xB54BFB65;
|
||||||
|
// DB sig from KeePass 1.03
|
||||||
|
public static final int PWM_DBVER_DW = 0x00030002;
|
||||||
|
|
||||||
|
public static final int PWM_FLAG_SHA2 = 1;
|
||||||
|
public static final int PWM_FLAG_RIJNDAEL = 2;
|
||||||
|
public static final int PWM_FLAG_ARCFOUR = 4;
|
||||||
|
public static final int PWM_FLAG_TWOFISH = 8;
|
||||||
|
|
||||||
|
public static final int ALGO_AES = 0;
|
||||||
|
public static final int ALGO_TWOFISH = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse given buf, as read from file.
|
* Parse given buf, as read from file.
|
||||||
* @param buf
|
* @param buf
|
||||||
@@ -46,11 +62,9 @@ public class PwDbHeader {
|
|||||||
System.arraycopy( buf, offset + 88, masterSeed2, 0, 32 );
|
System.arraycopy( buf, offset + 88, masterSeed2, 0, 32 );
|
||||||
numKeyEncRounds = Types.readInt( buf, offset + 120 );
|
numKeyEncRounds = Types.readInt( buf, offset + 120 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PwDbHeader() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void toBuf( byte[] buf, int offset ) {
|
|
||||||
throw new RuntimeException("Method 'toBuf' not implemented yet");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,20 +47,6 @@ public class PwManager {
|
|||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
// private static final int PWM_SESSION_KEY_SIZE = 12;
|
// private static final int PWM_SESSION_KEY_SIZE = 12;
|
||||||
// DB sig from KeePass 1.03
|
|
||||||
static final int PWM_DBSIG_1 = 0x9AA2D903;
|
|
||||||
// DB sig from KeePass 1.03
|
|
||||||
static final int PWM_DBSIG_2 = 0xB54BFB65;
|
|
||||||
// DB sig from KeePass 1.03
|
|
||||||
static final int PWM_DBVER_DW = 0x00030002;
|
|
||||||
|
|
||||||
static final int PWM_FLAG_SHA2 = 1;
|
|
||||||
static final int PWM_FLAG_RIJNDAEL = 2;
|
|
||||||
static final int PWM_FLAG_ARCFOUR = 4;
|
|
||||||
static final int PWM_FLAG_TWOFISH = 8;
|
|
||||||
|
|
||||||
static final int ALGO_AES = 0;
|
|
||||||
static final int ALGO_TWOFISH = 1;
|
|
||||||
|
|
||||||
// Descriptive name for database, used in GUI.
|
// Descriptive name for database, used in GUI.
|
||||||
public String name = "KeePass database";
|
public String name = "KeePass database";
|
||||||
@@ -88,7 +74,15 @@ public class PwManager {
|
|||||||
|
|
||||||
// root group
|
// root group
|
||||||
PwGroup rootGroup;
|
PwGroup rootGroup;
|
||||||
|
|
||||||
|
public int getAlgorithm() {
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumKeyEncRecords() {
|
||||||
|
return numKeyEncRounds;
|
||||||
|
}
|
||||||
|
|
||||||
public void setMasterKey( String key, String keyFileName ) throws InvalidKeyFileException, IOException {
|
public void setMasterKey( String key, String keyFileName ) throws InvalidKeyFileException, IOException {
|
||||||
assert( key != null && keyFileName != null );
|
assert( key != null && keyFileName != null );
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ package org.phoneid.keepassj2me;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@@ -219,16 +218,6 @@ public class Types {
|
|||||||
//return null;
|
//return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeCString(String str, OutputStream os) throws IOException {
|
|
||||||
byte[] initial = str.getBytes("UTF-8");
|
|
||||||
|
|
||||||
int length = initial.length;
|
|
||||||
os.write(writeInt(length+1));
|
|
||||||
os.write(initial);
|
|
||||||
os.write(0x00);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] writeTime(Date date) {
|
public static byte[] writeTime(Date date) {
|
||||||
byte[] buf = new byte[5];
|
byte[] buf = new byte[5];
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
@@ -250,4 +239,16 @@ public class Types {
|
|||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int writeCString(String str, OutputStream os) throws IOException {
|
||||||
|
byte[] initial = str.getBytes("UTF-8");
|
||||||
|
|
||||||
|
int length = initial.length+1;
|
||||||
|
os.write(writeInt(length));
|
||||||
|
os.write(initial);
|
||||||
|
os.write(0x00);
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 Brian Pellin.
|
|
||||||
*
|
|
||||||
* This file is part of KeePassDroid.
|
|
||||||
*
|
|
||||||
* KeePassDroid is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* KeePassDroid is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package com.android.keepass.tests;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.DigestOutputStream;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Calendar;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.phoneid.keepassj2me.PwEntry;
|
|
||||||
import org.phoneid.keepassj2me.PwGroup;
|
|
||||||
import org.phoneid.keepassj2me.PwManager;
|
|
||||||
import org.phoneid.keepassj2me.Types;
|
|
||||||
|
|
||||||
import com.android.keepass.keepasslib.PwEntryOutput;
|
|
||||||
import com.android.keepass.keepasslib.PwGroupOutput;
|
|
||||||
|
|
||||||
public class PwGroupOutputTest extends TestCase {
|
|
||||||
PwManager mPM;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
mPM = TestData.GetTest1();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPlainContent() throws IOException {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
// Groups
|
|
||||||
for (int i = 0; i < mPM.groups.size(); i++ ) {
|
|
||||||
PwGroup pg = mPM.groups.get(i);
|
|
||||||
PwGroupOutput pgo = new PwGroupOutput(pg, bos);
|
|
||||||
pgo.output();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entries
|
|
||||||
for (int i = 0; i < mPM.entries.size(); i++ ) {
|
|
||||||
boolean debug;
|
|
||||||
PwEntry pe = mPM.entries.get(i);
|
|
||||||
PwEntryOutput peo = new PwEntryOutput(pe, bos);
|
|
||||||
|
|
||||||
debug = (i == 1);
|
|
||||||
peo.output();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] buf = bos.toByteArray();
|
|
||||||
assertArrayEquals(mPM.postHeader, bos.toByteArray());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testChecksum() throws NoSuchAlgorithmException, IOException {
|
|
||||||
FileOutputStream fos = new FileOutputStream("/dev/null");
|
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
||||||
|
|
||||||
DigestOutputStream dos = new DigestOutputStream(fos, md);
|
|
||||||
|
|
||||||
// Groups
|
|
||||||
for (int i = 0; i < mPM.groups.size(); i++ ) {
|
|
||||||
PwGroup pg = mPM.groups.get(i);
|
|
||||||
PwGroupOutput pgo = new PwGroupOutput(pg, dos);
|
|
||||||
pgo.output();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entries
|
|
||||||
for (int i = 0; i < mPM.entries.size(); i++ ) {
|
|
||||||
PwEntry pe = mPM.entries.get(i);
|
|
||||||
PwEntryOutput peo = new PwEntryOutput(pe, dos);
|
|
||||||
peo.output();
|
|
||||||
}
|
|
||||||
|
|
||||||
assertArrayEquals("Hash of groups and entries failed.", md.digest(), mPM.dbHeader.contentsHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
96
tests/src/com/android/keepass/tests/PwManagerOutputTest.java
Normal file
96
tests/src/com/android/keepass/tests/PwManagerOutputTest.java
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Brian Pellin.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDroid.
|
||||||
|
*
|
||||||
|
* KeePassDroid is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDroid is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.android.keepass.tests;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.DigestOutputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.phoneid.keepassj2me.PwManager;
|
||||||
|
|
||||||
|
import com.android.keepass.keepasslib.PwDbHeaderOutput;
|
||||||
|
import com.android.keepass.keepasslib.PwManagerOutput;
|
||||||
|
|
||||||
|
public class PwManagerOutputTest extends TestCase {
|
||||||
|
PwManager mPM;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
mPM = TestData.GetTest1();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPlainContent() throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
PwManagerOutput pos = new PwManagerOutput(mPM, bos, PwManagerOutput.DEBUG);
|
||||||
|
pos.outputPlanGroupAndEntries(bos);
|
||||||
|
|
||||||
|
assertArrayEquals("Group and entry output doesn't match.", mPM.postHeader, bos.toByteArray());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testChecksum() throws NoSuchAlgorithmException, IOException {
|
||||||
|
FileOutputStream fos = new FileOutputStream("/dev/null");
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||||
|
|
||||||
|
DigestOutputStream dos = new DigestOutputStream(fos, md);
|
||||||
|
|
||||||
|
PwManagerOutput pos = new PwManagerOutput(mPM, dos, PwManagerOutput.DEBUG);
|
||||||
|
pos.outputPlanGroupAndEntries(dos);
|
||||||
|
|
||||||
|
assertArrayEquals("Hash of groups and entries failed.", md.digest(), mPM.dbHeader.contentsHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHeader() throws Exception {
|
||||||
|
ByteArrayOutputStream bActual = new ByteArrayOutputStream();
|
||||||
|
PwManagerOutput pActual = new PwManagerOutput(mPM, bActual, PwManagerOutput.DEBUG);
|
||||||
|
pActual.outputHeader(bActual);
|
||||||
|
|
||||||
|
ByteArrayOutputStream bExpected = new ByteArrayOutputStream();
|
||||||
|
PwDbHeaderOutput outExpected = new PwDbHeaderOutput(mPM.dbHeader, bExpected);
|
||||||
|
outExpected.output();
|
||||||
|
|
||||||
|
assertArrayEquals("Header does not match.", bExpected.toByteArray(), bActual.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public void testEncryptedPart() throws Exception {
|
||||||
|
File file = new File("/sdcard/test1.kdb");
|
||||||
|
long length = file.length();
|
||||||
|
|
||||||
|
FileInputStream fis = new FileInputStream(file);
|
||||||
|
byte[] expected = new byte[(int)(length-PwDbHeader.BUF_SIZE)];
|
||||||
|
|
||||||
|
fis.skip(PwDbHeader.BUF_SIZE);
|
||||||
|
fis.read(expected);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ public class TestData {
|
|||||||
|
|
||||||
if ( test1 == null ) {
|
if ( test1 == null ) {
|
||||||
FileInputStream fis = new FileInputStream("/sdcard/test1.kdb");
|
FileInputStream fis = new FileInputStream("/sdcard/test1.kdb");
|
||||||
ImporterV3 importer = new ImporterV3();
|
ImporterV3 importer = new ImporterV3(ImporterV3.DEBUG);
|
||||||
test1 = importer.openDatabase(fis, "12345", "");
|
test1 = importer.openDatabase(fis, "12345", "");
|
||||||
if (test1 != null) {
|
if (test1 != null) {
|
||||||
test1.constructTree(null);
|
test1.constructTree(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user